Пример #1
0
class SimpleFontWindow(BaseWindowController):

    def __init__(self, font):

        self._font = font

        if font.path:
            document = DoodleDocument.alloc().init()
            document.setFileURL_(NSURL.fileURLWithPath_(font.path))

            dc = NSDocumentController.sharedDocumentController()
            dc.addDocument_(document)

        self._canUpdateChangeCount = True

        self.w = Window((250, 500), "SimpleFontWindow", minSize=(200, 300))

        glyphs = sorted(font.keys())

        self.w.glyphs = List((0, 0, -0, -0), glyphs,
                             doubleClickCallback=self.openGlyph)

        toolbarItems = [
            dict(itemIdentifier="spaceCenter",
                 label="Space Center",
                 imageNamed="toolbarSpaceCenterAlternate",
                 callback=self.openSpaceCenter
                 ),
            dict(itemIdentifier="fontInfo",
                 label="Font Info",
                 imageNamed="toolbarFontInfo",
                 callback=self.openFontInfo
                 )
        ]
        self.w.addToolbar(toolbarIdentifier="SimpleToolbar",
                          toolbarItems=toolbarItems)

        windowController = self.w.getNSWindowController()
        windowController.setShouldCloseDocument_(True)
        self._font.UIdocument().addWindowController_(windowController)

        self._font.addObserver(self, "fontChanged", "Font.Changed")

        self.setUpBaseWindowBehavior()
        self.w.open()

        self.openFirstGlyph()

    def openGlyph(self, sender):
        sel = sender.getSelection()
        if sel:
            i = sel[0]
            name = sender[i]
            self._canUpdateChangeCount = False
            OpenGlyphWindow(self._font[name])
            self._canUpdateChangeCount = True

    def openSpaceCenter(self, sender):
        self._canUpdateChangeCount = False
        OpenSpaceCenter(self._font)
        self._canUpdateChangeCount = True

    def openFontInfo(self, sender):
        self._canUpdateChangeCount = False
        OpenFontInfoSheet(self._font, self.w)
        self._canUpdateChangeCount = True

    # notifications
    def fontChanged(self, notification):
        if self._canUpdateChangeCount:
            self._font.UIdocument().updateChangeCount_(0)

    # to make EditThatNextMaster work as needed

    def openFirstGlyph(self):

        glyphName = "A"

        if glyphName in font.keys():
            OpenGlyphWindow(self._font[glyphName])
Пример #2
0
class Unicron(object):
    def __init__(self):
        self.locations = [
            'User Agents', 'Global Agents', 'Global Daemons', 'System Agents',
            'System Daemons'
        ]
        self.listItems = []
        self.selected = {}

        # Preferences
        self.homedir = os.path.expanduser('~')
        self.prefsFolder = self.homedir + "/Library/Preferences/"
        self.prefsFile = "de.nelsonfritsch.unicron.plist"

        if os.path.isfile(self.prefsFolder + self.prefsFile):
            self.prefs = self._loadPrefs(self)
        else:
            self.prefs = dict(showSystemWarning=True, windowStyle='System')
            self._savePrefs(self)

        # Preferences Window
        self.prefsWindow = Window((300, 105), 'Preferences')

        self.styles = ['System', 'Light', 'Dark']
        self.prefsWindow.styleTxt = TextBox((10, 10, -10, 20), "Window Style:")
        self.prefsWindow.style = PopUpButton((30, 35, -10, 20),
                                             self.styles,
                                             callback=self.prefsSetStyle)

        self.prefsWindow.restore = Button((10, 75, -10, 20),
                                          'Restore Warnings',
                                          callback=self.prefsRestoreWarnings)

        # Main Window
        minsize = 285
        self.w = Window((minsize, 400),
                        'Unicron',
                        closable=True,
                        fullSizeContentView=True,
                        titleVisible=False,
                        minSize=(minsize, minsize),
                        maxSize=(600, 1200),
                        autosaveName="UnicronMainWindow")

        self.pathList = NSPopUpButton.alloc().initWithFrame_(
            ((0, 0), (160, 20)))
        self.pathList.addItemsWithTitles_(self.locations)

        refreshIcon = NSImage.alloc().initWithSize_((32, 32))
        sourceImage = NSImage.imageNamed_(NSImageNameRefreshTemplate)

        w, h = sourceImage.size()

        if w > h:
            diffx = 0
            diffy = w - h
        else:
            diffx = h - w
            diffy = 0

        maxSize = max([w, h])
        refreshIcon.lockFocus()
        sourceImage.drawInRect_fromRect_operation_fraction_(
            NSMakeRect(diffx, diffy + 4, 22, 22),
            NSMakeRect(0, 0, maxSize, maxSize), NSCompositeSourceOver, 1)
        refreshIcon.unlockFocus()
        refreshIcon.setTemplate_(True)

        toolbarItems = [
            dict(itemIdentifier="Daemons",
                 label="Daemons",
                 toolTip="Daemon Group",
                 view=self.pathList,
                 callback=self.populateList),
            dict(itemIdentifier="image",
                 label="Image",
                 imageObject=refreshIcon,
                 callback=self.populateList),
        ]
        self.w.addToolbar("Unicron Toolbar",
                          toolbarItems=toolbarItems,
                          displayMode="icon")

        self.w.blend = Group((0, 0, 0, 0), blendingMode='behindWindow')

        self.listColumnDescriptions = [{
            'title': '',
            'key': 'image',
            'width': 25,
            'typingSensitive': True,
            'allowsSorting': True,
            'cell': ImageListCell()
        }, {
            'title': 'Name',
            'key': 'name',
            'typingSensitive': True,
            'allowsSorting': True,
        }]
        self.rowHeight = 20
        self.w.list = List((0, 37, -0, 0),
                           items=self.listItems,
                           columnDescriptions=self.listColumnDescriptions,
                           showColumnTitles=True,
                           allowsEmptySelection=True,
                           allowsMultipleSelection=False,
                           autohidesScrollers=True,
                           drawFocusRing=False,
                           rowHeight=self.rowHeight,
                           selectionCallback=self._selectionCallback,
                           menuCallback=self._menuCallback)

        self.w.list._nsObject.setBorderType_(NSNoBorder)

        self.w.statusbar = Group((0, -26, 0, 0), blendingMode='behindWindow')
        self.w.statusbar.border = HorizontalLine((0, 0, 0, 1))

        self.w.counter = TextBox((16, -20, -16, 15),
                                 '',
                                 alignment='center',
                                 sizeStyle='small')
        self.populateList(self)
        self.w.rowIndicator = Group((0, 0, 0, 10))

        self.prefsSetStyle(self)

        self.w.open()

    def prefsSetStyle(self, sender):
        style = self.prefsWindow.style.getItem()
        self._changePref(self, 'windowStyle', style)

        if style == 'System':
            style = NSUserDefaults.standardUserDefaults().stringForKey_(
                'AppleInterfaceStyle')
        if style == 'Dark':
            winAppearance = 'NSAppearanceNameVibrantDark'
        else:
            winAppearance = 'NSAppearanceNameVibrantLight'
        appearance = NSAppearance.appearanceNamed_(winAppearance)
        self.w._window.setAppearance_(appearance)
        self.prefsWindow._window.setAppearance_(appearance)

    def prefsRestoreWarnings(self, sender):
        self._changePref(self, 'showSystemWarning', True)

    def populateList(self, sender):
        self.selected.clear()
        self.w.list._removeSelection()
        item = self.pathList.titleOfSelectedItem()

        for i in range(len(self.w.list)):
            del self.w.list[0]

        thisItem = {}
        image = None
        id = os.getuid()
        systemWarning = "You should not edit or remove existing system's daemons. These jobs are required for a working macOS system."

        if item != 'Active Daemons':
            if item == 'User Agents':
                homedir = os.path.expanduser('~')
                path = homedir + '/Library/LaunchAgents'
                # If the folder doesn't exist in the user folder, create it
                try:
                    os.listdir(path)
                except:
                    os.mkdir(path)
            elif item == 'Global Agents':
                path = '/Library/LaunchAgents'
            elif item == 'Global Daemons':
                path = '/Library/LaunchDaemons'
            elif item == 'System Agents':
                path = '/System/Library/LaunchAgents'
                self._warning(self, systemWarning, "showSystemWarning")
            elif item == 'System Daemons':
                path = '/System/Library/LaunchDaemons'
                self._warning(self, systemWarning, "showSystemWarning")

            items = []
            files = os.listdir(path)
            count = 0

            for file in files:
                if file.endswith('.plist'):
                    file = file.replace('.plist', '')
                    try:
                        pid = launchd.LaunchdJob(file).pid
                    except:
                        pid = False
                    if launchd.LaunchdJob(file).exists() and pid != None:
                        image = NSImage.imageNamed_(NSImageNameStatusAvailable)
                    elif launchd.LaunchdJob(file).exists() and pid == None:
                        image = NSImage.imageNamed_(
                            NSImageNameStatusPartiallyAvailable)
                    else:
                        image = NSImage.imageNamed_(NSImageNameStatusNone)
                    state = True
                    thisItem['image'] = image
                    thisItem['name'] = file
                    self.w.list.append(thisItem)
                    count += 1
            self.w.counter.set(str(count) + ' Jobs')

    def _showInFinder(self, sender):
        file = self.selected['file']
        subprocess.call(['open', '-R', '%s' % file],
                        cwd='/',
                        shell=False,
                        universal_newlines=False)

    def _loadUnloadDaemon(self, sender, command):
        self.w.list.scrollToSelection()
        name = self.selected['name']
        path = self.selected['file']

        if bool(launchd.LaunchdJob(name).exists()):
            try:
                subprocess.call(
                    ['launchctl', 'unload', '%s' % path],
                    cwd='/',
                    shell=False,
                    universal_newlines=False)
            except:
                return
        else:
            try:
                subprocess.call(
                    ['launchctl', 'load', '%s' % path],
                    cwd='/',
                    shell=False,
                    universal_newlines=False)
            except:
                return

        self.populateList(self)

    def _removeDaemon(self, sender):
        self._loadUnloadDaemon(self, 'unload')
        self._loadUnloadDaemon(self, 'remove')

    # def addGroup(self, sender, key, value):

    def _selectionCallback(self, sender):
        try:
            if not self.w.list.getSelection():
                # Application did not finish loading yet
                pass
            else:
                # Get job name
                self.selected.clear()
                job = sender.get()[self.w.list.getSelection()[0]]
                self.selected['name'] = job['name']
                self.valueGroups = []
                # Get job path and file location
                item = self.pathList.titleOfSelectedItem()

                if 'User' in item:
                    import getpass
                    username = getpass.getuser()
                    user = username
                    path = '/Users/%s/Library/Launch' % username
                elif 'Global' in item:
                    user = '******'
                    path = '/Library/Launch'
                elif 'System' in item:
                    user = '******'
                    path = '/System/Library/Launch'
                if 'Agents' in item:
                    path += 'Agents/'
                else:
                    path += 'Daemons/'

                self.selected['path'] = path
                self.selected['file'] = str(self.selected['path'].replace(
                    ' ', '\ ')) + job['name'].replace(' ', '\ ') + '.plist'
                f = open(self.selected['file'], "r")
                self.selected['raw'] = str(f.read())
                self.selected['short'] = (
                    self.selected['name'][:32] + '…') if len(
                        self.selected['name']) > 32 else self.selected['name']
                # Get status
                if job['image'] == NSImage.imageNamed_(NSImageNameStatusNone):
                    status = None
                else:
                    status = 'Available'
                self.selected['status'] = status

                index = sender.getSelection()[0]
                relativeRect = sender.getNSTableView().rectOfRow_(index)

                self.pop = Popover((300, 100))

                self.pop.tabs = Tabs((20, 40, -20, -20),
                                     ["Editor", "Raw View"])
                self.pop.tabs._nsObject.setTabViewType_(NSNoTabsNoBorder)

                self.pop.tabBtn = SegmentedButton(
                    (10, 10, -10, 20),
                    [dict(title="Editor"),
                     dict(title="Raw View")],
                    callback=self._segmentPressed,
                    selectionStyle='one')
                self.pop.tabBtn.set(0)

                self.edit = self.pop.tabs[0]

                self.rawEdit = self.pop.tabs[1]
                self.rawEdit.editor = TextEditor((0, 0, -0, -45),
                                                 text=self.selected['raw'])

                self.selected['dict'] = launchd.plist.read(
                    self.selected['name'])

                # TODO: Add stackview to scrollview as group
                # Waiting for merge into master: https://github.com/robotools/vanilla/issues/132
                self.edit.stack = VerticalStackGroup((0, 0, -0, -45))

                for idx, (key, value) in enumerate(
                        sorted(self.selected['dict'].items())):
                    group = ValueGroup((0, 0, -0, -0),
                                       sender=self,
                                       key=key,
                                       value=value,
                                       idx=idx)
                    self.valueGroups.append(group)
                    self.edit.stack.addView(
                        self.valueGroups[idx], 300,
                        self.valueGroups[idx].getPosSize()[3])

                self.pop.save = Button((20, -50, -20, 40),
                                       "Save",
                                       callback=self._savePlist)
                self.pop.save.enable(False)
                self.pop.open(parentView=sender.getNSTableView(),
                              preferredEdge='right',
                              relativeRect=relativeRect)
        except:
            pass

    # TODO
    def _savePlist(self, sender):
        return

    def _segmentPressed(self, sender):
        self.pop.tabs.set(self.pop.tabBtn.get())

    def _menuCallback(self, sender):
        items = []

        items.append(dict(title=self.selected['short'], enabled=False))
        items.append("----")
        if self.selected['status'] == None:
            load, able = 'Load', 'Enable'
        else:
            load, able = 'Unload', 'Disable'

        loadCallback = partial(self._loadUnloadDaemon, command=load)
        ableCallback = partial(self._loadUnloadDaemon, command=able)
        items.append(dict(title=load, callback=loadCallback))
        items.append(dict(title=able, callback=ableCallback))
        items.append(dict(title="Show in Finder", callback=self._showInFinder))
        items.append(dict(title="Refresh list", callback=self.populateList))

        return items

    def _loadPrefs(self, sender):
        with open(self.prefsFolder + self.prefsFile, 'rb') as fp:
            self.prefs = plistlib.load(fp)
        return self.prefs

    def _savePrefs(self, sender):
        with open(self.prefsFolder + self.prefsFile, 'wb') as fp:
            plistlib.dump(self.prefs, fp)

    def _changePref(self, sender, key, value):
        self.prefs[key] = value
        self._savePrefs(self)

    def _warning(self, sender, warning, prefKey):
        if self.prefs.get(prefKey):
            self.warning = Sheet((400, 140), self.w)
            self.warning.img = ImageView((10, 10, 60, 60))
            self.warning.img.setImage(imageNamed=NSImageNameCaution)
            self.warning.txt = TextBox((70, 10, -10, -40),
                                       "Warning\n" + warning)

            callback = partial(self._changePref,
                               key=prefKey,
                               value=not self.prefs.get(prefKey))
            self.warning.check = CheckBox((70, 80, -10, 20),
                                          "Always show this warning",
                                          value=self.prefs.get(prefKey),
                                          callback=callback)

            self.warning.closeButton = Button((10, 110, -10, 20),
                                              "I understand",
                                              callback=self._closeWarning)
            self.warning.setDefaultButton(self.warning.closeButton)
            self.warning.center()
            self.w.list.enable(False)
            self.warning.open()

    def _closeWarning(self, sender):
        self.warning.close()
        self.w.list.enable(True)
        del self.warning
Пример #3
0
class ValueGroup(Group):
    nsViewClass = NSView
    nsVisualEffectViewClass = NSVisualEffectView

    def __init__(self,
                 posSize,
                 sender=None,
                 blenderMode=None,
                 key=None,
                 value=None,
                 idx=0):
        super().__init__(posSize)
        self._setupView(self.nsViewClass, posSize)
        self.sender, self.key, self.value, self.idx = sender, key, value, idx

        if self.idx > 0:
            self.separator = HorizontalLine((0, 0, -0, 1))

        self.help = HelpButton((0, 10, 21, 20), callback=self._helpCallback)
        try:
            docstring[self.key]
        except:
            self.help.enable(False)

        description = TextBox((60, 10, -0, 20), str(self.key))

        if isinstance(value, dict):
            self.description = description
            # TODO: Recursive evaluation of nested dicts
            pass

        elif isinstance(self.value, str) or (isinstance(value, int)
                                             and not isinstance(value, bool)):
            self.description = description
            self.edit = EditText((10, 40, -0, 20),
                                 text=self.value,
                                 callback=self._dummyCallback)
            self.resize(self.getPosSize()[2], 80)

        elif isinstance(self.value, bool):
            self.check = CheckBox((60, 10, -0, 20),
                                  key,
                                  callback=self._dummyCallback,
                                  value=self.value)
            self.resize(self.getPosSize()[2], 40)

        elif isinstance(self.value, list):
            values = self.getValues(self.value)

            self.description = description
            self.list = List((10, 40, -0, 80),
                             items=self.value,
                             columnDescriptions=None,
                             showColumnTitles=False,
                             allowsEmptySelection=False,
                             allowsMultipleSelection=False,
                             autohidesScrollers=True,
                             drawFocusRing=False)
            self.list._nsObject.setBorderType_(NSNoBorder)
            self.resize(self.getPosSize()[2], 120)

    def _dummyCallback(self, sender):
        pass

    def run_command(self, sender, command):
        if self.fw:
            self.fw.close()

        p = subprocess.Popen(command,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)
        return iter(p.stdout.readline, b'')

    def getValues(self, name):
        try:
            lambda v: True if 'values' in sorted(docstring[name].keys()
                                                 ) else False
            if v:
                return docstring[name]['values']
        except:
            return

    def getContent(self, name):
        output = docstring[name]['description']

        if 'values' in docstring[name]:
            output += "\n\n\nValues:"
            for value in docstring[name]['values']:
                output += "\n\n" + value + ":\n" + docstring[name]['values'][
                    value]['description']

        return output

    def _helpCallback(self, sender):

        self.w = Window((300, 300),
                        "Help",
                        closable=True,
                        fullSizeContentView=True,
                        titleVisible=False,
                        minSize=(300, 300),
                        maxSize=(600, 800))

        self.topics = []
        for key in docstring.keys():
            self.topics.append(key)

        self.pathList = NSPopUpButton.alloc().initWithFrame_(
            ((0, 0), (160, 20)))
        self.pathList.addItemsWithTitles_(self.topics)

        toolbarItems = [
            dict(itemIdentifier="Help",
                 label="Help",
                 toolTip="Topic",
                 view=self.pathList,
                 callback=self._getTopic),
        ]
        self.w.addToolbar("Help Toolbar",
                          toolbarItems=toolbarItems,
                          displayMode="icon")

        output = self.getContent(self.key)
        self.w.helptext = TextEditor((10, 47, -10, -10),
                                     text=output,
                                     readOnly=True)
        self.w.helptext._nsObject.setBorderType_(NSNoBorder)
        self.w.helptext.getNSTextView().setDrawsBackground_(False)
        self.w.helptext.getNSScrollView().setDrawsBackground_(False)

        self.w.open()

    def _getTopic(self, sender):
        selected = self.pathList.titleOfSelectedItem()
        selected = self.getContent(selected)
        self.w.helptext.set(selected)