class PreferencesController(NSWindowController): stprWorkHours = objc.IBOutlet("stprWorkHours") edtWorkHours = objc.IBOutlet("edtWorkHours") stprNotificationTime = objc.IBOutlet("stprNotificationTime") edtNotificationTime = objc.IBOutlet("edtNotificationTime") stprNotificationRepeatTime = objc.IBOutlet("stprNotificationRepeatTime") edtNotificationRepeatTime = objc.IBOutlet("edtNotificationRepeatTime") dpkrWorkStarts = objc.IBOutlet("dpkrWorkStarts") edtLogEditCommand = objc.IBOutlet("edtLogEditCommand") pbtnRemoveProject = objc.IBOutlet("pbtnRemoveProject") edtAddProject = objc.IBOutlet("edtAddProject") stprWorkHours = objc.IBOutlet("stprWorkHours") edtDateTimeFormat = objc.IBOutlet("edtDateTimeFormat") chbShowWorkTill = objc.IBOutlet("chbShowWorkTill") chbShowNotification = objc.IBOutlet("chbShowNotification") chbShowDateTime = objc.IBOutlet("chbShowDateTime") chbSoundOnNotification = objc.IBOutlet("chbSoundOnNotification") btnPreviewPopup = objc.IBOutlet("btnPreviewPopup") def initWithMainContorller(self, mainController): self.mainController = mainController return super(PreferencesController, self).initWithWindowNibName_("Preferences") def showWindow_(self, sender): self.window().makeKeyAndOrderFront_(sender) def awakeFromNib(self): self.window().setFrameAutosaveName_("prefWindow") self.initVlaues() self.loadProjectsLists() def initVlaues(self): self.stprWorkHours.setIntValue_(fh.secToHours(userPrefs.workDayLength)) self.edtWorkHours.setIntValue_(self.stprWorkHours.intValue()) self.stprNotificationTime.setIntValue_(userPrefs.notificationTime) self.edtNotificationTime.setIntValue_( self.stprNotificationTime.intValue()) self.stprNotificationRepeatTime.setIntValue_( userPrefs.notificationRepeatTime) self.edtNotificationRepeatTime.setIntValue_( self.stprNotificationRepeatTime.intValue()) workEndTime = datetime.datetime.strptime(userPrefs.workEndTime, "%H:%M").time() someDate = datetime.datetime.combine(datetime.datetime.now(), workEndTime) self.dpkrWorkStarts.setDateValue_(fh.datetimeToNSDate(someDate)) self.edtLogEditCommand.setStringValue_(userPrefs.logEditCommand) self.chbShowWorkTill.setState_(1 if userPrefs.showWorkTill else 0) self.chbShowDateTime.setState_(1 if userPrefs.showDateTime else 0) self.chbShowNotification.setState_( 1 if userPrefs.showNotification else 0) self.chbSoundOnNotification.setState_( 1 if userPrefs.soundOnNotification else 0) self.edtDateTimeFormat.setStringValue_(userPrefs.logDateTimeFormat) self.edtDateTimeFormat.setEnabled_(self.chbShowDateTime.state()) self.showNotification_(self) def saveSettings(self): userPrefs.workDayLength = fh.hoursToSeconds( self.stprWorkHours.intValue()) userPrefs.workEndTime = fh.nsDateToDatetime( self.dpkrWorkStarts.dateValue()).strftime("%H:%M") userPrefs.logEditComman = self.edtLogEditCommand.stringValue() userPrefs.logDateTimeFormat = self.edtDateTimeFormat.stringValue() userPrefs.notificationTime = self.stprNotificationTime.intValue() userPrefs.notificationRepeatTime = ( self.stprNotificationRepeatTime.intValue()) userPrefs.save() def windowShouldClose_(self, sender): self.saveSettings() self.mainController.initControls() sender.orderOut_(sender) return False def loadProjectsLists(self): self.pbtnRemoveProject.removeAllItems() self.pbtnRemoveProject.addItemsWithTitles_(Projects.get()) @objc.IBAction def addProject_(self, sender): projectName = self.edtAddProject.stringValue() if projectName not in Projects.get() and not re.match( "^\s*$", projectName): Projects.add(self.edtAddProject.stringValue()) else: # show alert with reason for failure alert = NSAlert.alloc().init() alert.addButtonWithTitle_('OK') alert.setMessageText_('Failed to add new project') alert.setInformativeText_( 'Please ensure the project does not ' 'already exist and that it contains characters.') alert.runModal() self.loadProjectsLists() self.edtAddProject.setStringValue_('') @objc.IBAction def removeProject_(self, sender): Projects.remove(self.pbtnRemoveProject.titleOfSelectedItem()) self.loadProjectsLists() @objc.IBAction def showDateTime_(self, sender): self.edtDateTimeFormat.setEnabled_(self.chbShowDateTime.state()) userPrefs.showDateTime = bool(self.chbShowDateTime.state()) @objc.IBAction def showWorkTill_(self, sender): userPrefs.showWorkTill = bool(self.chbShowWorkTill.state()) @objc.IBAction def soundOnNotificaiton_(self, sender): userPrefs.soundOnNotification = bool( self.chbSoundOnNotification.state()) @objc.IBAction def showNotification_(self, sender): result = bool(self.chbShowNotification.state()) userPrefs.showNotification = result self.stprNotificationTime.setEnabled_(result) self.edtNotificationTime.setEnabled_(result) self.stprNotificationRepeatTime.setEnabled_(result) self.edtNotificationRepeatTime.setEnabled_(result) self.chbSoundOnNotification.setEnabled_(result) self.btnPreviewPopup.setEnabled_(result) @objc.IBAction def previewPopup_(self, sender): self.mainController.notification.notify("Test notification")
class WSTConnectionWindowController(Cocoa.NSWindowController): """ As per the definition in the NIB file, WSTConnectionWindowController is a subclass of NSWindowController. It acts as a NSTableView data source and implements a standard toolbar. """ methodDescriptionTextView = objc.IBOutlet() methodsTable = objc.IBOutlet() progressIndicator = objc.IBOutlet() statusTextField = objc.IBOutlet() urlTextField = objc.IBOutlet() __slots__ = ( "_toolbarItems", "_toolbarDefaultItemIdentifiers", "_toolbarAllowedItemIdentifiers", "_methods", "_methodSignatures", "_methodDescriptions", "_server", "_methodPrefix", ) @classmethod def connectionWindowController(self): """ Create and return a default connection window instance. """ return WSTConnectionWindowController.alloc().init() def init(self): """ Designated initializer. Returns self (as per ObjC designated initializer definition, unlike Python's __init__() method). """ self = self.initWithWindowNibName_("WSTConnection") self._toolbarItems = {} self._toolbarDefaultItemIdentifiers = [] self._toolbarAllowedItemIdentifiers = [] self._methods = [] return self def awakeFromNib(self): """ Invoked when the NIB file is loaded. Initializes the various UI widgets. """ self.retain() # balanced by autorelease() in windowWillClose_ self.statusTextField.setStringValue_("No host specified.") self.progressIndicator.setStyle_( Cocoa.NSProgressIndicatorSpinningStyle) self.progressIndicator.setDisplayedWhenStopped_(False) self.createToolbar() def windowWillClose_(self, aNotification): """ Clean up when the document window is closed. """ self.autorelease() def createToolbar(self): """ Creates and configures the toolbar to be used by the window. """ toolbar = Cocoa.NSToolbar.alloc().initWithIdentifier_( "WST Connection Window") toolbar.setDelegate_(self) toolbar.setAllowsUserCustomization_(True) toolbar.setAutosavesConfiguration_(True) self.createToolbarItems() self.window().setToolbar_(toolbar) lastURL = Cocoa.NSUserDefaults.standardUserDefaults().stringForKey_( "LastURL") if lastURL and len(lastURL): self.urlTextField.setStringValue_(lastURL) def createToolbarItems(self): """ Creates all of the toolbar items that can be made available in the toolbar. The actual set of available toolbar items is determined by other mechanisms (user defaults, for example). """ addToolbarItem( self, kWSTReloadContentsToolbarItemIdentifier, "Reload", "Reload", "Reload Contents", None, "reloadVisibleData:", Cocoa.NSImage.imageNamed_("Reload"), None, ) addToolbarItem( self, kWSTPreferencesToolbarItemIdentifier, "Preferences", "Preferences", "Show Preferences", None, "orderFrontPreferences:", Cocoa.NSImage.imageNamed_("Preferences"), None, ) addToolbarItem( self, kWSTUrlTextFieldToolbarItemIdentifier, "URL", "URL", "Server URL", None, None, self.urlTextField, None, ) self._toolbarDefaultItemIdentifiers = [ kWSTReloadContentsToolbarItemIdentifier, kWSTUrlTextFieldToolbarItemIdentifier, Cocoa.NSToolbarSeparatorItemIdentifier, Cocoa.NSToolbarCustomizeToolbarItemIdentifier, ] self._toolbarAllowedItemIdentifiers = [ kWSTReloadContentsToolbarItemIdentifier, kWSTUrlTextFieldToolbarItemIdentifier, Cocoa.NSToolbarSeparatorItemIdentifier, Cocoa.NSToolbarSpaceItemIdentifier, Cocoa.NSToolbarFlexibleSpaceItemIdentifier, Cocoa.NSToolbarPrintItemIdentifier, kWSTPreferencesToolbarItemIdentifier, Cocoa.NSToolbarCustomizeToolbarItemIdentifier, ] def toolbarDefaultItemIdentifiers_(self, anIdentifier): """ Return an array of toolbar item identifiers that identify the set, in order, of items that should be displayed on the default toolbar. """ return self._toolbarDefaultItemIdentifiers def toolbarAllowedItemIdentifiers_(self, anIdentifier): """ Return an array of toolbar items that may be used in the toolbar. """ return self._toolbarAllowedItemIdentifiers def toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_( self, toolbar, itemIdentifier, flag): """ Delegate method fired when the toolbar is about to insert an item into the toolbar. Item is identified by itemIdentifier. Effectively makes a copy of the cached reference instance of the toolbar item identified by itemIdentifier. """ newItem = Cocoa.NSToolbarItem.alloc().initWithItemIdentifier_( itemIdentifier) item = self._toolbarItems[itemIdentifier] newItem.setLabel_(item.label()) newItem.setPaletteLabel_(item.paletteLabel()) if item.view(): newItem.setView_(item.view()) else: newItem.setImage_(item.image()) newItem.setToolTip_(item.toolTip()) newItem.setTarget_(item.target()) newItem.setAction_(item.action()) newItem.setMenuFormRepresentation_(item.menuFormRepresentation()) if newItem.view(): newItem.setMinSize_(item.minSize()) newItem.setMaxSize_(item.maxSize()) return newItem def setStatusTextFieldMessage_(self, aMessage): """ Sets the contents of the statusTextField to aMessage and forces the fileld's contents to be redisplayed. """ if not aMessage: aMessage = "Displaying information about %d methods." % len( self._methods) # All UI calls should be directed to the main thread self.statusTextField.setStringValue_(aMessage) def reloadData(self): """Tell the main thread to update the table view.""" self.methodsTable.reloadData() def startWorking(self): """Signal the UI there's work goin on.""" self.progressIndicator.startAnimation_(self) def stopWorking(self): """Signal the UI that the work is done.""" self.progressIndicator.stopAnimation_(self) @objc.IBAction def reloadVisibleData_(self, sender): """ Reloads the list of methods and their signatures from the XML-RPC server specified in the urlTextField. Displays appropriate error messages, if necessary. """ url = self.urlTextField.stringValue() self._methods = [] self._methodSignatures = {} self._methodDescriptions = {} if not url: self.window().setTitle_("Untitled.") self.setStatusTextFieldMessage_("No URL specified.") return self.window().setTitle_(url) Cocoa.NSUserDefaults.standardUserDefaults().setObject_forKey_( url, "LastURL") self.setStatusTextFieldMessage_("Retrieving method list...") self.getMethods(url) @objc.python_method def getMethods(self, url): _server = self._server = Proxy(url.encode("utf8")) self.startWorking() return (_server.callRemote("listMethods").addCallback( # call self.receivedMethods(result, _server, "") on success self.receivedMethods, _server, "", ).addErrback( # on error, call this lambda lambda e: _server.callRemote("system.listMethods").addCallback( # call self.receievedMethods(result, _server, "system.") self.receivedMethods, _server, "system.", )).addErrback( # log the failure instance, with a method self.receivedMethodsFailure, "listMethods()", ).addBoth( # stop working nomatter what trap all errors (returns None) lambda n: self.stopWorking())) @objc.python_method def receivedMethodsFailure(self, why, method): self._server = None self._methodPrefix = None self.setStatusTextFieldMessage_( ("Server failed to respond to %s. " "See below for more information.") % (method, )) # log.err(why) self.methodDescriptionTextView.setString_(why.getTraceback()) @objc.python_method def receivedMethods(self, _methods, _server, _methodPrefix): self._server = _server self._methods = _methods self._methodPrefix = _methodPrefix self._methods.sort() self.reloadData() self.setStatusTextFieldMessage_( "Retrieving information about %d methods." % (len(self._methods), )) # we could make all the requests at once :) # but the server might not like that so we will chain them d = defer.succeed(None) for index, aMethod in enumerate(self._methods): d.addCallback(self.fetchMethodSignature, index, aMethod).addCallbacks( callback=self.processSignatureForMethod, callbackArgs=(index, aMethod), errback=self.couldntProcessSignatureForMethod, errbackArgs=(index, aMethod), ) return d.addCallback(lambda ig: self.setStatusTextFieldMessage_(None) ).addCallback(lambda ig: self.reloadData()) @objc.python_method def fetchMethodSignature(self, ignore, index, aMethod): if (index % 5) == 0: self.reloadData() self.setStatusTextFieldMessage_( "Retrieving signature for method %s (%d of %d)." % (aMethod, index, len(self._methods))) return self._server.callRemote(self._methodPrefix + "methodSignature", aMethod) @objc.python_method def processSignatureForMethod(self, methodSignature, index, aMethod): signatures = None if not len(methodSignature): return for aSignature in methodSignature: if (type(aSignature) == types.ListType) and (len(aSignature) > 0): # noqa: E721 signature = "%s %s(%s)" % ( aSignature[0], aMethod, string.join(aSignature[1:], ", "), ) else: signature = aSignature if signatures: signatures = signatures + ", " + signature else: signatures = signature self._methodSignatures[aMethod] = signatures @objc.python_method def couldntProcessSignatureForMethod(self, why, index, aMethod): # log.err(why) self._methodSignatures[aMethod] = "<error> %s %s" % ( aMethod, why.getBriefTraceback(), ) def tableViewSelectionDidChange_(self, sender): """ When the user selects a remote method, this method displays the documentation for that method as returned by the XML-RPC server. If the method's documentation has been previously queried, the documentation will be retrieved from a cache. """ selectedRow = self.methodsTable.selectedRow() selectedMethod = self._methods[selectedRow] def displayMethod(methodDescription): self.setStatusTextFieldMessage_(None) self.methodDescriptionTextView.setString_(methodDescription) self.fetchMethodDescription(selectedMethod).addCallback(displayMethod) @objc.python_method def fetchMethodDescription(self, aMethod): desc = self._methodDescriptions if aMethod in desc: return defer.succeed(desc[aMethod]) def cacheDesc(v): v = v or "No description available." desc[aMethod] = v return v def _stopWorking(v): self.stopWorking() return v desc[aMethod] = "<description is being retrieved>" self.setStatusTextFieldMessage_( "Retrieving signature for method %s..." % (aMethod, )) self.startWorking() return (self._server.callRemote( self._methodPrefix + "methodHelp", aMethod).addCallback(_stopWorking).addCallback(cacheDesc)) def numberOfRowsInTableView_(self, aTableView): """ Returns the number of methods found on the server. """ return len(self._methods) def tableView_objectValueForTableColumn_row_(self, aTableView, aTableColumn, rowIndex): """ Returns either the raw method name or the method signature, depending on if a signature had been found on the server. """ aMethod = self._methods[rowIndex] if aMethod in self._methodSignatures: return self._methodSignatures[aMethod] else: return aMethod def tableView_shouldEditTableColumn_row_(self, aTableView, aTableColumn, rowIndex): # don't allow editing of any cells return 0
class ASTranslateDocument(NSDocument): codeView = objc.IBOutlet('codeView') resultView = objc.IBOutlet('resultView') styleControl = objc.IBOutlet('styleControl') currentStyle = 0 # import osax; osax.ScriptingAddition().display_dialog('add to all %r'%val) def _addResult_to_(self, kind, val): if kind == kLangAll: for lang in self._resultStores: lang.append(val) else: self._resultStores[kind].append(val) if kind == self.currentStyle or kind == kLangAll: self.resultView.textStorage().appendAttributedString_( NSAttributedString.alloc().initWithString_( u'%s\n\n' % self._resultStores[self.currentStyle][-1])) def windowNibName( self): # a default NSWindowController is created automatically return "ASTranslateDocument" def windowControllerDidLoadNib_(self, controller): self._resultStores = [[] for _ in range(eventformatter.kLanguageCount)] self.currentStyle = _userDefaults.integerForKey_( u'defaultOutputLanguage') @objc.IBAction def runScript_(self, sender): self.resultView.setString_(u'') for lang in self._resultStores: while lang: lang.pop() try: sourceDesc = _standardCodecs.pack(self.codeView.string()) handler = eventformatter.makeCustomSendProc( self._addResult_to_, _userDefaults.boolForKey_('sendEvents')) result = astranslate.translate( sourceDesc, handler) # returns tuple; first item indicates if ok if result[0]: # script result script, result = (_standardCodecs.unpack(desc) for desc in result[1:]) self.codeView.setString_(script) self._addResult_to_(kLangAll, u'OK') else: # script error info script, errorNum, errorMsg, pos = (_standardCodecs.unpack(desc) for desc in result[1:]) start, end = (pos[aem.AEType(k)] for k in ['srcs', 'srce']) if script: errorKind = 'Runtime' self.codeView.setString_(script) else: errorKind = 'Compilation' self._addResult_to_( kLangAll, u'%s Error:\n%s (%i)' % (errorKind, errorMsg, errorNum)) self.codeView.setSelectedRange_((start, end - start)) except aem.ae.MacOSError, e: self._addResult_to_(kLangAll, u'OS Error: %i' % e.args[0])
class PreferencesWindowController(UpShotWindowController): nibfile = u'PreferenceWindow' # General launchAtStartup = objc.IBOutlet() iconset = objc.IBOutlet() # Screenshots randomize = objc.IBOutlet() copyonly = objc.IBOutlet() retinascale = objc.IBOutlet() # Dropbox metadata dropboxdir = objc.IBOutlet() dropboxid = objc.IBOutlet() # Custom share URLs url_select = objc.IBOutlet() url_text = objc.IBOutlet() url_example = objc.IBOutlet() def showWindow_(self, sender): super(PreferencesWindowController, self).showWindow_(sender) self.updateDisplay() def updateDisplay(self): """Update window display from settings.""" self.launchAtStartup.setState_(get_pref('launchAtStartup')) self.iconset.selectCellWithTag_(1 if get_pref('iconset') == 'grayscale' else 0) self.randomize.setState_(get_pref('randomize')) self.copyonly.setState_(get_pref('copyonly')) self.copyonly.setState_(get_pref('retinascale')) dropboxdir = detect_dropbox_folder() self.dropboxdir.setStringValue_(dropboxdir or u'None. Install Dropbox?') self.dropboxid.setStringValue_(get_pref('dropboxid')) customurl = get_pref('customurl') if not customurl: # Default. self.url_select.selectCellWithTag_(0) self.url_text.setEnabled_(False) self.url_text.setStringValue_('') self.url_example.setStringValue_( share_url(EXAMPLE_FILENAME, url='')) else: # Custom. self.url_select.selectCellWithTag_(1) self.url_text.setEnabled_(True) self.url_text.setStringValue_(customurl) self.url_example.setStringValue_( share_url(EXAMPLE_FILENAME, url=customurl)) @objc.IBAction def saveSettings_(self, sender): """Save changed settings.""" set_pref('launchAtStartup', bool(self.launchAtStartup.state())) launch_at_startup(bool(self.launchAtStartup.state())) # Iconset iconset_sel = self.iconset.selectedCell().tag() if iconset_sel == 1: # Grayscale set_pref('iconset', 'grayscale') else: set_pref('iconset', 'default') upshot = NSApplication.sharedApplication().delegate() upshot.update_menu() set_pref('randomize', bool(self.randomize.state())) set_pref('copyonly', bool(self.copyonly.state())) set_pref('retinascale', bool(self.retinascale.state())) try: set_pref('dropboxid', int(self.dropboxid.stringValue())) except ValueError: pass # Custom URL settings. if self.url_select.selectedCell().tag() == 0: # Default self.url_text.setStringValue_('') self.url_text.setEnabled_(False) self.url_example.setStringValue_( share_url(EXAMPLE_FILENAME, url='')) set_pref('customurl', '') else: # Custom self.url_text.setEnabled_(True) self.url_example.setStringValue_( share_url(EXAMPLE_FILENAME, url=self.url_text.stringValue())) set_pref('customurl', self.url_text.stringValue()) @objc.IBAction def domainHelp_(self, sender): """Open URL to learn about custom domain setup with Dropbox.""" sw = NSWorkspace.sharedWorkspace() sw.openURL_(NSURL.URLWithString_(DOMAIN_HELP_URL))
class ControlInstructions (PalettePlugin): dialogName = "com.mekkablue.ControlInstructionsPalette" dialog = objc.IBOutlet() controlInstructionsField = objc.IBOutlet() instanceLabel = objc.IBOutlet() @objc.python_method def settings(self): self.name = Glyphs.localize({ 'en': u'TT Control Instructions', 'de': u'TT-Kontrollinstruktionen' }) self.min = 100 self.max = 1000 # Load .nib dialog (without .extension) self.loadNib('IBdialog', __file__) @objc.python_method def start(self): # Adding a callback for the 'GSUpdateInterface' event Glyphs.addCallback(self.update, UPDATEINTERFACE) @objc.python_method def __del__(self): Glyphs.removeCallback(self.update) @objc.IBAction def setInstructions_(self, sender): windowController = self.windowController() if windowController: thisFont = windowController.document().font if thisFont and thisFont.currentTab: currentInstance = thisFont.currentTab.previewInstances if type(currentInstance) != str: currentInstance.customParameters["TTFAutohint control instructions"] = self.controlInstructionsField.stringValue() @objc.python_method def update( self, sender ): if self.windowController(): thisFont = self.windowController().document().font if thisFont and thisFont.currentTab: currentInstance = None try: currentInstance = thisFont.currentTab.previewInstances except Exception as e: print(e) if currentInstance and type(currentInstance) != str: self.instanceLabel.setStringValue_(currentInstance.name) controlInstructions = currentInstance.customParameters["TTFAutohint control instructions"] if controlInstructions: if controlInstructions[-1] != "\n": controlInstructions+="\n" self.controlInstructionsField.setStringValue_(controlInstructions) else: self.controlInstructionsField.setStringValue_("\n") else: self.instanceLabel.setStringValue_("Please select an instance") self.controlInstructionsField.setStringValue_("") def currentHeight(self): return Glyphs.intDefaults["com.mekkablue.ControlInstructionsPalette.height"] def setCurrentHeight_(self, newHeight): Glyphs.intDefaults["com.mekkablue.ControlInstructionsPalette.height"] = newHeight @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__ # def setSortID_(self, id): # pass # def sortID(self): # return 0
class MakeCalendarController(NSWindowController): """Present a dialog for entering a URL for http document retrieval.""" dateFrom = objc.IBOutlet() dateUntil = objc.IBOutlet() includeDays = objc.IBOutlet() includeHours = objc.IBOutlet() includeHoursFrom = objc.IBOutlet() includeHoursIntervall = objc.IBOutlet() includeHoursUntil = objc.IBOutlet() separateMonth = objc.IBOutlet() separateWeek = objc.IBOutlet() separateYear = objc.IBOutlet() weekMonday = objc.IBOutlet() weekNumber = objc.IBOutlet() calDayFormat = objc.IBOutlet() calHourFormat = objc.IBOutlet() calMonthFormat = objc.IBOutlet() calTitle = objc.IBOutlet() calWeekFormat = objc.IBOutlet() calYearFormat = objc.IBOutlet() def __new__(cls): return cls.alloc() def init(self): self = self.initWithWindowNibName_("CalendarCreator") window = self.window() window.setDelegate_(self) window.setTitle_(u"Define Calendar Spec") window.makeFirstResponder_(self.dateFrom) self.showWindow_(self) self.retain() return self @objc.IBAction def makeItSo_(self, sender): def getInt(n): s = 0 try: s = int(n) except ValueError: return 0 return s def calInsert(cal, date): y = date.year m = date.month d = date.day cur = cal if not y in cur: cur[y] = {'dt': date, 'months': {}} cur = cur[y]['months'] if not m in cur: cur[m] = {'dt': date, 'days': {}} cur = cur[m]['days'] if not d in cur: cur[d] = {'dt': date, 'day': set()} cur = cur[d]['day'] if isinstance(date, datetime.datetime): #h = str(date.hour).zfill(2) #m = str(date.minute).zfill(2) #s = u"%s:%s" % (h,m) #if not date in cur: # cur[s] = date cur.add(date) dateFrom = datetime.datetime.strptime( str(self.dateFrom.dateValue())[:10], "%Y-%m-%d") yearStart = dateFrom.year monthStart = dateFrom.month dateUntil = datetime.datetime.strptime( str(self.dateUntil.dateValue())[:10], "%Y-%m-%d") yearEnd = dateUntil.year monthEnd = dateUntil.month includeDays = bool(int(self.includeDays.state())) includeHours = bool(int(self.includeHours.state())) includeHoursFrom = getInt(str(self.includeHoursFrom.stringValue())) includeHoursIntervall = getInt( str(self.includeHoursIntervall.stringValue())) includeHoursUntil = getInt(str(self.includeHoursUntil.stringValue())) params = { "separateMonth": bool(int(self.separateMonth.state())), "separateWeek": bool(int(self.separateWeek.state())), "separateYear": bool(int(self.separateYear.state())), "weekMonday": bool(int(self.weekMonday.state())), "weekNumber": bool(int(self.weekNumber.state())), "includeDays": bool(int(self.includeDays.state())), "calDayFormat": self.calDayFormat.stringValue(), "calHourFormat": self.calHourFormat.stringValue(), "calMonthFormat": self.calMonthFormat.stringValue(), "calTitle": self.calTitle.stringValue(), "calWeekFormat": self.calWeekFormat.stringValue(), "calYearFormat": self.calYearFormat.stringValue(), "includeHours": bool(int(self.includeHours.state())) } days = daterange(dateFrom, dateUntil, step_days=1) result = [] cal = {} for day in days: dayStart = day.replace(hour=includeHoursFrom) dayEnd = day.replace(hour=includeHoursUntil) if includeHours: dayItems = timerange(dayStart, dayEnd, includeHoursIntervall) for dayItem in dayItems: #result.append( dayItem ) calInsert(cal, dayItem) else: # result.append( day.date() ) # pp( cal ) calInsert(cal, day.date()) app = NSApplication.sharedApplication() delg = app.delegate() # delg.makeCalendarCurrentOrNewDoc_( cal ) self.close() delg.makeCalendarCurrentOrNewDoc_((cal, params)) def windowWillClose_(self, notification): self.autorelease() @objc.IBAction def Cancel_(self, sender): self.close()
class VerticalSkew(PalettePlugin): dialog = objc.IBOutlet() textField = objc.IBOutlet() upButton = objc.IBOutlet() downButton = objc.IBOutlet() def settings(self): self.name = Glyphs.localize({ 'en': u'Vertical Skew', 'de': u'Vertikal neigen' }) self.dialogName = self.name # Load .nib dialog (without .extension) self.loadNib('IBdialog', __file__) def start(self): # Adding a callback for the 'GSUpdateInterface' event # Glyphs.addCallback(self.update, UPDATEINTERFACE) Glyphs.registerDefault('com.mekkablue.VerticalSkew.angle', 5.0) self.textField.setFloatValue_( float(Glyphs.defaults['com.mekkablue.VerticalSkew.angle'])) def __del__(self): pass #Glyphs.removeCallback(self.update) def transform(self, skew=0.0, origin=NSZeroPoint): myTransform = NSAffineTransform.transform() myTransform.shearYBy_atCenter_(math.radians(skew), -origin.x) return myTransform # Action triggered by UI @objc.IBAction def setAngle_(self, sender): # Store angle coming in from dialog Glyphs.defaults[ 'com.mekkablue.VerticalSkew.angle'] = sender.floatValue() # Action triggered by UI @objc.IBAction def upScale_(self, sender): skewAngle = Glyphs.defaults['com.mekkablue.VerticalSkew.angle'] if skewAngle: self.verticalSkew(Glyphs.font, skewAngle) # Action triggered by UI @objc.IBAction def downScale_(self, sender): skewAngle = Glyphs.defaults['com.mekkablue.VerticalSkew.angle'] if skewAngle: self.verticalSkew(Glyphs.font, -skewAngle) def transformOrigin(self, bounds): originType = int(Glyphs.defaults["GSTransformationsMetricsOriginType"]) gridChoice = int(Glyphs.defaults["selectedTransformGridCorner"]) pivotX = 0.0 # origin grid or metrics choice: if originType % 2 == 0: if gridChoice == GSBottomLeft or gridChoice == GSCenterLeft or gridChoice == GSTopLeft: pivotX = bounds.origin.x elif gridChoice == GSBottomRight or gridChoice == GSCenterRight or gridChoice == GSTopRight: pivotX = bounds.origin.x + bounds.size.width else: # if gridChoice == GSBottomCenter or gridChoice == GSCenterCenter or gridChoice == GSTopCenter: pivotX = bounds.origin.x + bounds.size.width * 0.5 # free point: elif originType == 1: pivotX = float(Glyphs.defaults["GSTransformOriginX"]) return NSPoint(pivotX, 0.0) def verticalSkew(self, font, angle): if font: layers = font.selectedLayers # mutiple layers (or no selection): if len(layers) > 1 or (len(layers) == 1 and len(layers[0].selection) == 0): for thisLayer in layers: transformOrigin = self.transformOrigin(thisLayer.bounds) layerTransform = self.transform(skew=angle, origin=transformOrigin) matrix = layerTransform.transformStruct() thisLayer.applyTransform(matrix) # selection in a single layer: elif len(layers) == 1 and layers[0].selection: thisLayer = layers[0] transformOrigin = self.transformOrigin( thisLayer.selectionBounds) selectionTransform = self.transform(skew=angle, origin=transformOrigin) for thisItem in thisLayer.selection: if type(thisItem) == GSComponent: matrix = selectionTransform.transformStruct() thisItem.applyTransform(matrix) else: try: thisItem.position = selectionTransform.transformPoint_( thisItem.position) except: pass def __file__(self): """Please leave this method unchanged""" return __file__ _sortID = 41 def setSortID_(self, id): try: self._sortID = id except Exception as e: self.logToConsole("setSortID_: %s" % str(e)) def sortID(self): return self._sortID
class ____PluginClassName____(FilterWithDialog): # Definitions of IBOutlets # The NSView object from the User Interface. Keep this here! dialog = objc.IBOutlet() # Text field in dialog myTextField = objc.IBOutlet() @objc.python_method def settings(self): self.menuName = Glyphs.localize({ 'en': u'My Filter', 'de': u'Mein Filter' }) # Word on Run Button (default: Apply) self.actionButtonLabel = Glyphs.localize({ 'en': u'Apply', 'de': u'Anwenden' }) # Load dialog from .nib (without .extension) self.loadNib('IBdialog', __file__) # On dialog show @objc.python_method def start(self): # Set default value Glyphs.registerDefault('com.myname.myfilter.value', 15.0) # Set value of text field self.myTextField.setStringValue_( Glyphs.defaults['com.myname.myfilter.value']) # Set focus to text field self.myTextField.becomeFirstResponder() # Action triggered by UI @objc.IBAction def setValue_(self, sender): # Store value coming in from dialog Glyphs.defaults['com.myname.myfilter.value'] = sender.floatValue() # Trigger redraw self.update() # Actual filter @objc.python_method def filter(self, layer, inEditView, customParameters): # Called on font export, get value from customParameters if customParameters.has_key('shift'): value = customParameters['shift'] # Called through UI, use stored value else: value = float(Glyphs.defaults['com.myname.myfilter.value']) # Shift all nodes in x and y direction by the value for path in layer.paths: for node in path.nodes: node.position = NSPoint(node.position.x + value, node.position.y + value) @objc.python_method def generateCustomParameter(self): return "%s; shift:%s;" % (self.__class__.__name__, Glyphs.defaults['com.myname.myfilter.value']) @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__
class GlyphsPluginAutopsy (GeneralPlugin): _window = objc.IBOutlet() _fontListController = objc.IBOutlet() def init( self ): try: self.loadNib('AutopsyDialog', __file__) defaultpdf = os.path.join(os.path.expanduser('~'), 'Desktop', 'Autopsy.pdf') defaultpreferences = { # 'com_yanone_Autopsy_PageOrientation_landscape' : 0, # 'com_yanone_Autopsy_PageSize_a4' : 0, # 'com_yanone_Autopsy_outline_filled' : True, # Other 'com_yanone_Autopsy_drawpointsvalues': True, 'com_yanone_Autopsy_drawmetrics': True, 'com_yanone_Autopsy_drawguidelines': True, 'com_yanone_Autopsy_fontnamesunderglyph': False, 'com_yanone_Autopsy_filename': defaultpdf, 'com_yanone_Autopsy_openPDF': True, 'com_yanone_Autopsy_checkforupdates': True, # Graphs 'com_yanone_Autopsy_graph_width': True, 'com_yanone_Autopsy_graph_width_scope_local': True, 'com_yanone_Autopsy_graph_bboxwidth': False, 'com_yanone_Autopsy_graph_bboxwidth_scope_local' : True, 'com_yanone_Autopsy_graph_bboxheight': False, 'com_yanone_Autopsy_graph_bboxheight_scope_local' : True, 'com_yanone_Autopsy_graph_highestpoint': False, 'com_yanone_Autopsy_graph_highestpoint_scope_local': False, 'com_yanone_Autopsy_graph_lowestpoint': False, 'com_yanone_Autopsy_graph_lowestpoint_scope_local': False, 'com_yanone_Autopsy_graph_leftsidebearing': True, 'com_yanone_Autopsy_graph_leftsidebearing_scope_local' : True, 'com_yanone_Autopsy_graph_rightsidebearing': True, 'com_yanone_Autopsy_graph_rightsidebearing_scope_local' : True, } NSUserDefaults.standardUserDefaults().registerDefaults_(defaultpreferences) except Exception as e: self.logToConsole( "init: %s" % str(e) ) return self def loadPlugin(self): mainMenu = NSApplication.sharedApplication().mainMenu() s = objc.selector(self.showWindow,signature='v@:') newMenuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(self.title(), s, "y" ) newMenuItem.setKeyEquivalentModifierMask_(NSAlternateKeyMask | NSCommandKeyMask) newMenuItem.setTarget_(self) mainMenu.itemAtIndex_(2).submenu().addItem_(newMenuItem) def title( self ): return "Autopsy" def interfaceVersion( self ): """ Distinguishes the API version the plugin was built for. Return 1. """ return 1 def showWindow(self): self.glyphlist = [] Font = Glyphs.orderedDocuments()[0].font if Font.selectedLayers is not None: for Layer in Font.selectedLayers: self.glyphlist.append(Layer.parent.name) self.mode = 'normal' # TODO implement proper handling of MM self._fontListController.setContent_(NSDocumentController.sharedDocumentController().valueForKeyPath_("documents.font")) self._window.makeKeyAndOrderFront_(self) @objc.IBAction def runAutopsy_(self, sender): print "autopsy:" self._window.orderOut_(self) #self.returnValue = NSOKButton if self.mode == 'normal': #self.d.GetValue('List_sel') fonts = self._fontListController.selectedObjects() elif self.mode == 'MM': #self.d.GetValue('MMvalues') myMMvalues = string.replace(self.MMvalues, ' ', '') self.selection = myMMvalues.split(",") # Save instances into customdata of VFB if self.MMvalues != self.customdata['MMinstances']: self.MMfont.modified = 1 self.customdata['MMinstances'] = self.MMvalues if self.MMfont.glyphs.has_key('.notdef'): self.MMfont['.notdef'].customdata = writePlistToString(self.customdata) #NSUserDefaults.standardUserDefaults()['com_yanone_Autopsy_fontselection'] = self.d.List_sel.get() import traceback try: from AutopsyLib import runAutopsy runAutopsy(fonts, self.glyphlist) except: print traceback.format_exc() @objc.IBAction def closeDialog_(self, sender): self._window.orderOut_(self) @objc.IBAction def browseFile(self, sender): Directory = NSUserDefaults.standardUserDefaults()["com_yanone_Autopsy_filename"] FileName = os.path.basename(Directory) file = putFile('', title='pdf', directory=Directory, fileName=FileName, fileTypes=['pdf']) if file: NSUserDefaults.standardUserDefaults()["com_yanone_Autopsy_filename"] = file def logToConsole( self, message ): """ The variable 'message' will be passed to Console.app. Use self.logToConsole( "bla bla" ) for debugging. """ myLog = "%s:\n%s" % ( self.__class__.__name__, message ) NSLog( myLog )
class DotView(Cocoa.NSView): colorWell = objc.IBOutlet() sizeSlider = objc.IBOutlet() def initWithFrame_(self, frame): self.center = (50.0, 50.0) super(DotView, self).initWithFrame_(frame) self.radius = 10.0 self.color = Cocoa.NSColor.redColor() return self def awakeFromNib(self): self.colorWell.setColor_(self.color) self.sizeSlider.setFloatValue_(self.radius) scrollView = self.superview().superview() scrollView.setHasHorizontalRuler_(1) scrollView.setHasVerticalRuler_(1) @objc.IBAction def zoomIn_(self, sender): (x, y), (bw, bh) = self.bounds() (x, y), (fw, fh) = self.frame() self.setBoundsSize_((bw / ZOOM, bh / ZOOM)) self.setFrameSize_((fw * ZOOM, fh * ZOOM)) self.setNeedsDisplay_(True) @objc.IBAction def zoomOut_(self, sender): (x, y), (bw, bh) = self.bounds() (x, y), (fw, fh) = self.frame() self.setBoundsSize_((bw * ZOOM, bh * ZOOM)) self.setFrameSize_((fw / ZOOM, fh / ZOOM)) self.setNeedsDisplay_(True) @objc.IBAction def setRulersVisible_(self, button): scrollView = self.superview().superview() scrollView.setRulersVisible_(button.state()) def isOpaque(self): return True def mouseDown_(self, event): eventLocation = event.locationInWindow() if event.modifierFlags() & Cocoa.NSCommandKeyMask: clipView = self.superview() self.originalPoint = eventLocation self.originalOffset = clipView.bounds()[0] else: self.center = self.convertPoint_fromView_(eventLocation, None) self.setNeedsDisplay_(True) self.autoscroll_(event) def mouseDragged_(self, event): if event.modifierFlags() & Cocoa.NSCommandKeyMask: clipView = self.superview() eventLocation = event.locationInWindow() ox, oy = self.originalPoint x, y = eventLocation dx, dy = x - ox, y - oy x, y = self.originalOffset ox, oy = clipView.constrainScrollPoint_((x - dx, y - dy)) clipView.scrollToPoint_((ox, oy)) clipView.superview().reflectScrolledClipView_(clipView) else: self.mouseDown_(event) def drawRect_(self, rect): Cocoa.NSColor.whiteColor().set() Cocoa.NSRectFill(self.bounds()) origin = (self.center[0] - self.radius, self.center[1] - self.radius) size = (2 * self.radius, 2 * self.radius) dotRect = (origin, size) self.color.set() Cocoa.NSBezierPath.bezierPathWithOvalInRect_(dotRect).fill() @objc.IBAction def setRadius_(self, sender): self.radius = sender.floatValue() self.setNeedsDisplay_(True) @objc.IBAction def setColor_(self, sender): self.color = sender.color() self.setNeedsDisplay_(True)
class OffsetCurveWithAngle(FilterWithDialog): # Definitions of IBOutlets # The NSView object from the User Interface. Keep this here! dialog = objc.IBOutlet() # Text field in dialog xOffsetField = objc.IBOutlet() yOffsetField = objc.IBOutlet() angleField = objc.IBOutlet() @objc.python_method def settings(self): self.menuName = Glyphs.localize({ 'en': 'Offset Curve with Angle', 'de': 'Verfetten mit Winkel', 'es': 'Desplazar curva con ángulo', 'fr': 'Épaissir le tracé avec un angle', }) # Word on Run Button (default: Apply) self.actionButtonLabel = Glyphs.localize({ 'en': 'Offset', 'de': 'Verfetten', 'es': 'Desplazar', 'fr': 'Épaissir', }) # Load dialog from .nib (without .extension) self.loadNib('IBdialog', __file__) # On dialog show @objc.python_method def start(self): # Set default value Glyphs.registerDefault('com.mekkablue.OffsetCurveWithAngle.xOffset', 15.0) Glyphs.registerDefault('com.mekkablue.OffsetCurveWithAngle.yOffset', 10.0) Glyphs.registerDefault('com.mekkablue.OffsetCurveWithAngle.angle', 27.0) # Set value of text field self.xOffsetField.setStringValue_( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.xOffset']) self.yOffsetField.setStringValue_( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.yOffset']) self.angleField.setStringValue_( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.angle']) # Set focus to text field self.xOffsetField.becomeFirstResponder() # Action triggered by UI @objc.IBAction def setXOffset_(self, sender): Glyphs.defaults[ 'com.mekkablue.OffsetCurveWithAngle.xOffset'] = sender.floatValue( ) self.update() # Action triggered by UI @objc.IBAction def setYOffset_(self, sender): Glyphs.defaults[ 'com.mekkablue.OffsetCurveWithAngle.yOffset'] = sender.floatValue( ) self.update() # Action triggered by UI @objc.IBAction def setAngle_(self, sender): Glyphs.defaults[ 'com.mekkablue.OffsetCurveWithAngle.angle'] = sender.floatValue() self.update() # Actual filter @objc.python_method def filter(self, layer, inEditView, customParameters): xOffset = 15.0 yOffset = 10.0 angle = 27.0 if not inEditView: if customParameters.has_key('xOffset'): xOffset = customParameters['xOffset'] if customParameters.has_key('yOffset'): yOffset = customParameters['yOffset'] if customParameters.has_key('angle'): angle = customParameters['angle'] else: xOffset = float( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.xOffset']) yOffset = float( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.yOffset']) angle = float( Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.angle']) layer.applyTransform(self.transform(rotate=-angle).transformStruct()) self.offsetLayer(layer, xOffset, yOffset) layer.applyTransform(self.transform(rotate=angle).transformStruct()) @objc.python_method def transform(self, shiftX=0.0, shiftY=0.0, rotate=0.0, skew=0.0, scale=1.0): """ Returns an NSAffineTransform object for transforming layers. Apply an NSAffineTransform t object like this: Layer.transform_checkForSelection_doComponents_(t,False,True) Access its transformation matrix like this: tMatrix = t.transformStruct() # returns the 6-float tuple Apply the matrix tuple like this: Layer.applyTransform(tMatrix) Component.applyTransform(tMatrix) Path.applyTransform(tMatrix) Chain multiple NSAffineTransform objects t1, t2 like this: t1.appendTransform_(t2) """ myTransform = NSAffineTransform.transform() if rotate: myTransform.rotateByDegrees_(rotate) if scale != 1.0: myTransform.scaleBy_(scale) if not (shiftX == 0.0 and shiftY == 0.0): myTransform.translateXBy_yBy_(shiftX, shiftY) if skew: skewStruct = NSAffineTransformStruct() skewStruct.m11 = 1.0 skewStruct.m22 = 1.0 skewStruct.m21 = math.tan(math.radians(skew)) skewTransform = NSAffineTransform.transform() skewTransform.setTransformStruct_(skewStruct) myTransform.appendTransform_(skewTransform) return myTransform @objc.python_method def offsetLayer(self, thisLayer, offsetX, offsetY, makeStroke=True, position=0.5, autoStroke=False): offsetFilter = NSClassFromString("GlyphsFilterOffsetCurve") try: # GLYPHS 3: offsetFilter.offsetLayer_offsetX_offsetY_makeStroke_autoStroke_position_metrics_error_shadow_capStyleStart_capStyleEnd_keepCompatibleOutlines_( thisLayer, offsetX, offsetY, # horizontal and vertical offset makeStroke, # if True, creates a stroke autoStroke, # if True, distorts resulting shape to vertical metrics position, # stroke distribution to the left and right, 0.5 = middle None, None, None, 0, 0, False) except: # GLYPHS 2: offsetFilter.offsetLayer_offsetX_offsetY_makeStroke_autoStroke_position_error_shadow_( thisLayer, offsetX, offsetY, # horizontal and vertical offset makeStroke, # if True, creates a stroke autoStroke, # if True, distorts resulting shape to vertical metrics position, # stroke distribution to the left and right, 0.5 = middle None, None) @objc.python_method def generateCustomParameter(self): return "%s; xOffset:%s; yOffset:%s; angle:%s;" % ( self.__class__.__name__, Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.xOffset'], Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.yOffset'], Glyphs.defaults['com.mekkablue.OffsetCurveWithAngle.angle'], ) @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__
class GraphicsBindingsDocument(NSDocument): graphicsView = objc.IBOutlet() shadowInspector = objc.IBOutlet() graphicsController = objc.IBOutlet() graphics = objc.ivar() def init(self): self = super(GraphicsBindingsDocument, self).init() if self is None: return None self.graphics = [] # NSMutableArray.array() self.bindings = [] return self def windowNibName(self): return "GraphicsBindingsDocument" def makeBinding_fromObject_toObject_withKeyPath_options_( self, key, fromObject, toObject, withKeyPath, options): self.bindings.append((fromObject, key)) fromObject.bind_toObject_withKeyPath_options_(key, toObject, withKeyPath, options) def windowControllerDidLoadNib_(self, controller): super(GraphicsBindingsDocument, self).windowControllerDidLoadNib_(controller) # we can't do these in IB at the moment, as # we don't have palette items for them # allow the shadow inspector (joystick) to handle multiple selections offsetOptions = {"NSAllowsEditingMultipleValuesSelection": True} angleOptions = { "NSValueTransformerName": "RadiansToDegreesTransformer", "NSAllowsEditingMultipleValuesSelection": True, } BINDINGS = [ ( "graphics", self.graphicsView, self.graphicsController, "arrangedObjects", None, ), ( "selectionIndexes", self.graphicsView, self.graphicsController, "selectionIndexes", None, ), ( "offset", self.shadowInspector, self.graphicsController, "selection.shadowOffset", offsetOptions, ), ( "angle", self.shadowInspector, self.graphicsController, "selection.shadowAngle", angleOptions, ), ] for binding in BINDINGS: self.makeBinding_fromObject_toObject_withKeyPath_options_(*binding) # "fake" what should be set in IB if we had a palette... self.shadowInspector.maxOffset = 15 def close(self): while self.bindings: obj, binding = self.bindings.pop() obj.unbind_(binding) super(GraphicsBindingsDocument, self).close() def dataRepresentationOfType_(self, aType): return NSKeyedArchiver.archivedDataWithRootObject_(self.graphics) def loadDataRepresentation_ofType_(self, data, aType): self.graphics = NSKeyedUnarchiver.unarchiveObjectWithData_(data) return True
class RegistrationPane (InstallerPane): uiFirstNameField = objc.IBOutlet() uiLastNameField = objc.IBOutlet() uiOrganizationField = objc.IBOutlet() uiSerialNumberField = objc.IBOutlet() def _entriesAreValid(self): "test all textfields to if they all have at least one character in them" if (len(self.uiFirstNameField.stringValue()) == 0 or len(self.uiLastNameField.stringValue()) == 0 or len(self.uiOrganizationField.stringValue()) == 0 or len(self.uiSerialNumberField.stringValue()) == 0): return False return True def _serialNumberIsValid(self): """ perform a simple string compare to validate the serial number entered by the user """ return self.uiSerialNumberField.stringValue() == '123-456-789' def _updateNextButtonState(self): "enable the 'Continue' button if '_entriesAreValid' returns 'True'" self.setNextEnabled_(self._entriesAreValid()) def _localizedStringForKey_(self, key): ''' localization helper method: This pulls localized strings from the plugin's bundle ''' return NSBundle.bundleForClass_(type(self )).localizedStringForKey_value_table_(key, '', None) def title(self): ''' return the title of this pane ''' return self._localizedStringForKey_("Title") def didEnterPane_(self, dir): ''' pane's entry point: code called when user enters this pane ''' NSLog("DIDENTER") self._updateNextButtonState() def shouldExitPane_(self, dir): ''' called when user clicks "Continue" -- return value indicates if application should exit pane ''' if dir == InstallerDirectionForward and not self._serialNumberIsValid(): self._updateNextButtonState() NSBeginInformationalAlertSheet( None, self._localizedStringForKey_("OK_BUTTON"), None, None, self.uiFirstNameField.window(), None, None, None, 0, self._localizedStringForKey_("InvalidSerialNumberAlertMessage")); return False return True def controlTextDidChange_(self, notification): """ updates the state of the next button when the contents of the delegate textfields change """ self._updateNextButtonState()
class CalendarMatrix(Cocoa.NSMatrix): lastMonthButton = objc.IBOutlet() monthName = objc.IBOutlet() nextMonthButton = objc.IBOutlet() __slots__ = ("_selectedDay", "_startOffset") def initWithFrame_(self, frameRect): self._selectedDay = None self._startOffset = 0 cell = Cocoa.NSButtonCell.alloc().initTextCell_("") now = Cocoa.NSCalendarDate.date() cell.setShowsStateBy_(Cocoa.NSOnOffButton) self.initWithFrame_mode_prototype_numberOfRows_numberOfColumns_( frameRect, Cocoa.NSRadioModeMatrix, cell, 5, 7) count = 0 for i in range(6): for j in range(7): val = self.cellAtRow_column_(i, j) if val: val.setTag_(count) count += 1 self._selectedDay = Cocoa.NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_( now.yearOfCommonEra(), now.monthOfYear(), now.dayOfMonth(), 0, 0, 0, Cocoa.NSTimeZone.localTimeZone(), ) return self @objc.IBAction def choseDay_(self, sender): prevSelDate = self.selectedDay() selDay = self.selectedCell().tag() - self._startOffset + 1 selDate = Cocoa.NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_( prevSelDate.yearOfCommonEra(), prevSelDate.monthOfYear(), selDay, 0, 0, 0, Cocoa.NSTimeZone.localTimeZone(), ) self.setSelectedDay_(selDate) self.highlightTodayIfVisible() if self.delegate().respondsToSelector_( "calendarMatrix:didChangeToDate:"): self.delegate().calendarMatrix_didChangeToDate_(self, selDate) @objc.IBAction def monthChanged_(self, sender): thisDate = self.selectedDay() currentYear = thisDate.yearOfCommonEra() currentMonth = thisDate.monthOfYear() if sender is self.nextMonthButton: if currentMonth == 12: currentMonth = 1 currentYear += 1 else: currentMonth += 1 else: if currentMonth == 1: currentMonth = 12 currentYear -= 1 else: currentMonth -= 1 self.setSelectedDay_( Cocoa.NSCalendarDate. dateWithYear_month_day_hour_minute_second_timeZone_( currentYear, currentMonth, 1, 0, 0, 0, Cocoa.NSTimeZone.localTimeZone())) self.refreshCalendar() self.choseDay_(self) def setSelectedDay_(self, newDay): self._selectedDay = newDay def selectedDay(self): return self._selectedDay def refreshCalendar(self): selDate = self.selectedDay() currentMonth = selDate.monthOfYear() currentYear = selDate.yearOfCommonEra() firstOfMonth = Cocoa.NSCalendarDate.dateWithYear_month_day_hour_minute_second_timeZone_( currentYear, currentMonth, 1, 0, 0, 0, Cocoa.NSTimeZone.localTimeZone()) self.monthName.setStringValue_( firstOfMonth.descriptionWithCalendarFormat_("%B %Y")) daysInMonth = gNumDaysInMonth[currentMonth] if (currentMonth == 2) and isLeap(currentYear): daysInMonth += 1 self._startOffset = firstOfMonth.dayOfWeek() dayLabel = 1 for i in range(42): cell = self.cellWithTag_(i) if cell is None: continue if i < self._startOffset or i >= (daysInMonth + self._startOffset): # blank out unused cells in the matrix cell.setBordered_(False) cell.setEnabled_(False) cell.setTitle_("") cell.setCellAttribute_to_(Cocoa.NSCellHighlighted, False) else: # Fill in valid days in the matrix cell.setBordered_(True) cell.setEnabled_(True) cell.setFont_(Cocoa.NSFont.systemFontOfSize_(12)) cell.setTitle_(str(dayLabel)) dayLabel += 1 cell.setCellAttribute_to_(Cocoa.NSCellHighlighted, False) self.selectCellWithTag_(selDate.dayOfMonth() + self._startOffset - 1) self.highlightTodayIfVisible() def highlightTodayIfVisible(self): now = Cocoa.NSCalendarDate.date() selDate = self.selectedDay() if (selDate.yearOfCommonEra() == now.yearOfCommonEra() and selDate.monthOfYear() == now.monthOfYear() and selDate.dayOfMonth() == now.dayOfMonth()): aCell = self.cellWithTag_(now.dayOfMonth() + self._startOffset - 1) aCell.setHighlightsBy_(Cocoa.NSMomentaryChangeButton) aCell.setCellAttribute_to_(Cocoa.NSCellHighlighted, True) def awakeFromNib(self): self.setTarget_(self) self.setAction_("choseDay:") self.setAutosizesCells_(True) self.refreshCalendar() self.choseDay_(self)
class CGraphController(Cocoa.NSObject): graphModel = objc.IBOutlet() graphView = objc.IBOutlet() fieldNormalizeCheck = objc.IBOutlet() settingDrawer = objc.IBOutlet() fieldSlider0 = objc.IBOutlet() fieldSlider1 = objc.IBOutlet() fieldSlider2 = objc.IBOutlet() phaseSlider0 = objc.IBOutlet() phaseSlider1 = objc.IBOutlet() phaseSlider2 = objc.IBOutlet() spacingSlider = objc.IBOutlet() fieldDisplay0 = objc.IBOutlet() fieldDisplay1 = objc.IBOutlet() fieldDisplay2 = objc.IBOutlet() phaseDisplay0 = objc.IBOutlet() phaseDisplay1 = objc.IBOutlet() phaseDisplay2 = objc.IBOutlet() RMSGainDisplay = objc.IBOutlet() spacingDisplay = objc.IBOutlet() #____________________________________________________________ # Update GUI display and control values def awakeFromNib(self): self.mapImage = Cocoa.NSImage.imageNamed_("Map") self.graphView.setMapImage(self.mapImage) self.drawGraph() def drawGraph(self): self.spacingDisplay.setFloatValue_( radToDeg(self.graphModel.getSpacing())) self.spacingSlider.setFloatValue_( radToDeg(self.graphModel.getSpacing())) self.fieldDisplay0.setFloatValue_(self.graphModel.getField(0)) self.fieldDisplay1.setFloatValue_(self.graphModel.getField(1)) self.fieldDisplay2.setFloatValue_(self.graphModel.getField(2)) self.fieldSlider0.setFloatValue_(self.graphModel.getField(0)) self.fieldSlider1.setFloatValue_(self.graphModel.getField(1)) self.fieldSlider2.setFloatValue_(self.graphModel.getField(2)) self.phaseDisplay0.setFloatValue_(radToDeg( self.graphModel.getPhase(0))) self.phaseDisplay1.setFloatValue_(radToDeg( self.graphModel.getPhase(1))) self.phaseDisplay2.setFloatValue_(radToDeg( self.graphModel.getPhase(2))) self.phaseSlider0.setFloatValue_(radToDeg(self.graphModel.getPhase(0))) self.phaseSlider1.setFloatValue_(radToDeg(self.graphModel.getPhase(1))) self.phaseSlider2.setFloatValue_(radToDeg(self.graphModel.getPhase(2))) totalField = self.graphModel.getField(0) + self.graphModel.getField( 1) + self.graphModel.getField(2) RMSGain = self.graphModel.fieldGain() self.graphView.setGain(RMSGain, totalField) self.RMSGainDisplay.setFloatValue_(RMSGain * 100.0) path, maxMag = self.graphModel.getGraph() self.graphView.setPath(path, maxMag) #____________________________________________________________ # Handle GUI values @objc.IBAction def fieldDisplay0_(self, sender): self.setNormalizedField(0, sender.floatValue()) self.drawGraph() @objc.IBAction def fieldDisplay1_(self, sender): self.setNormalizedField(1, sender.floatValue()) self.drawGraph() @objc.IBAction def fieldDisplay2_(self, sender): self.setNormalizedField(2, sender.floatValue()) self.drawGraph() @objc.IBAction def fieldSlider0_(self, sender): self.setNormalizedField(0, sender.floatValue()) self.drawGraph() @objc.IBAction def fieldSlider1_(self, sender): self.setNormalizedField(1, sender.floatValue()) self.drawGraph() @objc.IBAction def fieldSlider2_(self, sender): self.setNormalizedField(2, sender.floatValue()) self.drawGraph() def setNormalizedField(self, t, v): if self.fieldNormalizeCheck.intValue(): f = [0, 0, 0] cft = 0 for i in range(3): f[i] = self.graphModel.getField(i) cft += f[i] aft = cft - v if aft < 0.001: v = cft - 0.001 aft = 0.001 f[t] = v nft = 0 for i in range(3): nft += f[i] r = aft / (nft - f[t]) for i in range(3): self.graphModel.setField(i, f[i] * r) self.graphModel.setField(t, v) else: self.graphModel.setField(t, v) @objc.IBAction def phaseDisplay0_(self, sender): self.graphModel.setPhase(0, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def phaseDisplay1_(self, sender): self.graphModel.setPhase(1, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def phaseDisplay2_(self, sender): self.graphModel.setPhase(2, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def phaseSlider0_(self, sender): self.graphModel.setPhase(0, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def phaseSlider1_(self, sender): self.graphModel.setPhase(1, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def phaseSlider2_(self, sender): self.graphModel.setPhase(2, degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def spacingDisplay_(self, sender): self.graphModel.setSpacing(degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def spacingSlider_(self, sender): self.graphModel.setSpacing(degToRad(sender.floatValue())) self.drawGraph() @objc.IBAction def settingDrawerButton_(self, sender): self.settingDrawer.toggle_(self)
class PreferencesController (NSWindowController): start = objc.IBOutlet() stop = objc.IBOutlet() open = objc.IBOutlet() nginxPort = objc.IBOutlet() mysqlPort = objc.IBOutlet() phpPort = objc.IBOutlet() def init(self): self.initWithWindowNibName_("Preferences") return self def windowDidLoad(self): self.setSettings() def show(self): self.preferencesController = PreferencesController.alloc().init() self.preferencesController.showWindow_(self) show = classmethod(show) def setSettings(self): settings = NSUserDefaults.standardUserDefaults() startMEMP = settings.boolForKey_("start") if startMEMP: self.start.setState_(NSOnState) else: self.start.setState_(NSOffState) stopMEMP = settings.boolForKey_("stop") if stopMEMP: self.stop.setState_(NSOnState) else: self.stop.setState_(NSOffState) openMEMP = settings.boolForKey_("open") if openMEMP: self.open.setState_(NSOnState) else: self.open.setState_(NSOffState) nginxPort = settings.stringForKey_("nginxPort") if nginxPort: self.nginxPort.setStringValue_(nginxPort) mysqlPort = settings.stringForKey_("mysqlPort") if mysqlPort: self.mysqlPort.setStringValue_(mysqlPort) phpPort = settings.stringForKey_("phpPort") if phpPort: self.phpPort.setStringValue_(phpPort) @objc.IBAction def savePreferences_(self, sender): settings = NSUserDefaults.standardUserDefaults() if self.start.state(): settings.setObject_forKey_(1, 'start') else: settings.setObject_forKey_(0, 'start') if self.stop.state(): settings.setObject_forKey_(1, 'stop') else: settings.setObject_forKey_(0, 'stop') if self.open.state(): settings.setObject_forKey_(1, 'open') else: settings.setObject_forKey_(0, 'open') if self.nginxPort.stringValue(): settings.setObject_forKey_(self.nginxPort.stringValue(), 'nginxPort') else: settings.setObject_forKey_("80", 'nginxPort') if self.mysqlPort.stringValue(): settings.setObject_forKey_(self.mysqlPort.stringValue(), 'mysqlPort') else: settings.setObject_forKey_("3306", 'mysqlPort') if self.phpPort.stringValue(): settings.setObject_forKey_(self.phpPort.stringValue(), 'phpPort') else: settings.setObject_forKey_("9000", 'phpPort') settings.synchronize()
class ColorMaskDocument(NSPersistentDocument): window = objc.IBOutlet() source_list = objc.IBOutlet() image_view = objc.IBOutlet() zoom_slider = objc.IBOutlet() export_panel = objc.IBOutlet() export_progress = objc.IBOutlet() export_label = objc.IBOutlet() ZOOM_OUT = 0 ZOOM_IN = 1 ZOOM_ACTUAL_SIZE = 2 ZOOM_FIT = 3 @classmethod def initialize(self): """Class initialization, called once at load time. Can be used to do static initialization prior to Xib files being loaded. self is a class, not an object. """ CIPlugIn.loadAllPlugIns() self.colorTransformer = CIColorToNSColorTransformer.alloc().init() self.model = None NSValueTransformer.setValueTransformer_forName_( self.colorTransformer, 'CIColorToNSColorTransformer') def init(self): self = super(ColorMaskDocument, self).init() self.root = None self.project = None self.selected = None self.image = None self.drawingMode = 'mask' return self # Almost 20 lines of code to get the "automatic" file version upgrade working... def managedObjectModel(self): """ The default implementation tries to merge the 2 versions of the models together, which doesn't work. Instead, we return the "current" version. """ if self.__class__.model == None: bundle = NSBundle.bundleForClass_(self.class__()) url = bundle.URLForResource_withExtension_('ColorMaskDocument', 'momd') self.__class__.model = NSManagedObjectModel.alloc( ).initWithContentsOfURL_(url) return self.__class__.model def configurePersistentStoreCoordinatorForURL_ofType_modelConfiguration_storeOptions_error_( self, url, fileType, configuration, storeOptions, error): """ The default implementation doesn't turn on the auto-migration feature. This version does. """ if storeOptions != None: mutableOptions = storeOptions.mutableCopyWithZone_(None) else: mutableOptions = NSMutableDictionary.dictionaryWithCapacity_(2) mutableOptions.setObject_forKey_( True, 'NSMigratePersistentStoresAutomaticallyOption') mutableOptions.setObject_forKey_( True, 'NSInferMappingModelAutomaticallyOption') return super( ColorMaskDocument, self ).configurePersistentStoreCoordinatorForURL_ofType_modelConfiguration_storeOptions_error_( url, fileType, configuration, mutableOptions, error) def initWithType_error_(self, typeName, outError): self, error = super(ColorMaskDocument, self).initWithType_error_(typeName, outError) objContext = self.managedObjectContext() objContext.undoManager().disableUndoRegistration() self.project = NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext_( 'MaskProject', objContext) self.project.setValue_forKeyPath_('', 'sourceURL') objContext.processPendingChanges() objContext.undoManager().enableUndoRegistration() return self, None def windowNibName(self): return u"ColorMaskDocument" def validateUserInterfaceItem_(self, item): if item.action() == 'showMask:' and self.drawingMode != 'mask': item.setState_(NSOffState) elif item.action() == 'showSource:' and self.drawingMode != 'source': item.setState_(NSOffState) elif item.action() == 'showStacked:' and self.drawingMode != 'stacked': item.setState_(NSOffState) if item.action() == 'exportMasks:' or item.action( ) == 'showMask:' or item.action() == 'showStacked:': return self.image != None and len(self.maskList.masks) > 0 return True def selectSource_(self, sender): dialog = NSOpenPanel.openPanel() dialog.setFloatingPanel_(True) dialog.setCanChooseDirectories_(False) dialog.setCanChooseFiles_(True) dialog.setAllowsMultipleSelection_(False) result = dialog.runModalForTypes_(['public.image']) if result == NSOKButton: selected_url = dialog.URLs()[0] self.project.setValue_forKeyPath_(selected_url.absoluteString(), 'sourceURL') self.updateImage() def showMask_(self, sender): sender.setState_(NSOnState) self.drawingMode = 'mask' self.updateSelected() def showSource_(self, sender): sender.setState_(NSOnState) self.drawingMode = 'source' self.updateSelected() def showStacked_(self, sender): sender.setState_(NSOnState) self.drawingMode = 'stacked' self.updateSelected() def exportMasks_(self, sender): savePanel = NSSavePanel.savePanel() sourceURL = NSURL.URLWithString_( self.project.valueForKeyPath_('sourceURL')) cgSource = CGImageSourceCreateWithURL(sourceURL, None) type = CGImageSourceGetType(cgSource) fileName = sourceURL.path().lastPathComponent() saveOptions = IKSaveOptions.alloc( ).initWithImageProperties_imageUTType_(None, type) saveOptions.addSaveOptionsAccessoryViewToSavePanel_(savePanel) result = savePanel.runModal() if result == NSOKButton: if self.export_panel is None: NSBundle.loadNibNamed_owner_('ExportSheet', self) NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_( self.export_panel, self.window, None, None, None) baseURL = savePanel.URL() base, file = os.path.split(baseURL.absoluteString()) file, ext = os.path.splitext(file) session = NSApp.beginModalSessionForWindow_(self.export_panel) for index, mask in enumerate(self.maskList.masks): self.export_progress.setDoubleValue_( float(index) / len(self.maskList.masks) * 100.0) self.export_label.setStringValue_(''.join( ['Exporting: ', mask.name])) NSApp.runModalSession_(session) mask_file = os.path.join( base, file + '-' + mask.name.replace(' ', '_') + ext) dest = CGImageDestinationCreateWithURL( NSURL.URLWithString_(mask_file), saveOptions.imageUTType(), 1, None) mask.renderImage(dest, saveOptions.imageProperties()) NSApp.endModalSession_(session) NSApp.endSheet_(self.export_panel) self.export_panel.orderOut_(self) def windowControllerDidLoadNib_(self, aController): super(ColorMaskDocument, self).windowControllerDidLoadNib_(aController) # user interface preparation code aController.setShouldCloseDocument_(True) # fetch the project, if we were loaded from a file if self.project == None: context = self.managedObjectContext() fetchRequest = NSFetchRequest.alloc().init() entity = NSEntityDescription.entityForName_inManagedObjectContext_( 'MaskProject', context) fetchRequest.setEntity_(entity) fetchResult, error = context.executeFetchRequest_error_( fetchRequest, None) self.project = fetchResult.objectAtIndex_(0) self.root = [ OriginalItem.alloc().initFromDoc_(self), ColorListItem.alloc().initFromDoc_(self) ] self.maskList = self.root[-1] self.sourceToolsActions = [self.addItem, self.removeItem] self.source_list.reloadData() self.zoom_slider.setFloatValue_(1.0) self.updateImage() self.image_view.addObserver_forKeyPath_options_context_( self, 'zoom_factor', NSKeyValueObservingOptionNew, None) self.source_list.expandItem_(self.maskList) def windowWillClose_(self, notification): if self.selected != None: self.selected.unselected() self.image_view.removeObserver_forKeyPath_(self, 'zoom_factor') def updateImage(self): url = self.project.valueForKeyPath_('sourceURL') if url != '': self.image_view.setHidden_(False) self.image_view.setImageWithURL_(NSURL.URLWithString_(url)) self.root[0].imageSet() for mask in self.maskList.masks: mask.imageSet() self.image = self.image_view.image self.sourceLayer = self.image_view.getNewContentLayer() self.stackedLayer = self.image_view.getNewEmptyLayer() self.updateSelected() self.image_view.zoomImageToFit_(self) else: self.image_view.setHidden_(True) self.image = CIImage.emptyImage() def updateSelected(self): if self.selected == None: self.image_view.showLayer(self.sourceLayer) else: if self.drawingMode == 'mask': if self.selected.layer != None: self.selected.displayedLayer = self.selected.layer self.image_view.showLayer(self.selected.layer) elif self.drawingMode == 'source': self.image_view.showLayer(self.sourceLayer) elif self.drawingMode == 'stacked': anchor = CGPoint() anchor.x = 0.5 anchor.y = 0.5 position = CGPoint() position.x = 0.0 position.y = 0.0 self.stackedLayer.setSublayers_(None) layer = self.stackedLayer for mask in self.maskList.masks: newLayer = self.image_view.getNewContentLayer() filters = mask.filters + [ CIFilter.filterWithName_keysAndValues_( 'CIColorInvert', 'name', 'invertToMask', None), CIFilter.filterWithName_keysAndValues_( 'CIMaskToAlpha', 'name', 'mask', None), CIFilter.filterWithName_keysAndValues_( 'CIColorInvert', 'name', 'maskToBlack', None) ] newLayer.setFilters_(filters) newLayer.setOpacity_(0.5) mask.displayedLayer = newLayer layer.addSublayer_(newLayer) self.image_view.showLayer(self.stackedLayer) def outlineView_child_ofItem_(self, outlineView, index, item): if item == None: return self.root[index] else: return item.child(index) def outlineView_isItemExpandable_(self, outlineView, item): return item.hasChildren() def outlineView_numberOfChildrenOfItem_(self, outlineView, item): if self.root == None: # this can be called before we've been loaded from the Xib return 0 elif item == None: return len(self.root) else: return item.numChildren() def outlineView_objectValueForTableColumn_byItem_(self, outlineView, tableColumn, item): return item.name def outlineView_shouldSelectItem_(self, outlineView, item): return item.shouldSelect() def outlineViewSelectionDidChange_(self, notification): if self.selected != None: self.selected.unselected() self.selected = self.source_list.itemAtRow_( self.source_list.selectedRow()) self.selected.selected() self.updateSelected() def zoomOut_(self, sender): self.image_view.zoomOut_(self) def zoomIn_(self, sender): self.image_view.zoomIn_(self) def zoomActualSize_(self, sender): self.image_view.zoomImageToActualSize_(self) def zoomToFit_(self, sender): self.image_view.zoomImageToFit_(self) def observeValueForKeyPath_ofObject_change_context_( self, key, object, change, context): if key == 'zoom_factor' and object == self.image_view: self.zoom_slider.setFloatValue_(math.sqrt(math.sqrt(change._.new))) @objc.IBAction def zoomSliderMoved_(self, sender): self.image_view.setZoomFactor_(sender.floatValue()**4) @objc.IBAction def sourceToolsClicked_(self, sender): self.sourceToolsActions[sender.cell().tagForSegment_( sender.selectedSegment())]() def addItem(self): maskObjs = self.project.mutableSetValueForKey_('masks') objContext = self.managedObjectContext() newMask = NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext_( 'Mask', objContext) newMask.setValue_forKey_('test', 'name') newMask.setValue_forKey_(NSColor.redColor(), 'color') newMask.setValue_forKey_(0.4, 'chromaTolerance') newMask.setValue_forKey_(len(self.maskList.masks), 'sortOrder') maskObjs.addObject_(newMask) newItem = self.maskList.addMaskWithMask_(newMask) newItem.imageSet() self.source_list.reloadItem_reloadChildren_(self.maskList, True) self.source_list.selectRowIndexes_byExtendingSelection_( NSIndexSet.indexSetWithIndex_( self.source_list.rowForItem_(newItem)), False) self.outlineViewSelectionDidChange_(None) def removeItem(self): if isinstance(self.selected, MaskItem): maskObjs = self.project.mutableSetValueForKey_('masks') objContext = self.managedObjectContext() toRemove = self.selected toRemove.unbind() toRemove.unselected() self.selected = None self.maskList.masks.remove(toRemove) self.source_list.reloadItem_reloadChildren_(self.maskList, True) maskObjs.removeObject_(toRemove.mask) objContext.deleteObject_(toRemove.mask) self.outlineViewSelectionDidChange_(None)
class AppController(NSObject): mainWindow = objc.IBOutlet() taskCreationDialog = objc.IBOutlet() priorityPopup = objc.IBOutlet() eventCreationDialog = objc.IBOutlet() calendarData = objc.IBOutlet() calItemTitle = objc.ivar() calItemStartDate = objc.ivar() calItemEndDate = objc.ivar() objc.synthesize("calItemTitle", copy=True) objc.synthesize("calItemStartDate", copy=True) objc.synthesize("calItemEndDate", copy=True) @objc.IBAction def showTaskCreationDialog_(self, sender): # Set default values for the title, start date and priority # Cocoa bindings will clear out the related fields in the sheet self._.calItemTitle = None self._.calItemStartDate = NSDate.date() NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_( self.taskCreationDialog, self.mainWindow, self, "didEndSheet:returnCode:contextInfo:", None, ) @objc.IBAction def showEventCreationDialog_(self, sender): # Set default values for the title and start/end date # Cocoa bindings will clear out the related fields in the sheet self._.calItemTitle = None self._.calItemStartDate = NSDate.date() self._.calItemEndDate = NSDate.dateWithTimeIntervalSinceNow_(3600) NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_( self.eventCreationDialog, self.mainWindow, self, "didEndSheet:returnCode:contextInfo:", None, ) # Called when the "Add" button is pressed on the event/task entry sheet # This starts the sheet dismissal process @objc.IBAction def dismissDialog_(self, sender): NSApp.endSheet_(sender.window()) @objc.selectorFor( NSApplication. beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_) def didEndSheet_returnCode_contextInfo_(self, sheet, returnCode, contextInfo): # Find out which calendar was selected for the new event/task # We do this using the calendarData array controller which is bound to # the calendar popups in the sheet selectedCalendar = None count = len(self.calendarData.selectedObjects()) if count > 0: selectedCalendarUID = self.calendarData.selectedObjects()[0].uid() selectedCalendar = CalCalendarStore.defaultCalendarStore( ).calendarWithUID_(selectedCalendarUID) # Create an event/task based on which sheet was used if sheet is self.taskCreationDialog: if self._.calItemTitle is None: self._.calItemTitle = "My Task" self.createNewTaskWithCalendar_title_priority_dueDate_( selectedCalendar, self._.calItemTitle, self.priorityPopup.selectedTag(), self._.calItemStartDate, ) else: if self._.calItemTitle is None: self._.calItemTitle = "My Event" self.createNewEventWithCalendar_title_startDate_endDate_( selectedCalendar, self._.calItemTitle, self._.calItemStartDate, self._.calItemEndDate, ) # Dismiss the sheet sheet.orderOut_(self) def createNewEventWithCalendar_title_startDate_endDate_( self, calendar, title, startDate, endDate): # Create a new CalEvent object newEvent = CalEvent.event() # Set the calendar, title, start date and end date on the new event # using the parameters passed to this method newEvent._.calendar = calendar newEvent._.title = title newEvent._.startDate = startDate newEvent._.endDate = endDate # Save the new event to the calendar store (CalCalendarStore) and # return it res, err = CalCalendarStore.defaultCalendarStore( ).saveEvent_span_error_(newEvent, 0, None) if res: return newEvent NSLog("error:%@", err.localizedDescription()) return None def createNewTaskWithCalendar_title_priority_dueDate_( self, calendar, title, priority, dueDate): # Create a new CalTask object newTask = CalTask.task() # Set the calendar, title, priority and due date on the new task # using the parameters passed to this method newTask._.calendar = calendar newTask._.title = title newTask._.priority = priority newTask._.dueDate = dueDate # Save the new task to the calendar store (CalCalendarStore) and # return it res, err = CalCalendarStore.defaultCalendarStore().saveTask_error_( newTask, None) if res: return newTask NSLog("error:%@", err.localizedDescription()) return None
class HistoryViewer(NSWindowController): chatViewController = objc.IBOutlet() indexTable = objc.IBOutlet() contactTable = objc.IBOutlet() toolbar = objc.IBOutlet() entriesView = objc.IBOutlet() period = objc.IBOutlet() searchText = objc.IBOutlet() searchMedia = objc.IBOutlet() searchContactBox = objc.IBOutlet() paginationButton = objc.IBOutlet() foundMessagesLabel = objc.IBOutlet() queryDatabaseLabel = objc.IBOutlet() busyIndicator = objc.IBOutlet() contactMenu = objc.IBOutlet() # viewer sections contacts = [] dayly_entries = NSMutableArray.array() messages = [] # database handler history = None # search filters start = 0 search_text = None search_uris = None search_local = None search_media = None after_date = None before_date = None refresh_contacts_counter = 1 contact_cache = {} display_name_cache = {} refresh_in_progress = False daily_order_fields = {'date': 'DESC', 'local_uri': 'ASC', 'remote_uri': 'ASC'} media_type_array = {0: None, 1: ('audio', 'video'), 2: ('chat', 'sms'), 3: 'file-transfer', 4: 'audio-recording', 5: 'availability', 6: 'voicemail', 7: 'video-recording'} period_array = {0: None, 1: datetime.datetime.now()-datetime.timedelta(days=1), 2: datetime.datetime.now()-datetime.timedelta(days=7), 3: datetime.datetime.now()-datetime.timedelta(days=31), 4: datetime.datetime.now()-datetime.timedelta(days=90), 5: datetime.datetime.now()-datetime.timedelta(days=180), 6: datetime.datetime.now()-datetime.timedelta(days=365), -1: datetime.datetime.now()-datetime.timedelta(days=1), -2: datetime.datetime.now()-datetime.timedelta(days=7), -3: datetime.datetime.now()-datetime.timedelta(days=31), -4: datetime.datetime.now()-datetime.timedelta(days=90), -5: datetime.datetime.now()-datetime.timedelta(days=180), -6: datetime.datetime.now()-datetime.timedelta(days=365) } @objc.python_method def format_media_type(self, media_type): if media_type == 'sms': media_type_formated = NSLocalizedString("Short Messages", "Label") elif media_type == 'chat': media_type_formated = NSLocalizedString("Chat Sessions", "Label") elif media_type == 'audio': media_type_formated = NSLocalizedString("Audio Calls", "Label") elif media_type == 'file-transfer': media_type_formated = NSLocalizedString("File Transfers", "Label") elif media_type == 'availability': media_type_formated = NSLocalizedString("Availability", "Label") elif media_type == 'missed-call': media_type_formated = NSLocalizedString("Missed Call", "Label") elif media_type == 'voicemail': media_type_formated = NSLocalizedString("Voicemail", "Label") else: media_type_formated = media_type.title() return media_type_formated def __new__(cls, *args, **kwargs): return cls.alloc().init() def __init__(self): if self: BlinkLogger().log_debug('Starting History Viewer') NSBundle.loadNibNamed_owner_("HistoryViewer", self) self.all_contacts = BlinkHistoryViewerContact('Any Address', name='All Contacts') self.bonjour_contact = BlinkHistoryViewerContact('bonjour.local', name='Bonjour Neighbours', icon=NSImage.imageNamed_("NSBonjour")) self.notification_center = NotificationCenter() self.notification_center.add_observer(self, name='ChatViewControllerDidDisplayMessage') self.notification_center.add_observer(self, name='AudioCallLoggedToHistory') self.notification_center.add_observer(self, name='BlinkContactsHaveChanged') self.notification_center.add_observer(self, name='BlinkTableViewSelectionChaged') self.notification_center.add_observer(self, name='BlinkConferenceContactPresenceHasChanged') self.notification_center.add_observer(self, name='BlinkShouldTerminate') self.searchText.cell().setSendsSearchStringImmediately_(True) self.searchText.cell().setPlaceholderString_(NSLocalizedString("Type text and press Enter", "Placeholder text")) self.chatViewController.setContentFile_(NSBundle.mainBundle().pathForResource_ofType_("ChatView", "html")) self.chatViewController.setHandleScrolling_(False) self.entriesView.setShouldCloseWithWindow_(False) for c in ('remote_uri', 'local_uri', 'date', 'type'): col = self.indexTable.tableColumnWithIdentifier_(c) descriptor = NSSortDescriptor.alloc().initWithKey_ascending_(c, True) col.setSortDescriptorPrototype_(descriptor) self.chat_history = ChatHistory() self.session_history = SessionHistory() self.setPeriod(1) self.selectedTableView = self.contactTable @objc.python_method def setPeriod(self, days): if days <= -365: tag = -6 elif days <= -180: tag = -5 elif days <= -90: tag = -4 elif days <= -31: tag = -3 elif days <= -7: tag = -2 elif days <= -1: tag = -1 elif days <= 1: tag = 1 elif days <= 7: tag = 2 elif days <= 31: tag = 3 elif days <= 90: tag = 4 elif days <= 180: tag = 5 elif days <= 365: tag = 6 else: tag = 0 if tag == 0: self.before_date = None self.after_date = None elif tag < 0: try: date = self.period_array[tag] except KeyError: date = None self.before_date = date self.after_date = None else: try: date = self.period_array[tag] except KeyError: date = None self.after_date = date self.before_date = None self.period.selectItemWithTag_(tag) def awakeFromNib(self): NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, "contactSelectionChanged:", NSTableViewSelectionDidChangeNotification, self.contactTable) timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(1, self, "refreshContactsTimer:", None, True) NSRunLoop.currentRunLoop().addTimer_forMode_(timer, NSModalPanelRunLoopMode) NSRunLoop.currentRunLoop().addTimer_forMode_(timer, NSDefaultRunLoopMode) self.contactTable.setDoubleAction_("doubleClick:") def close_(self, sender): self.window().close() @objc.python_method @run_in_green_thread def delete_messages(self, local_uri=None, remote_uri=None, date=None, after_date=None, before_date=None, media_type=None): block_on(self.chat_history.delete_messages(local_uri=local_uri, remote_uri=remote_uri, date=date, after_date=after_date, before_date=before_date, media_type=media_type)) block_on(self.session_history.delete_entries(local_uri=local_uri, remote_uri=remote_uri, after_date=after_date, before_date=before_date)) self.search_text = None self.search_uris = None self.search_local = None self.refreshViewer() @objc.python_method def refreshViewer(self): self.refreshContacts() self.refreshDailyEntries() self.refreshMessages() @objc.python_method @run_in_green_thread def refreshContacts(self): if self.refresh_in_progress: return self.refresh_in_progress = True self.refresh_contacts_counter = 0 if self.chat_history: self.updateBusyIndicator(True) remote_uri = self.search_uris if self.search_uris else None media_type = self.search_media if self.search_media else None search_text = self.search_text if self.search_text else None after_date = self.after_date if self.after_date else None before_date = self.before_date if self.before_date else None results = self.chat_history.get_contacts(remote_uri=remote_uri, media_type=media_type, search_text=search_text, after_date=after_date, before_date=before_date) self.renderContacts(results) self.updateBusyIndicator(False) @objc.python_method @run_in_gui_thread def renderContacts(self, results): index = 0 found_uris = [] uris_without_display_name = [] for item in self.contacts: item.destroy() getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI self.contacts = [self.all_contacts, self.bonjour_contact] if self.search_uris: for uri in self.search_uris: try: found_contact = self.contact_cache[uri] except KeyError: found_contact = getFirstContactMatchingURI(uri, exact_match=True) self.contact_cache[uri] = found_contact if found_contact: contact_exist = False for contact_uri in found_contact.uris: if contact_uri.uri in found_uris: contact_exist = True break if contact_exist: continue contact = BlinkHistoryViewerContact(found_contact.uri, name=found_contact.name, icon=found_contact.icon) for contact_uri in found_contact.uris: found_uris.append(contact_uri.uri) self.contacts.append(contact) if isinstance(found_contact, BlinkPresenceContact): contact.setPresenceContact_(found_contact) else: if uri in found_uris: continue found_uris.append(uri) contact = BlinkHistoryViewerContact(str(uri), name=str(uri)) try: index = self.contacts.index(contact) except ValueError: pass if results: for row in results: try: found_contact = self.contact_cache[row[0]] except KeyError: found_contact = getFirstContactMatchingURI(row[0], exact_match=True) self.contact_cache[row[0]] = found_contact if found_contact: contact_exist = False for contact_uri in found_contact.uris: if contact_uri.uri in found_uris: contact_exist = True break if contact_exist: continue contact = BlinkHistoryViewerContact(found_contact.uri, name=found_contact.name, icon=found_contact.icon, presence_contact=found_contact if isinstance(found_contact, BlinkPresenceContact) else None) for contact_uri in found_contact.uris: found_uris.append(contact_uri.uri) else: if row[0] in found_uris: continue found_uris.append(row[0]) try: display_name = self.display_name_cache[row[0]] except KeyError: display_name = str(row[0]) uris_without_display_name.append(row[0]) contact = BlinkHistoryViewerContact(str(row[0]), name=display_name) self.contacts.append(contact) self.update_display_names(uris_without_display_name) self.contactTable.reloadData() self.contactTable.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(index), False) self.contactTable.scrollRowToVisible_(index) self.updateContactsColumnHeader() self.refresh_in_progress = False @objc.python_method @run_in_green_thread def update_display_names(self, uris_without_display_name): results = self.session_history.get_display_names(uris_without_display_name) self.updateDisplayNames(results) @objc.python_method @run_in_gui_thread def updateDisplayNames(self, results): must_reload = False for result in results: self.display_name_cache[result[0]]=result[1] for contact in self.contacts: if contact.uri == result[0] and contact.name != result[1]: contact.name = result[1] must_reload = True if must_reload: self.contactTable.reloadData() must_reload = False for entry in self.dayly_entries: if entry['remote_uri_sql'] == entry['remote_uri']: try: display_name = self.display_name_cache[entry['remote_uri_sql']] except KeyError: pass else: entry['display_name'] = display_name entry['remote_uri'] = '%s <%s>' % (display_name, entry['remote_uri_sql']) if '@' in entry['remote_uri_sql'] else display_name must_reload = True self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors()) self.indexTable.reloadData() @objc.python_method @run_in_green_thread def refreshDailyEntries(self, order_text=None): if self.chat_history: self.resetDailyEntries() self.updateBusyIndicator(True) search_text = self.search_text if self.search_text else None remote_uri = self.search_uris if self.search_uris else None local_uri = self.search_local if self.search_local else None media_type = self.search_media if self.search_media else None after_date = self.after_date if self.after_date else None before_date = self.before_date if self.before_date else None results = self.chat_history.get_daily_entries(local_uri=local_uri, remote_uri=remote_uri, media_type=media_type, search_text=search_text, order_text=order_text, after_date=after_date, before_date=before_date) self.renderDailyEntries(results) self.updateBusyIndicator(False) @objc.python_method @run_in_gui_thread def resetDailyEntries(self): self.dayly_entries = NSMutableArray.array() self.indexTable.reloadData() @objc.python_method @run_in_gui_thread def renderDailyEntries(self, results): getFirstContactMatchingURI = NSApp.delegate().contactsWindowController.getFirstContactMatchingURI self.dayly_entries = NSMutableArray.array() for result in results: display_name = None try: found_contact = self.contact_cache[result[2]] except KeyError: found_contact = getFirstContactMatchingURI(result[2], exact_match=True) self.contact_cache[result[2]] = found_contact if found_contact: display_name = found_contact.name remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name else: try: display_name = self.display_name_cache[result[2]] except KeyError: remote_uri = result[2] else: remote_uri = '%s <%s>' % (display_name, result[2]) if '@' in result[2] else display_name entry = NSMutableDictionary.dictionaryWithObjectsAndKeys_(result[1], "local_uri", remote_uri, "remote_uri", result[2], "remote_uri_sql", result[0], 'date', result[3], 'type', display_name, "display_name") self.dayly_entries.addObject_(entry) self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors()) self.indexTable.reloadData() if self.search_uris and not self.dayly_entries: self.contactTable.deselectAll_(True) @objc.python_method @run_in_green_thread def refreshMessages(self, count=SQL_LIMIT, remote_uri=None, local_uri=None, media_type=None, date=None, after_date=None, before_date=None): if self.chat_history: self.updateBusyIndicator(True) search_text = self.search_text if self.search_text else None if not remote_uri: remote_uri = self.search_uris if self.search_uris else None if not local_uri: local_uri = self.search_local if self.search_local else None if not media_type: media_type = self.search_media if self.search_media else None if not after_date: after_date = self.after_date if self.after_date else None if not before_date: before_date = self.before_date if self.before_date else None results = self.chat_history.get_messages(count=count, local_uri=local_uri, remote_uri=remote_uri, media_type=media_type, date=date, search_text=search_text, after_date=after_date, before_date=before_date) self.renderMessages(results) self.updateBusyIndicator(False) @objc.python_method @run_in_gui_thread def renderMessages(self, messages=None): self.chatViewController.clear() self.chatViewController.resetRenderedMessages() self.chatViewController.last_sender = None if messages is not None: # new message list. cache for pagination and reset pagination to the last page self.messages = list(reversed(messages)) message_count = len(messages) start = message_count // MAX_MESSAGES_PER_PAGE * MAX_MESSAGES_PER_PAGE end = message_count else: message_count = len(self.messages) start = self.start end = min(start + MAX_MESSAGES_PER_PAGE, message_count) for row in self.messages[start:end]: self.renderMessage(row) self.paginationButton.setEnabled_forSegment_(start > MAX_MESSAGES_PER_PAGE, 0) self.paginationButton.setEnabled_forSegment_(start > 0, 1) self.paginationButton.setEnabled_forSegment_(start + MAX_MESSAGES_PER_PAGE + 1 < message_count, 2) self.paginationButton.setEnabled_forSegment_(start + MAX_MESSAGES_PER_PAGE * 2 < message_count, 3) if message_count == 0: text = NSLocalizedString("No entry found", "Label") elif message_count == 1: text = NSLocalizedString("Displaying 1 entry", "Label") elif message_count < MAX_MESSAGES_PER_PAGE: text = NSLocalizedString("Displaying {} entries".format(end), "Label") else: text = NSLocalizedString("Displaying {} to {} out of {} entries", "Label").format(start+1, end, message_count) self.foundMessagesLabel.setStringValue_(text) @objc.python_method @run_in_gui_thread def renderMessage(self, message): if message.direction == 'outgoing': icon = NSApp.delegate().contactsWindowController.iconPathForSelf() else: sender_uri = sipuri_components_from_string(message.cpim_from)[0] # TODO: How to render the icons from Address Book? Especially in sandbox mode we do not have access to other folders icon = NSApp.delegate().contactsWindowController.iconPathForURI(sender_uri) try: timestamp=ISOTimestamp(message.cpim_timestamp) except Exception: pass else: is_html = False if message.content_type == 'text' else True private = True if message.private == "1" else False self.chatViewController.showMessage(message.sip_callid, message.msgid, message.direction, message.cpim_from, icon, message.body, timestamp, is_private=private, recipient=message.cpim_to, state=message.status, is_html=is_html, history_entry=True, media_type=message.media_type, encryption=message.encryption if message.media_type == 'chat' else None) @objc.IBAction def paginateResults_(self, sender): if sender.selectedSegment() == 0: self.start = 0 elif sender.selectedSegment() == 1: next_start = self.start - MAX_MESSAGES_PER_PAGE self.start = next_start if next_start >= 0 else self.start elif sender.selectedSegment() == 2: next_start = self.start + MAX_MESSAGES_PER_PAGE self.start = next_start if next_start < len(self.messages)-1 else self.start elif sender.selectedSegment() == 3: self.start = len(self.messages) - len(self.messages)%MAX_MESSAGES_PER_PAGE if len(self.messages) > MAX_MESSAGES_PER_PAGE else 0 self.renderMessages() def tableView_deleteRow_(self, table, row): pass def tableView_sortDescriptorsDidChange_(self, table, odescr): self.dayly_entries.sortUsingDescriptors_(self.indexTable.sortDescriptors()) self.indexTable.reloadData() @objc.IBAction def printDocument_(self, sender): printInfo = NSPrintInfo.sharedPrintInfo() printInfo.setTopMargin_(30) printInfo.setBottomMargin_(30) printInfo.setLeftMargin_(10) printInfo.setRightMargin_(10) printInfo.setOrientation_(NSPortraitOrientation) printInfo.setHorizontallyCentered_(True) printInfo.setVerticallyCentered_(False) printInfo.setHorizontalPagination_(NSFitPagination) printInfo.setVerticalPagination_(NSFitPagination) NSPrintInfo.setSharedPrintInfo_(printInfo) # print the content of the web view self.entriesView.mainFrame().frameView().documentView().print_(self) @objc.IBAction def search_(self, sender): if self.chat_history: self.search_text = str(sender.stringValue()).lower() self.refreshContacts() row = self.indexTable.selectedRow() if row > 0: self.refreshDailyEntries() self.refreshMessages(local_uri=self.dayly_entries[row].objectForKey_("local_uri"), date=self.dayly_entries[row].objectForKey_("date"), media_type=self.dayly_entries[row].objectForKey_("type")) else: row = self.contactTable.selectedRow() if row > 0: self.refreshMessages() self.refreshDailyEntries() else: self.refreshDailyEntries() self.refreshMessages() @objc.IBAction def searchContacts_(self, sender): text = str(self.searchContactBox.stringValue().strip()) contacts = [contact for contact in self.contacts[2:] if text in contact] if text else self.contacts[2:] self.contacts = [self.all_contacts, self.bonjour_contact] + contacts self.contactTable.reloadData() self.contactTable.selectRowIndexes_byExtendingSelection_(NSIndexSet.indexSetWithIndex_(0), False) self.contactTable.scrollRowToVisible_(0) self.updateContactsColumnHeader() if not text: self.refreshContacts() @objc.python_method def updateContactsColumnHeader(self): found_contacts = len(self.contacts)-2 if found_contacts == 1: title = NSLocalizedString("1 contact found", "Label") elif found_contacts > 1: title = NSLocalizedString("%d contacts found", "Label") % found_contacts else: title = NSLocalizedString("Contacts", "Label") self.contactTable.tableColumnWithIdentifier_('contacts').headerCell().setStringValue_(title) def tableViewSelectionDidChange_(self, notification): if self.chat_history: if notification.object() == self.contactTable: row = self.contactTable.selectedRow() if row < 0: return elif row == 0: self.search_local = None self.search_uris = None self.searchContactBox.setStringValue_('') self.refreshContacts() elif row == 1: self.search_local = 'bonjour.local' self.search_uris = None elif row > 1: self.search_local = None if self.contacts[row].presence_contact is not None: self.search_uris = list(str(contact_uri.uri) for contact_uri in self.contacts[row].presence_contact.uris) self.chatViewController.expandSmileys = not self.contacts[row].presence_contact.contact.disable_smileys self.chatViewController.toggleSmileys(self.chatViewController.expandSmileys) try: item = next((item for item in self.toolbar.visibleItems() if item.itemIdentifier() == 'smileys')) except StopIteration: pass else: item.setImage_(NSImage.imageNamed_("smiley_on" if self.chatViewController.expandSmileys else "smiley_off")) else: self.search_uris = (self.contacts[row].uri,) self.refreshDailyEntries() self.refreshMessages() else: row = self.indexTable.selectedRow() if row >= 0: self.refreshMessages(remote_uri=(self.dayly_entries[row].objectForKey_("remote_uri_sql"),), local_uri=self.dayly_entries[row].objectForKey_("local_uri"), date=self.dayly_entries[row].objectForKey_("date"), media_type=self.dayly_entries[row].objectForKey_("type")) def numberOfRowsInTableView_(self, table): if table == self.indexTable: return self.dayly_entries.count() elif table == self.contactTable: return len(self.contacts) return 0 def tableView_objectValueForTableColumn_row_(self, table, column, row): if table == self.indexTable: ident = column.identifier() if ident == 'type': return self.format_media_type(self.dayly_entries[row].objectForKey_(ident)) try: return str(self.dayly_entries[row].objectForKey_(ident)) except IndexError: return None elif table == self.contactTable: try: if type(self.contacts[row]) in (str, str): return self.contacts[row] else: return self.contacts[row].name except IndexError: return None return None def tableView_willDisplayCell_forTableColumn_row_(self, table, cell, tableColumn, row): if table == self.contactTable: try: if row < len(self.contacts): if type(self.contacts[row]) in (str, str): cell.setContact_(None) else: cell.setContact_(self.contacts[row]) except: pass def showWindow_(self, sender): self.window().makeKeyAndOrderFront_(None) @objc.python_method @run_in_gui_thread def filterByURIs(self, uris=(), media_type=None): self.search_text = None self.search_local = None if media_type != self.search_media: for tag in list(self.media_type_array.keys()): if self.media_type_array[tag] == media_type: self.searchMedia.selectItemAtIndex_(tag) self.search_media = media_type self.search_uris = uris self.refreshContacts() self.refreshDailyEntries() self.refreshMessages() @objc.IBAction def filterByMediaChanged_(self, sender): tag = sender.selectedItem().tag() self.search_media = self.media_type_array[tag] self.refreshContacts() self.refreshDailyEntries() self.refreshMessages() @objc.IBAction def filterByPeriodChanged_(self, sender): tag = sender.selectedItem().tag() if tag == 0: self.before_date = None self.after_date = None elif tag < 0: try: date = self.period_array[tag] except KeyError: date = None self.before_date = date self.after_date = None else: try: date = self.period_array[tag] except KeyError: date = None self.after_date = date self.before_date = None self.refreshContacts() self.refreshDailyEntries() self.refreshMessages() def validateToolbarItem_(self, item): if item.itemIdentifier() == NSToolbarPrintItemIdentifier and not self.messages: return False return True def toolbarWillAddItem_(self, notification): item = notification.userInfo()["item"] if item.itemIdentifier() == NSToolbarPrintItemIdentifier: item.setToolTip_("Print Current Entries") item.setTarget_(self) item.setAutovalidates_(True) @objc.IBAction def userClickedToolbarItem_(self, sender): if sender.itemIdentifier() == 'smileys': self.chatViewController.expandSmileys = not self.chatViewController.expandSmileys sender.setImage_(NSImage.imageNamed_("smiley_on" if self.chatViewController.expandSmileys else "smiley_off")) self.chatViewController.toggleSmileys(self.chatViewController.expandSmileys) row = self.contactTable.selectedRow() if row and row > 1 and self.contacts[row].presence_contact is not None: self.contacts[row].presence_contact.contact.disable_smileys = not self.contacts[row].presence_contact.contact.disable_smileys self.contacts[row].presence_contact.contact.save() elif sender.itemIdentifier() == 'delete': if self.selectedTableView == self.contactTable: try: row = self.contactTable.selectedRow() self.showDeleteConfirmationDialog(row) except IndexError: pass elif self.selectedTableView == self.indexTable: try: row = self.indexTable.selectedRow() local_uri = self.dayly_entries[row].objectForKey_("local_uri") remote_uri = self.dayly_entries[row].objectForKey_("remote_uri") remote_uri_sql = self.dayly_entries[row].objectForKey_("remote_uri_sql") date = self.dayly_entries[row].objectForKey_("date") media_type = self.dayly_entries[row].objectForKey_("type") label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_type + NSLocalizedString(" from %s", "SIP Address label") % remote_uri + NSLocalizedString(" on %s. ", "Date label") % date + NSLocalizedString("This operation cannot be undone. ", "Label") ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None) if ret == NSAlertDefaultReturn: self.delete_messages(local_uri=local_uri, remote_uri=remote_uri_sql, media_type=media_type, date=date) except IndexError: pass @objc.python_method def showDeleteConfirmationDialog(self, row): media_print = self.search_media or NSLocalizedString("all", "Label") tag = self.period.selectedItem().tag() period = '%s %s' % (NSLocalizedString(" newer than", "Date label") if tag < 4 else NSLocalizedString(" older than", "Date label"), self.period_array[tag].strftime("%Y-%m-%d")) if tag else '' if row == 0: label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_print + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label") ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None) if ret == NSAlertDefaultReturn: self.delete_messages(media_type=self.search_media, after_date=self.after_date, before_date=self.before_date) elif row == 1: remote_uri=self.contacts[row].uri label = NSLocalizedString("Please confirm the deletion of %s Bonjour history entries", "Label") % media_print + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label") ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None) if ret == NSAlertDefaultReturn: self.delete_messages(local_uri='bonjour.local', media_type=self.search_media, after_date=self.after_date, before_date=self.before_date) else: contact = self.contacts[row] if contact.presence_contact is not None: remote_uri = list(str(contact.uri) for contact in contact.presence_contact.uris) else: remote_uri = contact.uri label = NSLocalizedString("Please confirm the deletion of %s history entries", "Label") % media_print + NSLocalizedString(" from ", "Label") + contact.name + period + ". "+ NSLocalizedString("This operation cannot be undone. ", "Label") ret = NSRunAlertPanel(NSLocalizedString("Purge History Entries", "Window title"), label, NSLocalizedString("Confirm", "Button title"), NSLocalizedString("Cancel", "Button title"), None) if ret == NSAlertDefaultReturn: self.delete_messages(remote_uri=remote_uri, media_type=self.search_media, after_date=self.after_date, before_date=self.before_date) @objc.python_method @run_in_gui_thread def updateBusyIndicator(self, busy=False): if busy: self.queryDatabaseLabel.setHidden_(False) self.busyIndicator.setHidden_(False) self.busyIndicator.setIndeterminate_(True) self.busyIndicator.setStyle_(NSProgressIndicatorSpinningStyle) self.busyIndicator.startAnimation_(None) else: self.busyIndicator.stopAnimation_(None) self.busyIndicator.setHidden_(True) self.queryDatabaseLabel.setHidden_(True) @objc.python_method @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) @objc.python_method def _NH_BlinkShouldTerminate(self, notification): if self.window(): self.window().orderOut_(self) @objc.python_method def _NH_ChatViewControllerDidDisplayMessage(self, notification): if notification.data.local_party != 'bonjour.local': exists = any(contact for contact in self.contacts if notification.data.remote_party == contact.uri) if not exists: self.refreshContacts() @objc.python_method def _NH_AudioCallLoggedToHistory(self, notification): if notification.data.local_party != 'bonjour.local': exists = any(contact for contact in self.contacts if notification.data.remote_party == contact.uri) if not exists: self.refreshContacts() @objc.python_method def _NH_BlinkContactsHaveChanged(self, notification): self.refresh_contacts_counter += 1 def refreshContactsTimer_(self, timer): if self.refresh_contacts_counter: self.refreshContacts() self.toolbar.validateVisibleItems() @objc.python_method def _NH_BlinkTableViewSelectionChaged(self, notification): self.selectedTableView = notification.sender self.toolbar.validateVisibleItems() @objc.python_method def _NH_BlinkConferenceContactPresenceHasChanged(self, notification): try: contact = next((contact for contact in self.contacts[2:] if contact == notification.sender)) except StopIteration: return else: try: idx = self.contacts.index(contact) self.contactTable.reloadDataForRowIndexes_columnIndexes_(NSIndexSet.indexSetWithIndex_(idx), NSIndexSet.indexSetWithIndex_(0)) except ValueError: pass def contactSelectionChanged_(self, notification): pass def menuWillOpen_(self, menu): if menu == self.contactMenu: self.contactMenu.itemWithTag_(2).setEnabled_(False) self.contactMenu.itemWithTag_(3).setEnabled_(False) self.contactMenu.itemWithTag_(4).setEnabled_(False) try: row = self.contactTable.selectedRow() except: return if row < 2: return try: contact = self.contacts[row] except IndexError: return contact_exists = bool(contact.presence_contact is not None) if '@' in contact.uri: self.contactMenu.itemWithTag_(2).setEnabled_(not is_anonymous(contact.uri)) self.contactMenu.itemWithTag_(3).setEnabled_(not contact_exists and not is_anonymous(contact.uri)) self.contactMenu.itemWithTag_(4).setEnabled_(contact_exists) else: bonjour_contact = NSApp.delegate().contactsWindowController.model.getBonjourContactMatchingDeviceId(contact.uri) self.contactMenu.itemWithTag_(2).setEnabled_(bool(bonjour_contact)) self.contactMenu.itemWithTag_(3).setEnabled_(False) self.contactMenu.itemWithTag_(4).setEnabled_(False) @objc.IBAction def doubleClick_(self, sender): row = self.contactTable.selectedRow() if row < 2: return try: contact = self.contacts[row] except IndexError: return if '@' in contact.uri: NSApp.delegate().contactsWindowController.startSessionWithTarget(contact.uri) else: bonjour_contact = NSApp.delegate().contactsWindowController.model.getBonjourContactMatchingDeviceId(contact.uri) if not bonjour_contact: BlinkLogger().log_info("Bonjour neighbour %s was not found on this network" % contact.name) message = NSLocalizedString("Bonjour neighbour %s was not found on this network. ", "label") % contact.name NSRunAlertPanel(NSLocalizedString("Error", "Window title"), message, NSLocalizedString("OK", "Button title"), None, None) return NSApp.delegate().contactsWindowController.startSessionWithTarget(bonjour_contact.uri) @objc.IBAction def userClickedContactMenu_(self, sender): row = self.contactTable.selectedRow() try: contact = self.contacts[row] except IndexError: return tag = sender.tag() if tag == 1: self.showDeleteConfirmationDialog(row) elif tag == 2: NSApp.delegate().contactsWindowController.searchBox.setStringValue_(contact.uri) NSApp.delegate().contactsWindowController.searchContacts() NSApp.delegate().contactsWindowController.window().makeFirstResponder_(NSApp.delegate().contactsWindowController.searchBox) NSApp.delegate().contactsWindowController.window().deminiaturize_(sender) NSApp.delegate().contactsWindowController.window().makeKeyWindow() elif tag == 3: NSApp.delegate().contactsWindowController.addContact(uris=[(contact.uri, 'sip')], name=contact.name) elif tag == 4 and contact.presence_contact is not None: NSApp.delegate().contactsWindowController.model.editContact(contact.presence_contact) @objc.IBAction def userClickedActionsButton_(self, sender): point = sender.window().convertScreenToBase_(NSEvent.mouseLocation()) event = NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_( NSLeftMouseUp, point, 0, NSDate.timeIntervalSinceReferenceDate(), sender.window().windowNumber(), sender.window().graphicsContext(), 0, 1, 0) NSMenu.popUpContextMenu_withEvent_forView_(self.contactMenu, event, sender)
class DragAppAppDelegate(Cocoa.NSObject): clubWindow = objc.IBOutlet() peopleWindow = objc.IBOutlet() _managedObjectModel = objc.ivar() _managedObjectContext = objc.ivar() _things = objc.ivar() def managedObjectModel(self): if self._managedObjectModel is None: allBundles = Cocoa.NSMutableSet.alloc().init() allBundles.addObject_(Cocoa.NSBundle.mainBundle()) allBundles.addObjectsFromArray_(Cocoa.NSBundle.allFrameworks()) self._managedObjectModel = ( CoreData.NSManagedObjectModel.mergedModelFromBundles_( allBundles.allObjects())) return self._managedObjectModel # Change this path/code to point to your App's data store. def applicationSupportFolder(self): paths = Cocoa.NSSearchPathForDirectoriesInDomains( Cocoa.NSApplicationSupportDirectory, Cocoa.NSUserDomainMask, True) if len(paths) == 0: Cocoa.NSRunAlertPanel("Alert", "Can't find application support folder", "Quit", None, None) Cocoa.NSApplication.sharedApplication().terminate_(self) else: applicationSupportFolder = paths[ 0].stringByAppendingPathComponent_("DragApp") return applicationSupportFolder def managedObjectContext(self): if self._managedObjectContext is None: fileManager = Cocoa.NSFileManager.defaultManager() applicationSupportFolder = self.applicationSupportFolder() if not fileManager.fileExistsAtPath_isDirectory_( applicationSupportFolder, None)[0]: fileManager.createDirectoryAtPath_attributes_( applicationSupportFolder, None) url = Cocoa.NSURL.fileURLWithPath_( applicationSupportFolder.stringByAppendingPathComponent_( "DragApp.xml")) coordinator = CoreData.NSPersistentStoreCoordinator.alloc( ).initWithManagedObjectModel_( # noqa: B950 self.managedObjectModel()) ( result, error, ) = coordinator.addPersistentStoreWithType_configuration_URL_options_error_( CoreData.NSXMLStoreType, None, url, None, None) if result: self._managedObjectContext = ( CoreData.NSManagedObjectContext.alloc().init()) self._managedObjectContext.setPersistentStoreCoordinator_( coordinator) else: Cocoa.NSApplication.sharedApplication().presentError_(error) return self._managedObjectContext def windowWillReturnUndoManager_(self, window): return self.managedObjectContext().undoManager() @objc.IBAction def saveAction_(self, sender): res, error = self.managedObjectContext().save_(None) if not res: Cocoa.NSApplication.sharedApplication().presentError_(error) def applicationShouldTerminate_(self, sender): context = self.managedObjectContext() reply = Cocoa.NSTerminateNow if context is not None: if context.commitEditing(): res, error = context.save_(None) if not res: # This default error handling implementation should be # changed to make sure the error presented includes # application specific error recovery. For now, simply # display 2 panels. errorResult = Cocoa.NSApplication.sharedApplication( ).presentError_(error) if errorResult: # Then the error was handled reply = Cocoa.NSTerminateCancel else: # Error handling wasn't implemented. Fall back to # displaying a "quit anyway" panel. alertReturn = Cocoa.NSRunAlertPanel( None, "Could not save changes while quitting. Quit anyway?", "Quit anyway", "Cancel", None, ) if alertReturn == Cocoa.NSAlertAlternateReturn: reply = Cocoa.NSTerminateCancel else: reply = Cocoa.NSTerminateCancel return reply
class MagicRemover (PalettePlugin): dialog = objc.IBOutlet() EraseButton = objc.IBOutlet() @objc.python_method def settings(self): self.name = Glyphs.localize({ 'en': 'Magic Remover', 'de': 'Magic-Löscher', 'es': 'Borrador magico', 'fr': 'Gomme magique', 'pt': 'Apagador mágico', 'it': 'Cancellatore magico', }) # Load .nib dialog (without .extension) self.loadNib('IBdialog', __file__) @objc.python_method def start(self): # Adding a callback for the 'GSUpdateInterface' event Glyphs.addCallback(self.update, UPDATEINTERFACE) @objc.python_method def __del__(self): Glyphs.removeCallback(self.update) @objc.python_method def update(self, sender): button = self.EraseButton # Extract font from sender currentTab, font = None, None sentObject = sender.object() if sentObject is None: return if sentObject.isKindOfClass_(GSEditViewController): currentTab = sentObject font = currentTab.parent.font() elif sentObject.isKindOfClass_(GSFont): font = sentObject currentTab = font.currentTab # We’re in the Edit View if currentTab: if font.selectedLayers and len(font.selectedLayers) == 1: if font.selectedLayers[0].selection: button.setEnabled_(True) return # default: disable button button.setEnabled_(False) return # Action triggered by UI @objc.IBAction def eraseSelectedItemsOnAllMasters_(self, sender=None): try: # get current font font = Glyphs.font if font: # We’re in the Edit View if font.currentTab and len(font.selectedLayers) == 1: currentLayer = font.selectedLayers[0] # collect selected items: pathNodeIndexes = [] anchorNames = [] componentIndexes = [] hintIDs = [] for thisItem in currentLayer.selection: if type(thisItem) == GSNode: pathNodeIndexes.append( currentLayer.indexPathOfNode_(thisItem) ) elif type(thisItem) == GSAnchor: anchorNames.append( thisItem.name ) elif type(thisItem) == GSComponent: componentIndexes.append( thisItem.elementIndex() ) elif type(thisItem) == GSHint: if thisItem.isCorner: hintIDs.append( hintID(thisItem) ) # delete respective items on all (compatible) layers: if pathNodeIndexes or anchorNames or componentIndexes or hintIDs: # reverse-sort path and node indexes # so deletion of nodes does not mess with the indexes of the next node to be deleted pathNodeIndexes = sorted( pathNodeIndexes, key=itemgetter(0,1), reverse=True, ) currentCS = currentLayer.compareString() thisGlyph = currentLayer.parent allCompatibleLayers = [l for l in thisGlyph.layers if (l.isMasterLayer or l.isSpecialLayer) and (l.compareString() == currentCS) ] thisGlyph.beginUndo() # begin undo grouping for thisLayer in allCompatibleLayers: for pathNodeIndex in pathNodeIndexes: pathIndex, nodeIndex = pathNodeIndex[0], pathNodeIndex[1] path = thisLayer.paths[pathIndex] node = thisLayer.nodeAtIndexPath_(pathNodeIndex) path.removeNodeCheckKeepShape_normalizeHandles_(node,True) for anchorName in anchorNames: thisLayer.removeAnchorWithName_(anchorName) for componentIndex in sorted(componentIndexes, reverse=True): if Glyphs.versionNumber >= 3: # GLYPHS 3 del thisLayer.shapes[componentIndex] else: # GLYPHS 2 del thisLayer.components[componentIndex] if hintIDs: for hintIndex in sorted(range(len(thisLayer.hints)), reverse=True): if hintID(thisLayer.hints[hintIndex]) in hintIDs: thisLayer.removeHint_(thisLayer.hints[hintIndex]) thisGlyph.endUndo() # end undo grouping except Exception as e: Glyphs.clearLog() # clears macro window log print("Magic Remover Exception:") print(e) print("\nMagic Remover Traceback:") import traceback print(traceback.format_exc()) @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__
class EnvironmentPane(PreferencePanes.NSPreferencePane): """ The 'model/controller' for the "Shell Environment" preference pane """ deleteButton = objc.IBOutlet() mainTable = objc.IBOutlet() # __slots__ = ( # 'environ', # The actual environment, as a NSMutableDictionary # 'keys', # The list of keys, in the right order for the tableView # 'changed', # True if we should save before exitting # ) def initWithBundle_(self, bundle): # Our bundle has been loaded, initialize the instance variables. # We don't load the environment.plist yet, do that when we're # actually selected. That way we can easier pick up manual changes. self = super(EnvironmentPane, self).initWithBundle_(bundle) if self is None: return None self.keys = () self.environ = None self.changed = False return self def mainViewDidLoad(self): self.deleteButton.setEnabled_(False) def didSelect(self): # We are the selected preference pane. Load the environment.plist. self.environ = Cocoa.NSMutableDictionary.dictionaryWithContentsOfFile_( os.path.expanduser(ENVPLIST) ) if self.environ is None: self.environ = Cocoa.NSMutableDictionary.dictionary() self.keys = list(self.environ.keys()) self.keys.sort() self.changed = False self.mainTable.reloadData() def shouldUnselect(self): # The user wants to select another preference pane. If we have # unsaved changes ask if they should be saved right now. if self.changed: Cocoa.NSBeginAlertSheet( Cocoa.NSLocalizedString("Save changes?", ""), Cocoa.NSLocalizedString("Cancel", ""), Cocoa.NSLocalizedString("Don't Save", ""), Cocoa.NSLocalizedString("Save", ""), self.mainView().window(), self, None, "sheetDidDismiss:returnCode:contextInfo:", 0, Cocoa.NSLocalizedString( "There are unsaved changed, should these be saved?", "" ), ) return PreferencePanes.NSUnselectLater return PreferencePanes.NSUnselectNow @AppHelper.endSheetMethod def sheetDidDismiss_returnCode_contextInfo_(self, sheet, code, info): # Sheet handler for saving unsaved changes. if code == Cocoa.NSAlertDefaultReturn: # 'Cancel' self.replyToShouldUnselect_(PreferencePanes.NSUnselectCancel) return elif code == Cocoa.NSAlertAlternateReturn: # 'Don't Save' pass elif code == Cocoa.NSAlertOtherReturn: # 'Save' r = self.saveEnvironment() if not r: self.runAlertSheet( Cocoa.NSLocalizedString("Cannot save changes", ""), Cocoa.NSLocalizedString( "It was not possible to save your changes", "" ), ) self.replyToShouldUnselect_(PreferencePanes.NSUnselectCancel) return self.keys = () self.environ = None self.changed = False self.replyToShouldUnselect_(PreferencePanes.NSUnselectNow) def saveEnvironment(self): """ Save the data to environment.plist """ fname = os.path.expanduser(ENVPLIST) dname = os.path.dirname(fname) if not os.path.isdir(dname): try: os.mkdir(dname) except os.error: return False if not self.environ.writeToFile_atomically_(fname, True): return False return True @objc.IBAction def deleteVariable_(self, sender): """ Delete the selected variable """ r = self.mainTable.selectedRow() envname = self.keys[r] del self.environ[envname] self.keys.remove(envname) self.mainTable.reloadData() self.changed = True @objc.IBAction def newVariable_(self, sender): """ Add a new variable """ i = 0 name = NEWTMPL % (i,) while name in self.environ: i += 1 name = NEWTMPL % (i,) self.environ[name] = Cocoa.NSLocalizedString("New Value", "") self.keys = list(self.environ.keys()) self.keys.sort() self.mainTable.reloadData() self.changed = True def numberOfRowsInTableView_(self, aView): """ Return the number of environment variables """ return len(self.keys) def tableView_objectValueForTableColumn_row_(self, aView, aCol, rowIndex): """ Get the name of value of an environment variable """ name = aCol.identifier() envname = self.keys[rowIndex] if name == "name": return envname elif name == "value": return self.environ[envname] def tableView_setObjectValue_forTableColumn_row_( self, aView, value, aCol, rowIndex ): """ Change the name or value of an environment variable """ if self.environ is None: aView.reloadData() return name = aCol.identifier() envname = self.keys[rowIndex] if name == "name": if value != envname: if value in self.environ: self.runAlertSheet( Cocoa.NSLocalizedString("Name exists", ""), Cocoa.NSLocalizedString("The name %s is already used", "") % (value,), ) aView.reloadData() return val = self.environ[envname] del self.environ[envname] self.environ[value] = val self.keys = list(self.environ.keys()) self.keys.sort() aView.reloadData() self.changed = True elif name == "value": val = self.environ[envname] if val != value: self.environ[envname] = value self.changed = True def tableViewSelectionDidChange_(self, notification): """ The delete button should only be active if a row is selected """ if self.mainTable.numberOfSelectedRows() == 0: self.deleteButton.setEnabled_(False) else: self.deleteButton.setEnabled_(True) @objc.python_method def runAlertSheet(self, title, message): """ Run an alertsheet without callbacks """ Cocoa.NSBeginAlertSheet( title, Cocoa.NSLocalizedString("OK", ""), None, None, self.mainView().window(), self, None, None, 0, message, )
class KeyboardIncrement(PalettePlugin): # the view dialog = objc.IBOutlet() # keyboard increment changer UIs keyboard_switch = objc.IBOutlet() keyboard_txt_keys = objc.IBOutlet() keyboard_txt_shift = objc.IBOutlet() # metrics increment changer UIs metrics_switch = objc.IBOutlet() metrics_txt_keys = objc.IBOutlet() metrics_txt_shift = objc.IBOutlet() # kerning increment changer UIs kerning_switch = objc.IBOutlet() kerning_txt_keys = objc.IBOutlet() kerning_txt_shift = objc.IBOutlet() @objc.python_method def settings(self): self.name = Glyphs.localize({ 'en': 'Keyboard Increment', # 'de': 'Meine Palette', # 'fr': 'Ma palette', # 'es': 'Mi panel', 'pt': 'Incremento de Teclado', }) # Load .nib dialog (without .extension) version = platform.mac_ver()[0] versionStr = platform.mac_ver()[0] parts = versionStr.split(".") if float(parts[0] + "." + parts[1]) >= 10.15: self.loadNib('IBdialog', __file__) else: self.loadNib('IBdialogpre15', __file__) @objc.python_method def start(self): Glyphs.registerDefault('com.filipenegrao.Increment.keyboard_small', 1) Glyphs.registerDefault('com.filipenegrao.Increment.keyboard_big', 10) Glyphs.registerDefault('com.filipenegrao.Increment.metrics_small', 1) Glyphs.registerDefault('com.filipenegrao.Increment.metrics_big', 10) Glyphs.registerDefault('com.filipenegrao.Increment.kerning_small', 1) Glyphs.registerDefault('com.filipenegrao.Increment.kerning_big', 10) Glyphs.registerDefault('com.filipenegrao.Increment.keyboard', False) Glyphs.registerDefault('com.filipenegrao.Increment.metrics', False) Glyphs.registerDefault('com.filipenegrao.Increment.kerning', False) self.keyboard_txt_keys.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.keyboard_small']) self.keyboard_txt_shift.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.keyboard_big']) self.metrics_txt_keys.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.metrics_small']) self.metrics_txt_shift.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.metrics_big']) self.kerning_txt_keys.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.kerning_small']) self.kerning_txt_shift.setIntValue_( Glyphs.defaults['com.filipenegrao.Increment.kerning_big']) self.keyboard_switch.setObjectValue_( bool(Glyphs.defaults['com.filipenegrao.Increment.keyboard'])) self.metrics_switch.setObjectValue_( bool(Glyphs.defaults['com.filipenegrao.Increment.metrics'])) self.kerning_switch.setObjectValue_( bool(Glyphs.defaults['com.filipenegrao.Increment.kerning'])) # if Glyphs.versionNumber <= 3.0: # self.keyboard_txt_shift.isEditable = False @objc.IBAction def setKeyboardSmall_(self, sender): key_small = sender.intValue() Glyphs.defaults[ 'com.filipenegrao.Increment.keyboard_small'] = key_small self.keyboard_txt_keys.setIntValue_(key_small) @objc.IBAction def setKeyboardBig_(self, sender): key_big = sender.intValue() Glyphs.defaults['com.filipenegrao.Increment.keyboard_big'] = key_big self.keyboard_txt_shift.setIntValue_(key_big) @objc.IBAction def applyKeyboard_(self, sender): switch_on = bool(sender.objectValue()) font = Glyphs.font if switch_on: try: # Glyphs 3 font.keyboardIncrement = Glyphs.defaults[ 'com.filipenegrao.Increment.keyboard_small'] font.keyboardIncrementBig = Glyphs.defaults[ 'com.filipenegrao.Increment.keyboard_big'] except: # Glyphs 2 keyboardIncrement = Glyphs.defaults[ 'com.filipenegrao.Increment.keyboard_small'] else: try: # Glyphs 3 font.keyboardIncrement = 1 font.keyboardIncrementBig = 10 except: # Glyphs 2 font.keyboardIncrement = 1 @objc.IBAction def setMetricsSmall_(self, sender): metrics_small = sender.intValue() Glyphs.defaults[ 'com.filipenegrao.Increment.metrics_small'] = metrics_small self.metrics_txt_keys.setIntValue_(metrics_small) @objc.IBAction def setMetricsBig_(self, sender): metrics_big = sender.intValue() Glyphs.defaults['com.filipenegrao.Increment.metrics_big'] = metrics_big self.metrics_txt_shift.setIntValue_(metrics_big) @objc.IBAction def applyMetrics_(self, sender): switch_on = bool(sender.objectValue()) font = Glyphs.font if switch_on: Glyphs.intDefaults["GSSpacingIncrementLow"] = Glyphs.defaults[ 'com.filipenegrao.Increment.metrics_small'] Glyphs.intDefaults["GSSpacingIncrementHigh"] = Glyphs.defaults[ 'com.filipenegrao.Increment.metrics_big'] else: Glyphs.intDefaults["GSSpacingIncrementLow"] = 1 Glyphs.intDefaults["GSSpacingIncrementHigh"] = 10 @objc.IBAction def setKerningSmall_(self, sender): kerning_small = sender.intValue() Glyphs.defaults[ 'com.filipenegrao.Increment.kerning_small'] = kerning_small self.kerning_txt_keys.setIntValue_(kerning_small) @objc.IBAction def setKerningBig_(self, sender): kerning_big = sender.intValue() Glyphs.defaults['com.filipenegrao.Increment.kerning_big'] = kerning_big self.kerning_txt_shift.setIntValue_(kerning_big) @objc.IBAction def applyKerning_(self, sender): switch_on = bool(sender.objectValue()) font = Glyphs.font if switch_on: Glyphs.intDefaults["GSKerningIncrementLow"] = Glyphs.defaults[ 'com.filipenegrao.Increment.kerning_small'] Glyphs.intDefaults["GSKerningIncrementHigh"] = Glyphs.defaults[ 'com.filipenegrao.Increment.kerning_big'] else: Glyphs.intDefaults["GSKerningIncrementLow"] = 1 Glyphs.intDefaults["GSKerningIncrementHigh"] = 10 # @objc.IBAction # def setMetrics_( self, sender ): # # print('Metrics') # Glyphs.defaults['com.filipenegrao.KeyboardIncrement.metrics'] = bool(sender.objectValue()) # @objc.IBAction # def setKerning_( self, sender ): # # print('Kerning') # Glyphs.defaults['com.filipenegrao.KeyboardIncrement.kerning'] = bool(sender.objectValue()) # @objc.IBAction # def setKeyboard_( self, sender ): # # print('Keyboard') # Glyphs.defaults['com.filipenegrao.KeyboardIncrement.keyboard'] = bool(sender.objectValue()) # @objc.IBAction # def applyButton_( self, sender ): # font = Glyphs.font # # get the default values # incValue = Glyphs.defaults['com.filipenegrao.KeyboardIncrement.increment'] # applyMetrics = Glyphs.defaults['com.filipenegrao.KeyboardIncrement.metrics'] # applyKerning = Glyphs.defaults['com.filipenegrao.KeyboardIncrement.kerning'] # applyKeyboard = Glyphs.defaults['com.filipenegrao.KeyboardIncrement.keyboard'] # if applyMetrics: # Glyphs.intDefaults["GSSpacingIncrementLow"] = incValue # Glyphs.intDefaults["GSSpacingIncrementLow"] = incValue * 10 # if applyKerning: # Glyphs.intDefaults["GSKerningIncrementLow"] = incValue # Glyphs.intDefaults["GSKerningIncrementHigh"] = incValue * 10 # if applyKeyboard: # font.keyboardIncrement = incValue # font.keyboardIncrementBig = incValue * 10 # @objc.IBAction # def resetButton_( self, sender ): # print('Reset Button') # @objc.python_method # def updateControls( self, sender = None, ui_field ): # # self.displayValue.setStringValue_(str(Glyphs.defaults['com.filipenegrao.KeyboardIncrement.increment'])) # self.stepper.setIntValue_(Glyphs.defaults['com.filipenegrao.KeyboardIncrement.increment']) # self.displayValue.setIntValue_(Glyphs.defaults['com.filipenegrao.KeyboardIncrement.increment']) @objc.python_method def __del__(self): Glyphs.removeCallback(self.update) @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__
class GlyphsAppSpeedPunkReporter(ReporterPlugin): settingsView = objc.IBOutlet() gainSlider = objc.IBOutlet() @objc.python_method def settings(self): self.keyboardShortcut = 'x' curveGain = speedpunk.speedpunklib.curveGain Glyphs.registerDefault('de.yanone.speedPunk.curveGain', speedpunk.speedpunklib.Interpolate(curveGain[0], curveGain[1], .2)) Glyphs.registerDefault('de_yanone.speedPunk.fader', 1.0) self.loadNib('settingsView', __file__) self.menuName = 'Speed Punk' self.speedpunklib = speedpunk.speedpunklib.SpeedPunkLib() self.speedpunklib.tool = self self.generalContextMenus = [{'name': 'Speed Punk', 'view': self.settingsView}] self.gainSlider.setMinValue_(speedpunk.speedpunklib.curveGain[0]) self.gainSlider.setMaxValue_(speedpunk.speedpunklib.curveGain[1]) self.histWidth = 200 self.histHeight = 20 default = NSUserDefaultsController.sharedUserDefaultsController() default.addObserver_forKeyPath_options_context_(self, 'values.de.yanone.speedPunk.illustrationPositionIndex', 0, None) default.addObserver_forKeyPath_options_context_(self, 'values.de.yanone.speedPunk.curveGain', 0, None) default.addObserver_forKeyPath_options_context_(self, 'values.de.yanone.speedPunk.useFader', 0, None) default.addObserver_forKeyPath_options_context_(self, 'values.de.yanone.speedPunk.fader', 0, None) @objc.python_method def conditionsAreMetForDrawing(self): """ Don't activate if text or pan (hand) tool are active. """ currentController = self.controller.view().window().windowController() if currentController: tool = currentController.toolDrawDelegate() textToolIsActive = tool.isKindOfClass_( NSClassFromString("GlyphsToolText") ) handToolIsActive = tool.isKindOfClass_( NSClassFromString("GlyphsToolHand") ) if not textToolIsActive and not handToolIsActive: return True return False def observeValueForKeyPath_ofObject_change_context_(self, keypath, observed, changed, context): self.speedpunklib.loadPreferences() Glyphs.redraw() @objc.python_method def background(self, layer): if self.conditionsAreMetForDrawing(): self.speedpunklib.UpdateGlyph(layer) def drawForegroundWithOptions_(self, options): if self.speedpunklib.getPreference('useFader'): visibleRect = self.controller.viewPort histOriginX = NSMinX(visibleRect) + 10 histOriginY = NSMaxY(visibleRect) - 10 - self.histHeight NSGraphicsContext.currentContext().saveGraphicsState() clippingPath = NSBezierPath.bezierPathWithRoundedRect_cornerRadius_(NSRect((histOriginX, histOriginY), (self.histWidth, self.histHeight)), 5) clippingPath.addClip() self.speedpunklib.drawGradient(histOriginX, histOriginY, self.histWidth, self.histHeight) self.speedpunklib.drawHistogram(histOriginX, histOriginY, self.histWidth, self.histHeight) NSGraphicsContext.currentContext().restoreGraphicsState() @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__ @objc.IBAction def visitWebsite_(self, sender): webbrowser.open_new_tab('https://github.com/yanone/speedpunk') @objc.IBAction def visitTwitter_(self, sender): webbrowser.open_new_tab('https://twitter.com/yanone')
class ____PluginClassName____(FileFormatPlugin): # Definitions of IBOutlets # The NSView object from the User Interface. Keep this here! dialog = objc.IBOutlet() # Example variables. You may delete them feedbackTextField = objc.IBOutlet() unicodeCheckBox = objc.IBOutlet() glyphWidthCheckbox = objc.IBOutlet() @objc.python_method def settings(self): self.name = Glyphs.localize({ 'en': u'My CSV Export', 'de': u'Mein CSV-Export' }) self.icon = 'ExportIcon' self.toolbarPosition = 100 # Load .nib dialog (with .extension) self.loadNib('IBdialog', __file__) @objc.python_method def start(self): # Init user preferences if not existent and set default value Glyphs.registerDefault(unicodePref, True) Glyphs.registerDefault(glyphWidthPref, True) # Set initial state of checkboxes according to user variables self.unicodeCheckBox.setState_(Glyphs.defaults[unicodePref]) self.glyphWidthCheckbox.setState_(Glyphs.defaults[glyphWidthPref]) # Update text field. You may delete them self.updateFeedBackTextField() # Example function. You may delete it @objc.IBAction def setExportUnicode_(self, sender): Glyphs.defaults[unicodePref] = bool(sender.intValue()) self.updateFeedBackTextField() # Example function. You may delete it @objc.IBAction def setExportGlyphWidth_(self, sender): Glyphs.defaults[glyphWidthPref] = bool(sender.intValue()) self.updateFeedBackTextField() # Example function. You may delete it @objc.python_method def updateFeedBackTextField(self): string = [] if Glyphs.defaults[unicodePref]: string.append('Unicodes') if Glyphs.defaults[glyphWidthPref]: string.append('Glyph Width') self.feedbackTextField.setStringValue_( ', '.join(string) if len(string) else 'Nothing') @objc.python_method def export(self, font): # Ask for export destination and write the file: title = "Choose export destination" proposedFilename = font.familyName fileTypes = ['csv'] # Call dialog filepath = GetSaveFile(title, proposedFilename, fileTypes) if filepath: import csv with open(filepath, 'w') as csvfile: fieldnames = ['glyph_name', 'unicode', 'glyph_width'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for g in font.glyphs: writeDict = {} writeDict['glyph_name'] = g.name if Glyphs.defaults[unicodePref] == True and g.unicode: writeDict['unicode'] = g.unicode if Glyphs.defaults[glyphWidthPref] == True and g.layers[ 0].width: writeDict['glyph_width'] = g.layers[0].width writer.writerow(writeDict) return (True, 'The export of "%s" was successful.' % (os.path.basename(filepath))) else: return (False, 'No file chosen') @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__
class SettingsViewController(NSWindowController): hostTextField = objc.IBOutlet() portTextField = objc.IBOutlet() usernameTextField = objc.IBOutlet() passwordTextField = objc.IBOutlet() topicTextField = objc.IBOutlet() saveButton = objc.IBOutlet() cancelButton = objc.IBOutlet() loadingIndicator = objc.IBOutlet() app = None mqtt = None config = None def init(self): logger.info("Initializing...") self = objc.super(SettingsViewController, self).initWithWindowNibName_("SettingsWindow") return self @objc.python_method def initWithApp(self, app): self = objc.super(SettingsViewController, self).initWithWindowNibName_("SettingsWindow") self.app = app self.config = app.config self.shouldCloseDocument = True return self @objc.python_method def setLoading(self, loading): if loading: self.loadingIndicator.startAnimation_(self) else: self.loadingIndicator.stopAnimation_(self) self.saveButton.setEnabled_(not loading) self.hostTextField.setEnabled_(not loading) self.portTextField.setEnabled_(not loading) self.usernameTextField.setEnabled_(not loading) self.topicTextField.setEnabled_(not loading) self.passwordTextField.setEnabled_(not loading) @objc.python_method def load_settings(self): self.hostTextField.setStringValue_(self.config.get_host() or '') self.portTextField.setIntegerValue_(self.config.get_port() or 1883) self.usernameTextField.setStringValue_(self.config.get_username() or '') self.topicTextField.setStringValue_(self.config.get_topic() or '') self.passwordTextField.setStringValue_(self.config.get_password() or '') def windowDidLoad(self): NSWindowController.windowDidLoad(self) self.load_settings() self._.window.center() self.setLoading(False) logger.info("Window did load") def windowWillClose_(self, notification): logger.info("Window will close") if self.mqtt is not None: self.mqtt.stop() self.mqtt = None self.setLoading(False) self.load_settings() def awakeFromNib(self): logger.info("Awake from nib") @objc.IBAction def onSaveSettingsClick_(self, sender): self.config.set_host(self.hostTextField.stringValue()) self.config.set_topic(self.topicTextField.stringValue()) self.config.set_username(self.usernameTextField.stringValue()) self.config.set_port(self.portTextField.integerValue()) self.config.set_password(self.passwordTextField.stringValue()) self.config.save() self.setLoading(True) self.mqtt = MqttCheckConfig.create(self.config) self.mqtt.on_connect_success = self.on_connect_success self.mqtt.on_connect_error = self.on_connect_error @objc.IBAction def onCancelClick_(self, sender): if self.mqtt is None: self._.window.performClose_(self) else: self.mqtt.stop() self.setLoading(False) self.mqtt = None @objc.python_method def on_connect_success(self): logger.info("Connection success, config success, proceed") self._.window.performClose_(self) self.app.start_mqtt() @objc.python_method def on_connect_error(self, message): Alert.show_alert('Error', message) self.setLoading(False) logger.info("Connection error: " + message)
class MyDocument(CoreData.NSPersistentDocument): outlineTreeController = objc.IBOutlet() def initWithType_error_(self, tp, error): self, error = super(MyDocument, self).initWithType_error_(tp, error) if self is None: return (None, error) managedObjectContext = self.managedObjectContext() for aPriorityValue in range(5): aPriority = CoreData.NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext_( "Priority", managedObjectContext) aPriority.setValue_forKey_(aPriorityValue + 1, "value") CoreData.NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext_( "Note", managedObjectContext) managedObjectContext.processPendingChanges() managedObjectContext.undoManager().removeAllActions() self.updateChangeCount_(Cocoa.NSChangeCleared) return (self, None) def windowNibName(self): return "MyDocument" def prioritySortDescriptions(self): return prioritySortDescriptions def createNote_(self, sender): self.outlineTreeController.add_(sender) def createChildNote_(self, sender): self.outlineTreeController.addChild_(sender) def indentNote_(self, sender): selectionPath = self.outlineTreeController.selectionIndexPath() if not selectionPath: Cocoa.NSBeep() return selection = self.outlineTreeController.selection() parentNote = selection.valueForKeyPath_("parent") if parentNote is None: children = self.outlineTreeController.content() else: children = parentNote.valueForKeyPath_("children").allObjects() children = children.sortedArrayUsingDescriptors_( self.outlineTreeController.sortDescriptors()) index = selectionPath.indexAtPosition_(selectionPath.length() - 1) if index == 0: Cocoa.NSBeep() else: sibling = children.objectAtIndex_(index - 1) selection.setValue_forKeyPath_(sibling, "parent") def dedentNote_(self, sender): selection = self.outlineTreeController.selection() parent = selection.valueForKeyPath_("parent") if parent in ( None, Cocoa.NSMultipleValuesMarker, Cocoa.NSNoSelectionMarker, Cocoa.NSNotApplicableMarker, ): Cocoa.NSBeep() return parent = parent.valueForKeyPath_("parent") selection.setValue_forKeyPath_(parent, "parent")
class PeopleDataSource(Cocoa.NSObject): _abPeople = objc.ivar() _imPersonStatus = objc.ivar() # Parallel array to abPeople _table = objc.IBOutlet() def awakeFromNib(self): self._imPersonStatus = Cocoa.NSMutableArray.alloc().init() # We don't need to query the staus of everyone, we will wait for # notifications of their status to arrive, so we just set them all up # as offline. self.setupABPeople() Cocoa.NSNotificationCenter.defaultCenter( ).addObserver_selector_name_object_( self, b'abDatabaseChangedExternallyNotification:', AddressBook.kABDatabaseChangedExternallyNotification, None) Cocoa.NSNotificationCenter.defaultCenter( ).addObserver_selector_name_object_( self, b'addressBookPersonStatusChanged:', kAddressBookPersonStatusChanged, None) Cocoa.NSNotificationCenter.defaultCenter( ).addObserver_selector_name_object_(self, b'statusImagesChanged:', kStatusImagesChanged, None) # This dumps all the status information and rebuilds the array against # the current _abPeople # Fairly expensive, so this is only done when necessary def rebuildStatusInformation(self): # Now scan through all the people, adding their status to the status # cache array for i, person in enumerate(self._abPeople): # Let's assume they're offline to start bestStatus = InstantMessage.IMPersonStatusOffline for service in InstantMessage.IMService.allServices(): screenNames = service.screenNamesForPerson_(person) for screenName in screenNames: dictionary = service.infoForScreenName_(screenName) status = dictionary.get(InstantMessage.IMPersonStatusKey) if status is not None: thisStatus = status if InstantMessage.IMComparePersonStatus( bestStatus, thisStatus) != Cocoa.NSOrderedAscending: bestStatus = thisStatus self._imPersonStatus[i] = bestStatus self._table.reloadData() # Rebuild status information for a given person, much faster than a full # rebuild def rebuildStatusInformationForPerson_(self, forPerson): for i, person in enumerate(self._abPeople): if person is forPerson: bestStatus = InstantMessage.IMPersonStatusOffline # Scan through all the services, taking the 'best' status we # can find for service in InstantMessage.IMService.allServices(): screenNames = service.screenNamesForPerson_(person) # Ask for the status on each of their screen names for screenName in screenNames: dictionary = service.infoForScreenName_(screenName) status = dictionary.get( InstantMessage.IMPersonStatusKey) if status is not None: thisStatus = status if InstantMessage.IMComparePersonStatus( bestStatus, thisStatus) != Cocoa.NSOrderedAscending: bestStatus = thisStatus self._imPersonStatus[i] = bestStatus self._table.reloadData() break # Sets up all our internal data def setupABPeople(self): # Keep around a copy of all the people in the AB now self._abPeople = AddressBook.ABAddressBook.sharedAddressBook().people( ).mutableCopy() # Sort them by display name self._abPeople.sortUsingSelector_('compareDisplayNames:') # Assume everyone is offline. self._imPersonStatus.removeAllObjects() offlineNumber = InstantMessage.IMPersonStatusOffline for i in range(len(self._abPeople)): self._imPersonStatus.append(offlineNumber) # This will do a full flush of people in our AB Cache, along with # rebuilding their status */ def reloadABPeople(self): self.setupABPeople() # Now recache all the status info, this will spawn a reload of the table self.rebuildStatusInformation() def numberOfRowsInTableView_(self, tableView): if self._abPeople is None: return 0 return len(self._abPeople) def tableView_objectValueForTableColumn_row_(self, tableView, tableColumn, row): identifier = tableColumn.identifier() if identifier == u"image": status = self._imPersonStatus[row] return Cocoa.NSImage.imageNamed_( InstantMessage.IMService.imageNameForStatus_(status)) elif identifier == u"name": return self._abPeople[row].displayName() return None # Posted from ServiceWatcher # The object of this notification is an ABPerson who's status has # Changed def addressBookPersonStatusChanged_(self, notification): self.rebuildStatusInformationForPerson_(notification.object()) # Posted from ServiceWatcher # We should reload the tableview, because the user has changed the # status images that iChat is using. def statusImagesChanged_(self, notification): self._table.reloadData() # If the AB database changes, force a reload of everyone # We could look in the notification to catch differential updates, but # for now this is fine. def abDatabaseChangedExternallyNotification_(self, notification): self.reloadABPeople()
class MyView (NSView): currentMenuItem = objc.IBOutlet() def initWithFrame_(self, frameRect): self = super(MyView, self).initWithFrame_(frameRect) if self is None: return None global _pdfDocument _pdfDocument = None return self if False: def isFlipped(self): return True def drawRect_(self, rect): context = NSGraphicsContext.currentContext().graphicsPort() if _pdfDocument is None: if _drawingCommand in (UIHandling.kHICommandDrawNSString, UIHandling.kHICommandDrawNSLayoutMgr, UIHandling.kHICommandDrawCustomNSLayoutMgr): if _drawingCommand == UIHandling.kHICommandDrawNSString: FrameworkTextDrawing.drawNSStringWithAttributes() elif _drawingCommand == UIHandling.kHICommandDrawNSLayoutMgr: FrameworkTextDrawing.drawWithNSLayout() else: FrameworkTextDrawing.drawWithCustomNSLayout() else: AppDrawing.DispatchDrawing(context, _drawingCommand) else: mediaRect = CGPDFDocumentGetMediaBox(_pdfDocument, 1) mediaRect.origin.x = mediaRect.origin.y = 0 CGContextDrawPDFDocument(context, mediaRect, _pdfDocument, 1) @objc.IBAction def setDrawCommand_(self, sender): global _drawingCommand, _pdfDocument newCommand = sender.tag() if _drawingCommand != newCommand: _drawingCommand = newCommand # The view needs to be redisplayed since there is a new drawing command. self.setNeedsDisplay_(True) # Disable previous menu item. if self.currentMenuItem is not None: self.currentMenuItem.setState_(NSOffState) # Update the current item. self.currentMenuItem = sender # Enable new menu item. self.currentMenuItem.setState_(NSOnState) # If we were showing a pasted document, let's get rid of it. if _pdfDocument: _pdfDocument = None def currentPrintableCommand(self): # The best representation for printing or exporting # when the current command caches using a bitmap context # or a layer is to not do any caching. if _drawingCommand in (UIHandling.kHICommandDrawOffScreenImage, UIHandling.kHICommandDrawWithLayer): return UIHandling.kHICommandDrawNoOffScreenImage return _drawingCommand def print_(self, sender): global _drawingCommand savedDrawingCommand = _drawingCommand # Set the drawing command to be one that is printable. _drawingCommand = self.currentPrintableCommand() # Do the printing operation on the view. NSPrintOperation.printOperationWithView_(self).runOperation() # Restore that before the printing operation. _drawingCommand = savedDrawingCommand def acceptsFirstResponder(self): return True @objc.IBAction def copy_(self, sender): addPDFDataToPasteBoard(_drawingCommand) @objc.IBAction def paste_(self, sender): global _pdfDocument newPDFDocument = createNewPDFRefFromPasteBoard() if newPDFDocument is not None: _pdfDocument = newPDFDocument # The view needs to be redisplayed since there is # a new PDF document. self.setNeedsDisplay_(True) # Return the number of pages available for printing. For this # application it is always 1. def knowsPageRange_(self): return True, NSRange(1, 1) # Return the drawing rectangle for a particular page number. # For this application it is always the page width and height. def rectForPage_(self, page): pi = NSPrintOperation.currentOperation().printInfo() # Calculate the page height in points. paperSize = pi.paperSize() return NSMakeRect(0, 0, paperSize.width, paperSize.height) def validateMenuItem_(self, menuItem): if menuItem.tag() == _drawingCommand: self.currentMenuItem = menuItem menuItem.setState_(True) else: menuItem.setState_(False) return True
class ConferenceScreenSharing(NSObject): implements(IObserver) window = objc.IBOutlet() toolbar = objc.IBOutlet() webView = objc.IBOutlet() errorText = objc.IBOutlet() fitWindowButton = objc.IBOutlet() loading = False closed_by_user = True @classmethod def createWithOwner_(cls, owner): w = ConferenceScreenSharing.alloc().initWithOwner_(owner) return w def initWithOwner_(self, owner): self = super(ConferenceScreenSharing, self).init() if self: self.owner = owner NSBundle.loadNibNamed_owner_("ConferenceScreenSharing", self) self.screensharing_fit_window = True self.screensharing_uri = None self.screensharing_url = None self.display_name = None self.webView.setShouldCloseWithWindow_(True) NotificationCenter().add_observer(self, name='SIPSessionGotConferenceInfo') return self @allocate_autorelease_pool @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPSessionGotConferenceInfo(self, notification): BlinkLogger().log_info(u"Received conference-info update in web view") screen_sharing_urls = list(unquote(user.screen_image_url.value) for user in notification.data.conference_info.users if user.screen_image_url is not None) if self.screensharing_url not in screen_sharing_urls and self.loading: BlinkLogger().log_info(u"%s stopped sharing her screen" % self.display_name) #self.stopLoading() # unfortunately stop loading does not prevent the view to refresh based on html refresh meta tag self.closed_by_user = False self.window.performClose_(None) elif self.screensharing_url in screen_sharing_urls and not self.loading: BlinkLogger().log_info(u"%s re-started sharing her screen" % self.display_name) self.startLoading() def setTitle(self): self.window.setTitle_("Shared Screen of %s <%s> %s"%(self.display_name, self.screensharing_uri, "(stopped)" if not self.loading else "")) def close_(self, sender): self.window.close() def windowWillClose_(self, notification): if self.closed_by_user: self.owner.remote_screens_closed_by_user.add(self.screensharing_uri) NotificationCenter().remove_observer(self, name='SIPSessionGotConferenceInfo') try: del self.owner.remoteScreens[self.screensharing_uri] except KeyError: pass def show(self, display_name, sip_uri, web_url): self.screensharing_uri = sip_uri self.screensharing_url = web_url self.display_name = display_name self.webView.setHidden_(False) self.errorText.setHidden_(True) self.startLoading() self.window.makeKeyAndOrderFront_(self) def startLoading(self): self.loading = True self.setTitle() delimiter = '&' if '?' in self.screensharing_url else '?' url = '%s%sfit=1' % (self.screensharing_url, delimiter) if self.screensharing_fit_window else self.screensharing_url url = NSURL.URLWithString_(url) request = NSURLRequest.requestWithURL_cachePolicy_timeoutInterval_(url, NSURLRequestReloadIgnoringLocalAndRemoteCacheData, 15) self.webView.mainFrame().loadRequest_(request) def stopLoading(self): self.loading = False self.setTitle() self.webView.mainFrame().stopLoading() @objc.IBAction def userClickedToolbarButton_(self, sender): if sender.tag() == 100: self.fitWindowButton.setState_(NSOffState if self.fitWindowButton.state() == NSOnState else NSOnState) self.fitWindowButton.setImage_(NSImage.imageNamed_('shrinktofit-pressed' if not self.screensharing_fit_window else 'shrinktofit')) self.screensharing_fit_window = False if self.screensharing_fit_window else True self.startLoading() def webView_didFailProvisionalLoadWithError_forFrame_(self, sender, error, frame): self.errorText.setStringValue_(error.localizedDescription()) self.errorText.setHidden_(False) BlinkLogger().log_error(u"Could not load web page: %s" % error) def webView_didFailLoadWithError_forFrame_(self, sender, error, frame): self.errorText.setStringValue_(error.localizedDescription()) self.errorText.setHidden_(False) BlinkLogger().log_error(u"Could not load web page: %s" % error) def webView_didFinishLoadForFrame_(self, sender, frame): self.errorText.setStringValue_('') self.errorText.setHidden_(True)