// // AdvanceSettingViewController.swift // KdanAuto // // Created by 朱东勇 on 2023/4/17. // import Cocoa class AdvanceSettingViewController: NSViewController, NSPopoverDelegate { @IBOutlet var m_titleBarView:NSView! // Default is NO @IBOutlet var m_cancelBtn:NSButton! @IBOutlet var m_doneBtn:NSButton! @IBOutlet var m_titleLbl:NSTextField! @IBOutlet var m_nameLbl:NSTextField! @IBOutlet var m_pathLbl:NSTextField! @IBOutlet var m_typeBox:NSComboBox! @IBOutlet var m_sepLine:NSView! // Default is NO let m_useOldLibCell = ASBOOLPropertyCell.shared() /** { "Extention" : "xlsx", "Classs" : [ { "Name" : "对照测试", "Class": "AutoTest" } ], "Params" : [ { "ValueType" : "NSInteger", "Property" : "contentOptions", "Name" : "Content Options", "DefaultValue": @(2) "Values" : [{"Value":@(0), "Name":"Only Text"}, {"Value":@(1), "Name":"Only Table"},... ] }, { "ValueType" : "BOOL", "Property" : "isAllowOCR", "Name" : "Allow OCR", "DefaultValue": @(YES) }, ... ] } */ var m_baseInfo:NSDictionary! /** { "Type":"Others(Old)", // The Folder Name "ID" : "1001", // The ID for Search, private, "Extentiion" : "txt", "Name" : "快照对比(老库)", // Name "Class" : "AutoTest", "Params" : { "useOldLib" : @(true), "Options" : [ { "Property" : "contentOptions", "ValueType" : "NSInteger", "Value": @(2) }, ... ] } } */ var m_testCaseInfo:NSMutableDictionary? = nil /** such as CSV/PDF/PNG/JPG etc. */ var m_fileType:String? = nil var m_testObj:AutoTest? = nil var m_callBack:(_ testObj:AutoTest?, _ property:NSDictionary) -> () = {(obj, property) in } @IBOutlet var m_propertyCV:NSView! var m_propertyViews = NSMutableArray() var _popover: NSPopover! /// static var sharedASViewController : AdvanceSettingViewController? = nil class func shared() -> AdvanceSettingViewController { if nil == sharedASViewController { var objects : NSArray! Bundle.main.loadNibNamed("AdvanceSettingViewController", owner: nil, topLevelObjects: &objects) for tView in objects { if let tv = tView as? AdvanceSettingViewController { sharedASViewController = tv } } } return sharedASViewController! } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. } override func awakeFromNib() { self.view.wantsLayer = true; self.view.layer?.backgroundColor = .init(gray: 0.98, alpha: 1) m_titleBarView.wantsLayer = true; m_titleBarView.layer?.backgroundColor = .init(gray: 0.9, alpha: 0.8) m_sepLine.wantsLayer = true; m_sepLine.layer?.backgroundColor = .init(gray: 0.5, alpha: 0.5); m_useOldLibCell?.setPropertyInfo(["ValueType":"BOOL", "DefaultValue":NSNumber(booleanLiteral: true), "Name":"Use Old Lib" ]) m_useOldLibCell?.setValueChangedCallBack({ value, object in let boolValue = value as! NSNumber for pv in self.m_propertyViews { let propView = pv as! ASPropertyCell? propView?.setEnabled(!boolValue.boolValue) } }); } /// Setter func setBaseInfo(_ info:NSDictionary) { /** { class : AutoTest Extention : pdf Params: Aray } */ m_baseInfo = info; updateViews() } func setTestCase(_ info:NSDictionary?) { m_testCaseInfo = info != nil ? NSMutableDictionary(dictionary: info!) : nil m_doneBtn.title = (m_testCaseInfo == nil) ? "新建" : "保存" m_nameLbl.stringValue = (m_testCaseInfo?.value(forKey: "Name") ?? "") as! String m_pathLbl.isEditable = m_testCaseInfo == nil; m_pathLbl.stringValue = (m_testCaseInfo?.value(forKey: "Type") ?? "") as! String m_useOldLibCell?.setValue(NSNumber(booleanLiteral: false)) let params = m_testCaseInfo?.value(forKey: "Params") as? NSDictionary if (params != nil) { let useOldLib = NSDictionary(dictionary: params!).value(forKey: "useOldLib") as? NSNumber if (nil != useOldLib && useOldLib!.boolValue) { m_useOldLibCell?.setValue(useOldLib as AnyObject) } } let boolValue = m_useOldLibCell?.value() as! NSNumber for pv in self.m_propertyViews { let propView = pv as! ASPropertyCell? propView?.setEnabled(!boolValue.boolValue) } updateValues() } func setCallback(_ callback:@escaping (_ testObj:AutoTest?, _ property:NSDictionary) -> ()) { m_callBack = callback } /// Load Views func updateViews() { for view in m_propertyViews { (view as! ASPropertyCell?)!.removeFromSuperview() } m_propertyViews.removeAllObjects() let classs = m_baseInfo.value(forKey: "Classs") as! NSArray m_typeBox.removeAllItems() for cl in classs { let classInfo = cl as! NSDictionary m_typeBox.addItem(withObjectValue: classInfo.value(forKey: "Name") as! String); } m_typeBox.isEnabled = classs.count > 1 if (m_baseInfo.value(forKey: "Params") != nil) { let propertys = m_baseInfo.value(forKey: "Params") as! NSArray for property in propertys { let cell = ASPropertyCell.propertyCellFor(property as! NSDictionary) if (cell != nil) { m_propertyViews.add(cell!); m_propertyCV.addSubview(cell!); } } } m_propertyCV.addSubview(m_useOldLibCell!) let cellCount = m_propertyViews.count + 1 self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height - self.m_propertyCV.frame.size.height + CGFloat(cellCount * 35)+5) m_useOldLibCell?.frame = CGRectMake(0, 5+CGFloat((cellCount - 1) * 35), self.m_propertyCV.frame.size.width, 35) for pv in m_propertyViews { let propView = pv as! ASPropertyCell? let index = cellCount - 2 - m_propertyViews.index(of: pv) propView?.frame = CGRectMake(0, 5+CGFloat(index * 35), self.m_propertyCV.frame.size.width, 35) } } func updateValues() { let params = m_testCaseInfo?.value(forKey: "Params") as? NSDictionary if (params != nil) { let options = params?.value(forKey: "Options") as? NSArray if (options != nil) { for option in options! { let par = option as! NSDictionary let propertyName = par.value(forKey: "Property") as! String for pv in m_propertyViews { let propView = pv as! ASPropertyCell? let pv_property = propView?.m_propertyInfo?.value(forKey: "Property") as! String if (NSString(string: propertyName).isEqual(to: pv_property)) { if (par.value(forKey: "Value") != nil) { propView?.setValue(par.value(forKey: "Value")! as AnyObject) } break } } } } } if (m_testCaseInfo != nil) { let cClass = m_testCaseInfo!.value(forKey: "Class") as! NSString let classs = m_baseInfo.value(forKey: "Classs") as! NSArray for cl in classs { let classInfo = cl as! NSDictionary if (cClass.isEqual(to: classInfo.value(forKey: "Class"))) { m_typeBox.selectItem(at: classs.index(of: cl)) break } } }else { m_typeBox.selectItem(at: 0) } } /// Show func showIn(_ view:NSView, rect:NSRect) { if _popover == nil { _popover = NSPopover.init() _popover.contentViewController = self; _popover.delegate = self } _popover.contentSize = self.view.frame.size _popover.show(relativeTo: rect, of: view, preferredEdge: NSRectEdge.maxX) } /// IBAction @IBAction func cancelAction(_ sender:NSButton) { _popover.close() } @IBAction func doneAction(_ sender:NSButton) { let type = self.m_pathLbl.stringValue as NSString let name = self.m_nameLbl.stringValue as NSString if (name.length == 0) { self.showAlert("测试项名称不能为空!") return } if (type.length == 0) { self.showAlert("测试项文件夹不能为空!") return } let path = DataModel.shared.directoryPath().appendingFormat("/\(m_fileType ?? "")/\(type)") let currentType = m_testCaseInfo?.value(forKey: "Type") if (!type.isEqual(to: currentType) && FileManager.default.fileExists(atPath: path)) { self.showAlert("【测试项文件夹】(\(type))已存在,请换一个【测试项文件夹】名称!") return } let property = NSMutableDictionary() property.setValue(type, forKey: "Type") property.setValue(name, forKey: "Name") if (m_testCaseInfo != nil) { property.setValue(m_testCaseInfo?.value(forKey: "ID"), forKey: "ID") } property.setValue(m_baseInfo.value(forKey: "Extention"), forKey: "Extention") let classs = m_baseInfo.value(forKey: "Classs") as! NSArray let classInfo = classs.object(at: m_typeBox.indexOfSelectedItem) as! NSDictionary property.setValue(classInfo.value(forKey: "Class") as! String, forKey: "Class") let params = NSMutableDictionary() property.setValue(params, forKey: "Params") let useOldLib = m_useOldLibCell?.value() as! NSNumber if (useOldLib.boolValue) { params.setValue(useOldLib, forKey: "useOldLib") }else { let options = NSMutableArray() params.setValue(options, forKey: "Options") for pv in m_propertyViews { let propView = pv as! ASPropertyCell? let pv_property = propView?.m_propertyInfo?.value(forKey: "Property") as! String let pv_valueType = propView?.m_propertyInfo?.value(forKey: "ValueType") as! String options.add(["Property": pv_property, "ValueType":pv_valueType, "Value":propView!.value()]) } } m_callBack(m_testObj, property) if (LogViewController.shared().isVisable()) { if (m_testCaseInfo != nil) { LogViewController.shared().appendLog("\n*********修改参数*******\n") }else { LogViewController.shared().appendLog("\n*********新建测试项*******\n") } LogViewController.shared().appendLog("- 名称: \(name)\n") LogViewController.shared().appendLog("- 文件夹: \(type)\n") property.setValue(type, forKey: "Type") property.setValue(name, forKey: "Name") if (useOldLib.boolValue) { LogViewController.shared().appendLog("- 库版本: 老库\n") }else { LogViewController.shared().appendLog("- 库版本: 新库\n") for pv in m_propertyViews { let propView = pv as! ASPropertyCell? let pv_propertyName = propView?.m_propertyInfo?.value(forKey: "Name") as! String let pv_ValueType = propView?.m_propertyInfo?.value(forKey: "ValueType") as! NSString var value = propView?.value() let pv_Values = propView?.m_propertyInfo?.value(forKey: "Values") as? NSArray if (pv_ValueType.isEqual(to: "BOOL") || pv_ValueType.isEqual(to: "Bool") || pv_ValueType.isEqual(to: "bool")) { LogViewController.shared().appendLog("- \(pv_propertyName): \((value as! NSNumber).boolValue ? "YES" : "NO")\n") }else if ((["int", "int16_t", "int32_t", "int64_t", "NSInteger", "size_t", "uint16_t", "uint32_t", "uint64_t", "NSUInteger", "uint8_t", "int8_t"] as NSArray).contains(pv_ValueType)) { if (pv_Values != nil) { for vi in pv_Values! { let valueInfo = vi as! NSDictionary if ((valueInfo["Value"] as! NSNumber).intValue == (value as! NSNumber).intValue) { LogViewController.shared().appendLog("- \(pv_propertyName): \(valueInfo["Name"] as! String)\n") break; } } }else { LogViewController.shared().appendLog("- \(pv_propertyName): \((value as! NSNumber).intValue)\n") } }else if ((["float", "double"] as NSArray).contains(pv_ValueType)) { if (pv_Values != nil) { for vi in pv_Values! { let valueInfo = vi as! NSDictionary if (fabs((valueInfo["Value"] as! NSNumber).floatValue - (value as! NSNumber).floatValue) < 0.001) { LogViewController.shared().appendLog("- \(pv_propertyName): \(valueInfo["Name"] as! String)\n") break; } } }else { LogViewController.shared().appendLog("- \(pv_propertyName): \((value as! NSNumber).floatValue)\n") } }else if ((["CGRect", "NSRect"] as NSArray).contains(pv_ValueType)) { if (pv_Values != nil) { for vi in pv_Values! { let valueInfo = vi as! NSDictionary if (valueInfo["Value"] as! NSString).isEqual(to: (value as! String)) { LogViewController.shared().appendLog("- \(pv_propertyName): \(valueInfo["Name"] as! String)\n") break; } } }else { LogViewController.shared().appendLog("- \(pv_propertyName): \(value as! String)\n") } }else if ((["CGSize", "NSSize"] as NSArray).contains(pv_ValueType)) { if (pv_Values != nil) { for vi in pv_Values! { let valueInfo = vi as! NSDictionary if (valueInfo["Value"] as! NSString).isEqual(to: (value as! String)) { LogViewController.shared().appendLog("- \(pv_propertyName): \(valueInfo["Name"] as! String)\n") break; } } }else { LogViewController.shared().appendLog("- \(pv_propertyName): \(value as! String)\n") } }else { LogViewController.shared().appendLog("- \(pv_propertyName): \((value as? String) ?? "")\n") } } } } _popover.close() } // NSPopoverDelegate func popoverShouldClose(_ popover: NSPopover) -> Bool { return true } //Show Alert func showAlert(_ msg:String) { let alert = NSAlert() alert.messageText = msg alert.runModal() } } extension AdvanceSettingViewController { class func baseInfoFor(_ type:String) -> NSDictionary? { let path = Bundle.main.path(forResource: "AdvanceSettingPropertyRules", ofType: "plist") let asPropertys = try? NSDictionary.init(contentsOfFile: path!) if asPropertys != nil { return asPropertys?.value(forKey: type) as? NSDictionary } return nil } }