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")
Example #2
0
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
Example #3
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])
Example #4
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))
Example #5
0
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
Example #6
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()
Example #7
0
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
Example #8
0
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__
Example #9
0
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 )
Example #10
0
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)
Example #11
0
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()
Example #14
0
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)
Example #15
0
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)
Example #16
0
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()
Example #17
0
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)
Example #18
0
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
Example #21
0
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__
Example #22
0
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,
        )
Example #23
0
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__
Example #24
0
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')
Example #25
0
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__
Example #26
0
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)
Example #27
0
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")
Example #28
0
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()
Example #29
0
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
Example #30
0
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)