// Created by Jaime O. Rios import AppKit var sharedPlugin: XcodePerforcePlugin? class XcodePerforcePlugin: NSObject { var bundle: NSBundle var p4Functionatlity: P4Functionality = P4Functionality() var pathForIconResource: NSString? var p4Icon: NSImage? init(bundle: NSBundle) { self.bundle = bundle super.init() let myPlugin = NSBundle(forClass: XcodePerforcePlugin.self) pathForIconResource = myPlugin.pathForResource("plugin_icons", ofType:"icns") if pathForIconResource != nil { p4Icon = NSImage(contentsOfFile: pathForIconResource! as String) } createMenuItems() } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } func createMenuItems() { // Under 6.3.2, mainMenu is not available at startup dispatch_async(dispatch_get_main_queue()) { let mainMenu : NSMenu? = NSApp.mainMenu let item = mainMenu?.itemWithTitle("Source Control") if item != nil { self.p4SettingsSetUpMenu(item) self.p4InfoSetUpMenu(item) self.p4EditSetUpMenu(item) self.p4AddSetUpMenu(item) self.p4RevertSetUpMenu(item) self.p4SubmitSetUpMenu(item) //self.p4vcSubmitSetUpMenu(item) self.p4vcRevGraphSetUpMenu(item) self.p4vcTimeLapseSetUpMenu(item) //p4MergeDiffSetUpMenu(item) } } } func p4SettingsSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"Perforce plugin settings", action:#selector(XcodePerforcePlugin.p4Settings), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(NSMenuItem.separatorItem()) item!.submenu!.addItem(menuItem) } func p4Settings() { p4Functionatlity.checkSettings() var attr = p4Functionatlity.p4Installed let p4Installed = String("p4 installed: \t" + (attr ? "YES": "NO") + "\n") var value = p4Functionatlity.p4Path var valueStr = (value != nil ? value : "Unknown") let p4Path = String("p4 path: \t\t" + valueStr! + "\n") attr = p4Functionatlity.p4vcInstalled let p4vcInstalled = String("p4vc installed: \t" + (attr ? "YES": "NO") + "\n") value = p4Functionatlity.p4vcPath valueStr = (value != nil ? value : "Unknown") let p4vcPath = String("p4vc path: \t" + valueStr! + "\n") attr = p4Functionatlity.P4CONFIG_Set let p4ConfigSet = String("P4CONFIG set: " + (attr ? "YES": "NO") + "\n") value = p4Functionatlity.p4ClientName let p4ClientName = String("P4CLIENT name: " + value! + "\n") let combinedString = p4Installed + p4Path + p4vcInstalled + p4vcPath + p4ConfigSet + p4ClientName displayCustomAlertBox("Perforce plugin settings", informativeText: combinedString) } // MARK: - p4 commands func p4EditSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4 - edit", action:#selector(XcodePerforcePlugin.p4Edit), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } /** Precondition(s): - valid filepath - p4 command line app installed - P4CONFIG environment variable set */ func p4Edit() { let currentDoc = getCurrentXcodeDocumentURL() if currentDoc.result == false { return } if p4Functionatlity.p4ClientSet() == true { let filePath = currentDoc.document!.path let resultMessage = p4Functionatlity.issueP4EditForFile(filePath!) displayCustomAlertBox("p4 edit", informativeText: resultMessage) } else { displayDefaultP4NotSetError() } } func p4AddSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4 - add", action:#selector(XcodePerforcePlugin.p4Add), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4Add() { let currentDoc = getCurrentXcodeDocumentURL() if currentDoc.result == false { return } if p4Functionatlity.p4ClientSet() == true { let filePath = currentDoc.document!.path let resultMessage = p4Functionatlity.issueP4AddForFile(filePath!) displayCustomAlertBox("p4 add", informativeText: resultMessage) } else { displayDefaultP4NotSetError() } } func p4RevertSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4 - revert", action:#selector(XcodePerforcePlugin.p4Revert), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4Revert() { let currentDoc = getCurrentXcodeDocumentURL() if currentDoc.result == false { return } if p4Functionatlity.p4ClientSet() == true { let a = NSAlert() let fileName: NSString = currentDoc.document!.path! a.addButtonWithTitle("Cancel") a.addButtonWithTitle("Revert") a.messageText = "p4 revert"; a.informativeText = "Are you sure you want to revert " + fileName.lastPathComponent + ", this is not undoable." if p4Icon != nil { a.icon = p4Icon } let response = a.runModal(); if (response == NSAlertSecondButtonReturn) { let filePath = currentDoc.document!.path let resultMessage = p4Functionatlity.issueP4RevertForFile(filePath!) displayCustomAlertBox("p4 revert", informativeText: resultMessage) } } } else { displayDefaultP4NotSetError() } } func p4InfoSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4 - info", action:#selector(XcodePerforcePlugin.p4Info), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } /** Precondition(s): - Plugin is able to query the current file that is in focus within Xcode -- The parent folder is used as part of the 'p4 info' command call Postcondition(s): - p4 info message for current file's parent folder */ func p4Info() { let currentDoc = getCurrentXcodeDocumentURL() if currentDoc.result == false { return } if p4Functionatlity.p4ClientSet() == true { let filePath = (currentDoc.document?.path as NSString?) let parentFolder = filePath!.stringByDeletingLastPathComponent var resultMessage = p4Functionatlity.issueP4InfoForFolder(parentFolder) if resultMessage.isEmpty { resultMessage = "Error detected while attempting to query p4 info" } displayCustomAlertBox("p4 info", informativeText: resultMessage) } else { displayDefaultP4NotSetError() } } func p4SubmitSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4 - submit", action:#selector(XcodePerforcePlugin.p4Submit), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4Submit() { let currentDoc = getCurrentXcodeDocumentURL() if (currentDoc.result == false) { return } if p4Functionatlity.p4ClientSet() == true { let a = NSAlert() let fileName: NSString = currentDoc.document!.path! a.messageText = "Submit file: " + fileName.lastPathComponent; a.informativeText = "Please Enter Submit Comment:" a.addButtonWithTitle("Submit") a.addButtonWithTitle("Cancel") if p4Icon != nil { a.icon = p4Icon } let inputTextField = NSTextView(frame: NSRect(x: 0, y: 0, width: 300, height: 24*4)) a.accessoryView = inputTextField let response = a.runModal(); if response == NSAlertFirstButtonReturn { let enteredString = inputTextField.string if (!(enteredString?.isEmpty)!) { let filePath = currentDoc.document!.path let resultMessage = p4Functionatlity.issueP4SubmitForFile(filePath!, withDescription: enteredString!) displayCustomAlertBox("p4 Submit", informativeText: resultMessage) } else { displayCustomAlertBox("p4 Submit", informativeText: "p4 Submit requires a description!") } } } else { displayDefaultP4NotSetError() } } // MARK: - p4vc commands func p4vcSubmitSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4vc - submit", action:#selector(XcodePerforcePlugin.p4vcSubmit), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4vcSubmit() { // p4vc submit } func p4vcRevGraphSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4vc - revgraph", action:#selector(XcodePerforcePlugin.p4vcRevGraph), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4vcRevGraph() { let currentDoc = getCurrentXcodeDocumentURL() if(currentDoc.result == false) { return } if (p4Functionatlity.p4ClientSet() == true && p4Functionatlity.p4vcInstalled == true) { let filePath : NSString! = (currentDoc.document?.path as NSString?) let parentFolder = filePath!.stringByDeletingLastPathComponent let p4InfoErr = p4Functionatlity.issueP4InfoForFolder(parentFolder) var resultMessage = "Unable to connect to perforce server" if p4InfoErr.isEmpty == false { resultMessage = p4Functionatlity.displayP4VCRevGraphForFileAtPath(filePath! as String) } if resultMessage.isEmpty == false { displayCustomAlertBox("p4vc revgraph", informativeText: resultMessage) } } else { displayDefaultP4NotSetError() } } func p4vcTimeLapseSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4vc - timelapse", action:#selector(XcodePerforcePlugin.p4vcTimeLapse), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4vcTimeLapse() { let currentDoc = getCurrentXcodeDocumentURL() if currentDoc.result == false { return } if p4Functionatlity.p4ClientSet() == true && p4Functionatlity.p4vcInstalled == true { let filePath = (currentDoc.document?.path as NSString?) let parentFolder = filePath?.stringByDeletingLastPathComponent let p4InfoErr = p4Functionatlity.issueP4InfoForFolder(parentFolder!) var resultMessage = "Unable to connect to perforce server" if(p4InfoErr.isEmpty == false) { resultMessage = p4Functionatlity.displayP4VCTimeLapseForFileAtPath(filePath! as String) } if(resultMessage.isEmpty == false) { displayCustomAlertBox("p4vc revgraph", informativeText: resultMessage) } } else { displayDefaultP4NotSetError() } } // MARK: - p4merge commands func p4MergeDiffSetUpMenu(let item : NSMenuItem?) { let menuItem = NSMenuItem(title:"p4merge - diff", action:#selector(XcodePerforcePlugin.p4MergeDiff), keyEquivalent:"") menuItem.target = self item!.submenu!.addItem(menuItem) } func p4MergeDiff() { } // MARK: - misc func getCurrentXcodeDocumentURL() -> (result:Bool, document:NSURL?) { var result = false let currentXcodeDocURL = P4XcodeHelper.currentSourceCodeDocumentURL() if currentXcodeDocURL != nil { result = true } else { let alertBox = NSAlert() alertBox.messageText = "Error" alertBox.informativeText = "Unable to acquire a valid file path from Xcode" alertBox.runModal() displayCustomAlertBox("Error", informativeText: "Unable to acquire a valid file path from Xcode") } return (result, currentXcodeDocURL) } func displayDefaultP4NotSetError() { var errorMessage = "" if p4Functionatlity.p4Installed == false { errorMessage = "The p4 command line app is not installed" } if p4Functionatlity.p4vcInstalled == false { if errorMessage.isEmpty == false { errorMessage += "\n" } errorMessage += "The p4vc command line app is not installed" } if p4Functionatlity.P4CONFIG_Set == false { if errorMessage.isEmpty == false { errorMessage += "\n" } errorMessage += "The P4CONFIG environment variable is not set" } displayCustomAlertBox("Error", informativeText: errorMessage) } func displayCustomAlertBox(messageText:NSString?, informativeText:NSString?) { let alertBox = NSAlert() alertBox.messageText = (messageText as! String) alertBox.informativeText = (informativeText as! String) if p4Icon != nil { alertBox.icon = p4Icon } alertBox.runModal() } }