Esempio n. 1
0
    def show(self, text_or_file='', font=None, timeout=None):
        '''Show alert message iff not suppressed.

           @param text_or_file: The contents (C{str} or C{file}).
           @keyword font: Optional font (L{Font}), default C{Fonts.MonoSpace}.
           @keyword timeout: Optional time limit (C{float}).

           @return: The button clicked (C{PanelButton.Close}) or
                    C{PanelButton.TimedOut} if the I{timeout} expired.

           @raise ValueError: No I{text_or_file} given.
        '''
        ns = NSAlert.alloc().init()
        ns.setAlertStyle_(AlertStyle.Info)
        ns.addButtonWithTitle_(release(NSStr('Close')))

        if not text_or_file:
            raise ValueError('no %s: %r' % ('text_or_file', text_or_file))

        text, t = _text_title2(text_or_file, self.title)
        if t:
            ns.setMessageText_(release(NSStr(t)))

        t = nsTextView(
            text,
            NSFont.userFixedPitchFontOfSize_(0) if font is None else font.NS)
        ns.setAccessoryView_(t)
        r = _runModal(ns, timeout)
        ns.release()
        return r
Esempio n. 2
0
 def _release(self):
     # release all NSStr-s and NS-s
     while self._rows:
         for s in (self._rows.pop() or ()):
             if isinstance(s, NSStr) and s is not _NS.BlankCell:
                 release(s)
     self.NSdelegate.release()
     self.NS.release()
def nsTextView(text, ns_font):
    '''Return an C{NSTextView} for the given text string.
    '''
    # <https://Developer.Apple.com/documentation/appkit/
    #        nsalert/1530575-accessoryview>
    w, h, n = nsTextSize3(text, ns_font=ns_font)
    if n > 50:
        r = NSRect4_t(0, 0, max(300, w), min(800, h))
    else:  # make sure the frame is tall enough to avoid overwritten text
        r = NSRect4_t(0, 0, 300, max(20, min(800, h)))

    # XXX key NSFontAttributeName has a NSString value, no longer a Font?
    # d = NSDictionary.dictionaryWithObject_forKey_(ns_font, NSStr('NSFontAttributeName'))
    # t = NSAttributedString.alloc().initWithString_attributes_(NSStr(text), d)
    ns = NSTextView.alloc().initWithFrame_(r)
    ns.setFont_(ns_font)  # XXX set font BEFORE text
    ns.insertText_(release(NSStr(text)))
    ns.setEditable_(NO)
    ns.setDrawsBackground_(NO)
    if n > 50:  # force scroll view
        ns.setVerticallyResizable_(YES)
        ns.setHorizontallyResizable_(YES)

        r.size.width = min(600, r.size.width)
        sv = NSScrollView.alloc().initWithFrame_(r)
        sv.setHasVerticalScroller_(YES)
        sv.setHasHorizontalScroller_(YES)
        sv.setAutohidesScrollers_(YES)
        sv.setBorderType_(2)  # Border.Bezel or NSBezelBorder
        sv.setDocumentView_(ns)
        ns = sv
    else:
        ns.sizeToFit()
    return ns
Esempio n. 4
0
    def __init__(self, text_or_file, font=None, title='Text', fraction=0.5, **kwds):
        '''Create a L{TextWindow}.

           @param text_or_file: The contents (C{str} or C{file}).
           @keyword font: Optional font (L{Font}), default C{Fonts.MonoSpace}.
           @keyword title: Window name or title (C{str}).
           @keyword fraction: Window size as fraction of the screen (C{float}).
           @keyword kwds: Optional, additional keyword arguments, see L{Window}.
        '''
        text, t = _text_title2(text_or_file, title)
        super(TextWindow, self).__init__(title=t, fraction=fraction, **kwds)

        if font is None:
            f = NSFont.userFixedPitchFontOfSize_(12)
        else:
            f = font.NS
        w, _, _ = nsTextSize3(text, f)
        # <https://Developer.Apple.com/library/content/documentation/
        #        Cocoa/Conceptual/TextUILayer/Tasks/CreateTextViewProg.html>
        # <https://Developer.Apple.com/library/content/documentation/
        #        Cocoa/Conceptual/TextUILayer/Tasks/TextInScrollView.html>
        ns = self.NS
        cf = ns.contentView().frame()
        hs = w > cf.size.width

        sv = NSScrollView.alloc().initWithFrame_(cf)
        sv.setBorderType_(Border.No)
        if hs:
            sv.setHasHorizontalScroller_(YES)
            sv.setAutoresizingMask_(AutoResize.Sizable)
        else:
            sv.setHasHorizontalScroller_(NO)
            sv.setAutoresizingMask_(AutoResize.WidthSizable)
        sv.setHasVerticalScroller_(YES)

        tv = NSTextView.alloc().initWithFrame_(cf)
        tv.setMaxSize_(NSSize_t(NSIntegerMax, NSIntegerMax))
        tv.setMinSize_(NSSize_t(16, cf.size.height))
        tc = tv.textContainer()
        if hs:
            tv.setHorizontallyResizable_(YES)
            tv.setAutoresizingMask_(AutoResize.Sizable)
            tc.setContainerSize_(NSSize_t(NSIntegerMax, NSIntegerMax))  # FLT_MAX
            tc.setWidthTracksTextView_(NO)  # YES?
        else:
            tv.setHorizontallyResizable_(NO)
            tv.setAutoresizingMask_(AutoResize.WidthSizable)
            tc.setContainerSize_(NSSize_t(cf.size.width, NSIntegerMax))  # FLT_MAX
            tc.setWidthTracksTextView_(YES)  # NO?
        tv.setVerticallyResizable_(YES)

        tv.setFont_(f)  # XXX set font BEFORE text
        tv.insertText_(release(NSStr(text)))
        tv.setEditable_(NO)
        tv.setDrawsBackground_(NO)

        self.NSView = sv  # == ns.setContentView_(sv)
        self.PMview = tv  # XXX or sv?
        ns.makeKeyAndOrderFront_(None)
        ns.makeFirstResponder_(tv)
Esempio n. 5
0
def app_title(title):
    '''Get/set the app title.

       @param title: New title (C{str}).

       @return: Previous title (C{str}).
    '''
    return nsBundleRename(release(NSStr(title)))
Esempio n. 6
0
 def title(self, title):
     '''Set the title.
     '''
     if isinstance(title, NSStr):
         try:
             self.NS.setTitle_(title)
         except AttributeError:  # no NSApplication.setTitle_
             pass
         title = nsString2str(title)
     else:
         try:
             t = NSStr(title)
             self.NS.setTitle_(t)
             release(t)
         except AttributeError:  # no NSApplication.setTitle_
             t.release()
     self._title = bytes2str(title)
Esempio n. 7
0
    def size2(self, bstr):
        '''Get the size of a string.

           @param bstr: The string (C{str}, C{bytes} or L{Str}).

           @return: 2-Tuple (width, height) in (C{float} or C{int}).
        '''
        if isinstance(bstr, Str):
            ns = bstr.NS
        elif isinstance(bstr, _ByteStrs):
            ns = release(NSStr(bstr))
        elif isinstanceOf(bstr, NSStr, name='bstr'):
            ns = bstr
        return flint(self.NS.widthOfString_(ns)), self.height
Esempio n. 8
0
 def tableView_objectValueForTableColumn_row_(self, table, col, row):
     # table is the NSTableView created above,
     # row is the row number, but col is an
     # NSTableColumn instance, not an index
     # (and col.identifier must be an NSStr).
     try:
         r = self.rows[row]
         if r in (None, ()):
             # XXX reduce the height of row separator?
             # <https://Developer.Apple.com/library/content/samplecode/
             #        CocoaTipsAndTricks/Listings/TableViewVariableRowHeights_
             #        TableViewVariableRowHeightsAppDelegate_m.html>
             return _NS.BlankCell
         c = self.id2i[col.identifier()]
         # **) return an NSStr, always
         return r[c] if 0 <= c < len(r) else _NS.EmptyCell
     except (IndexError, KeyError):  # TypeError, ValueError
         c = col.identifier()
     return release(NSStr('[C%r, R%s]' % (c, row)))
Esempio n. 9
0
def url2NS(py, url2=None):
    '''Create an C{NSURL} instance from a Python string.

       @param py: The URL (C{str} or C{unicode}).
       @keyword url2: Optionally, relative to this URL (C{str} or C{unicode}).

       @return: The ObjC instance (C{NSURL}).

       @see: U{URL<https://Developer.Apple.com/documentation/foundation/url>}
             for parsing an C{NSURL}.
    '''
    ns = release(NSStr(py))
    if ':' in bytes2str(py):
        if url2:
            return NSURL.alloc().initWithString_relativeToURL_(ns, url2NS(url2))
        else:
            return NSURL.alloc().initWithString_(ns)
    elif url2:
        return NSURL.alloc().initFileURLWithPath_relativeToURL_(ns, url2NS(url2))
    else:
        return NSURL.alloc().initFileURLWithPath_(ns)
def nsTextSize3(text, ns_font=None):
    '''Return the size of a multi-line text.

       @param text: The text (C{str}), including C{linesep}arators.
       @keyword ns_font: The text font (C{NSFont}) or C{None}.

       @return: 3-Tuple (width, height, lines) in (pixels, pixels) or
                in (characters, lines, lines) if I{ns_font} is C{None}.
    '''
    w = ''
    for t in text.split(linesep):
        if len(t) > len(w):
            w = t

    h = n = text.count(linesep) + 1
    if ns_font:
        h *= NSMain.LayoutManager.defaultLineHeightForFont_(ns_font)
        w = ns_font.widthOfString_(release(NSStr(w)))
    else:
        w = len(w)
    return w, h, n
def isAlias(path):
    '''Resolve a macOS file or folder alias.

       @param path: The alias name (C{str} or L{NSStr}).

       @return: The alias' target (C{str}) or C{None} if I{path}
                isn't a macOS alias.

       @see: U{mac-alias<https://GitHub.com/al45tair/mac_alias>} and
             U{here<https://StackOverflow.com/questions/21150169>}.
    '''
    if isinstance(path, _ByteStrs):
        path = release(NSStr(path))
    elif isinstanceOf(path, NSStr, name='path'):
        pass

    u = NSURL.alloc().initFileURLWithPath_(path)
    r = cfURLResolveAlias(u)  # URL_t
    u.release()
    if r:
        u = ObjCInstance(r)  # URL_t to NSURL
        r = cfString2str(u.path())
        u.release()
    return r
Esempio n. 12
0
    def display(self, title, width=400, height=300):
        '''Show the table in a scrollable window.

           @param title: Window title (C{str}).
           @keyword width: Window frame width (C{int} or C{float}).
           @keyword height: Window frame height (C{int} or C{float}).

           @return: The window (L{TableWindow}).

           @raise ValueError: Invalid header column ":width", font
                              ":trait" or text ":alignment".
        '''
        f = Rect4(0, 0, width, height)
        v = NSTableView.alloc().initWithFrame_(f.NS)

        cols = []
        high = 0
        id2i = {}  # map col.identifier to col number
        wide = f.width  # == v.frame().size.width
        # <https://Developer.Apple.com/documentation/appkit/nstablecolumn>
        for i, h in enumerate(self._headers):
            # note, the identifier MUST be an NSStr (to avoid warnings)
            t = retain(NSStr(str(i)))
            c = NSTableColumn.alloc().initWithIdentifier_(t)
            # simply map col.identifier to I{int}, instead of frequent,
            # costly int(nsString2str(col.identifier())) conversions in
            # _NSTableViewDelegate.tableView_objectValueForTableColumn_row_
            id2i[c.identifier()] = i
            # <https://Developer.Apple.com/documentation/appkit/nscell>
            h = _format(h, c)
            cols.append(h)
            c.setTitle_(release(
                NSStr(h)))  # == c.headerCell().setStringValue_(NSStr(h))
            # <https://Developer.Apple.com/documentation/uikit/nstextalignment>
            v.addTableColumn_(c)
            # increase row height 1-2 points to show (bold) descenders
            high = max(high, Font(c.dataCell().font()).height + 2)
            wide -= c.width()

        if wide > 0:  # stretch last col to frame edge
            c.setWidth_(float(wide + c.width()))
        if high > v.rowHeight():  # adjust the row height
            v.setRowHeight_(high)

        # <https://Developer.Apple.com/library/content/documentation/
        #        Cocoa/Conceptual/TableView/VisualAttributes/VisualAttributes.html>
        v.setGridStyleMask_(NSTableViewSolidHorizontalGridLineMask
                            | NSTableViewSolidVerticalGridLineMask)
        #       v.setDrawsGrid_(YES)  # XXX obsolete, not needed

        d = NSTableViewDelegate.alloc().init(cols, self._rows, id2i)
        v.setDelegate_(d)
        v.setDataSource_(d)
        #       v.setEditing_(NSMain.NO_false)  # NO
        v.reloadData()

        self.NS = retain(v)
        self.NSdelegate = retain(d)

        self._window = w = TableWindow(title, self)
        # v.setDelegate_(w.delegate)
        return w
Esempio n. 13
0
 def label(self, label):
     '''Set the badge text of the app's dock tile (C{str}).
     '''
     self._label = bytes2str(label)
     self.NS.setBadgeLabel_(release(NSStr(label)))
     self.NS.display()
Esempio n. 14
0
    def __init__(self, family_or_font, size=0, traits=0, weight=5):
        '''New L{Font}.

           @param family_or_font: Generic font name (C{str}, L{Str}, L{NSStr})
                                  like "Times" or "Helvetica" or a L{Font},
                                  C{NSFont} or C{NSFontDescriptor} instance.
           @keyword size: Desired point size (C{int}), zero for any.
           @keyword traits: Desired font traits (C{str} or C{FontTrait}C{s mask}).
           @keyword weigth: Desired book weight (C{int}) in range 0..15, where
                            0=light, 5=regular, 9=bold and 15=heavy.

           @raise FontError: No such I{family_or_font}.

           @raise FontTraitError: Mutually exclusive I{traits}.

           @raise TypeError: Invalid I{family_or_font}.

           @raise ValueError: Invalid I{weight}.

           @note: The new L{Font} may not exhibit the desired I{traits}
                  and I{weight}.  The I{weight} is ignored if I{traits}
                  include C{FontTrait.Bold}, both I{traits} and I{weight}
                  are ignored if I{family_or_font} is C{NSFontDescriptor}.

           @see: Function L{fontsof} to obtain all available fonts of
                 a particular font family.
        '''
        if isinstance(family_or_font, Str):
            ns, py = family_or_font.NS, str(family_or_font)
        elif isinstance(family_or_font, _ByteStrs):
            ns, py = release(NSStr(family_or_font)), bytes2str(family_or_font)
        elif isinstance(family_or_font, NSStr):
            ns, py = family_or_font, nsString2str(family_or_font)
#       elif isObjCInstanceOf(family_or_font, NSFontDescriptor):
# <https://Developer.Apple.com/documentation/appkit/nsfont/1525386-init>
# ignore traits and weight
#           ns, py = NSFont.alloc().init_(family_or_font, size), None
        elif isObjCInstanceOf(family_or_font, NSFont, name='family_or_font'):
            ns, py = family_or_font, None
            if size == 0:
                size = ns.pointSize()
            if traits == 0:
                traits = NSMain.FontManager.traitsOfFont_(ns)
            if not (size == ns.pointSize()
                    and traits == NSMain.FontManager.traitsOfFont_(ns)):
                ns = ns.familyName()
                py = nsString2str(ns)

        if py is not None:
            # <https://Developer.Apple.com/documentation/appkit/
            #        nsfontmanager/1462332-fontwithfamily>
            self._traits = _traitsin(traits)
            self._weight = _weightin(weight)
            ns = NSMain.FontManager.fontWithFamily_traits_weight_size_(
                ns, self._traits, self._weight, size)
            if isNone(ns):
                self._family = py
                self._size = flint(size)
                raise FontError('no such %s: %s' % ('font', self._argstr()))

        self._NS = ns  # _RO
        # <https://Developer.Apple.com/library/content/documentation/
        #  TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html>
        self._family = nsString2str(ns.familyName())
        self._height = flint(
            NSMain.LayoutManager.defaultLineHeightForFont_(ns) + 1)
        self._name = nsString2str(ns.fontName())
        self._size = flint(ns.pointSize())
        # traits not always reflect actual traits
        self._traits = NSMain.FontManager.traitsOfFont_(ns) or 0
        # update with the family traits, if any
        self._traits |= _traitsin(self._family, raiser=False)
        if ns.isFixedPitch() and not self.isMonoSpace:
            self._traits |= FontTrait.MonoSpace
        self._weight = NSMain.FontManager.weightOfFont_(ns)
Esempio n. 15
0
    def show(self, text='', font=None, timeout=None):
        '''Show alert message iff not suppressed.

           @keyword text: Optional, accessory text (C{str}).
           @keyword font: Optional font (L{Font}), default C{Fonts.System}.
           @keyword timeout: Optional time limit (C{float}).

           @return: The button clicked (C{PanelButton}).  If
                    C{PanelButton.Suppressed} is returned, the
                    alert panel was not shown since it was suppressed
                    due to a previous selection of the corresponding
                    check box.  C{PanelButton.TimedOut} is returned
                    if no button was clicked before the I{timeout}
                    expired.
        '''
        # <https://Developer.Apple.com/documentation/appkit/nsalert>
        ns = NSAlert.alloc().init()
        ns.setAlertStyle_(self._style)
        ns.setMessageText_(release(NSStr(self.title)))

        if self._info:
            # <https://Developer.Apple.com/library/content/documentation/
            #        Cocoa/Conceptual/Strings/Articles/stringsParagraphBreaks.html>
            ns.setInformativeText_(NSStr(self._info))

        ns.addButtonWithTitle_(release(NSStr(self._ok)))
        if self._cancel:
            ns.addButtonWithTitle_(release(NSStr(self._cancel)))
            if self._other:
                ns.addButtonWithTitle_(release(NSStr(self._other)))

        if self._suppress in (False, YES):
            self._suppress = False
            ns.setShowsSuppressionButton_(YES)
            s = _AlertStyleStr.get(self._style, '')
            s = 'Do not show this %sAlert again' % (s, )
            ns.suppressionButton().setTitle_(release(NSStr(s)))

        # <https://Developer.Apple.com/library/content/documentation/
        #        Cocoa/Conceptual/Dialog/Tasks/DisplayAlertHelp.html>
        # ns.showsHelp_(YES)
        # ns.helpAnchor_(HTML?)

        if text:
            t = nsTextView(
                text,
                NSFont.systemFontOfSize_(0) if font is None else font.NS)
            ns.setAccessoryView_(t)

        # <https://Developer.Apple.com/documentation/appkit/
        #        nsalert/1535196-showssuppressionbutton>
        if self._suppress is None:
            r = _runModal(ns, timeout)
        elif self._suppress is False:
            s = ns.suppressionButton().state()
            r = _runModal(ns, timeout)
            # XXX value of NSOnState?
            if ns.suppressionButton().state() != s:
                self._suppress = True
        else:
            r = PanelButton.Suppressed

        # ns.release()  # XXX may crash
        return r
Esempio n. 16
0
    def pick(self,
             filetypes,
             aliases=False,
             dirs=False,
             files=True,
             hidden=False,
             hidexts=False,
             multiple=False,
             packages=False,
             prompt='',
             otherOK=False,
             dflt=None):
        '''Select a file from the panel.

           @param filetypes: The selectable file types (tuple of str-s).
           @keyword aliases: Allow selection of aliases (C{bool}).
           @keyword dirs: Allow selection of directories (C{bool}).
           @keyword hidden: Allow selection of hidden files (C{bool}).
           @keyword hidexts: Hide file extensions (C{bool}).
           @keyword multiple: Allow selection of multiple files (C{bool}).
           @keyword packages: Treat file packages as directories (C{bool}).
           @keyword prompt: The button label (C{str}), default "Open".
           @keyword otherOK: Allow selection of other file types (C{bool}).
           @keyword dflt: Return value, if cancelled, nothing selected (C{None}).

           @return: The selected file name path (C{str}) or I{dflt}.
        '''
        if multiple:  # setAllowsMultipleSelection_
            raise NotImplementedError('multiple %s' % (multiple, ))

        ns = NSOpenPanel.openPanel()
        #       ns.setTitleHidden_(NO)  # "does nothing now"

        ns.setResolvesAliases_(YES if aliases else NO)
        ns.setCanChooseDirectories_(YES if dirs else NO)
        ns.setCanChooseFiles_(YES if files else NO)
        ns.setShowsHiddenFiles_(YES if hidden else NO)
        # ns.setCanSelectHiddenExtension_(YES if hidden else NO)
        ns.setExtensionHidden_(YES if hidexts else NO)

        # ns.setRequiredFileType_(NSStr)
        if filetypes:  # an NSArray of file extension NSStr[ing]s without the '.'
            ns.setAllowedFileTypes_(py2NS(t.lstrip('.') for t in filetypes))

        ns.setAllowsOtherFileTypes_(YES if otherOK else NO)
        ns.setTreatsFilePackagesAsDirectories_(YES if packages else NO)

        if prompt:
            ns.setPrompt_(release(NSStr(prompt)))

        while True:
            # ns.orderFrontRegardless()  # only flashes
            # <https://Developer.Apple.com/documentation/
            #        appkit/nssavepanel/1525357-runmodal>
            if ns.runModal() == NSCancelButton:  # runModalForTypes_
                path = dflt  # nothing selected
                break


#           paths = ns.filenames()  # returns an NSArray
#           urls = ns.URLs()  # returns an NSArray
            path = nsString2str(ns.filename())  # == ns.URL().path()
            # mimick NSOpenPanel.setAllowedFileTypes_
            if path.lower().endswith(filetypes):
                break
        # ns.release()  # XXX crashes Cancel pick
        return path
Esempio n. 17
0
    def save_as(
            self,
            name='',
            filetype='',  # PYCHOK expected
            dir='',
            hidden=False,
            hidexts=False,
            label='',
            packages=False,
            prompt='',
            tags=(),
            dflt=None):
        '''Specify a file name in the panel.

           @keyword name: A suggested file name (C{str}), default "Untitled".
           @keyword filetype: The file type (C{str}).
           @keyword dir: The directory (C{str}).
           @keyword hidden: Show hidden files (C{bool}).
           @keyword hidexts: Hide file extensions (C{bool}).
           @keyword label: The name label (C{str}), default "Save As:".
           @keyword packages: Treat file packages as directories (C{bool}).
           @keyword prompt: The button label (C{str}), default "Save".
           @keyword tags: Suggested tag names (C{tuple} of C{str}-s).
           @keyword dflt: Return value, cancelled (C{None}).

           @return: The specified file name path (C{str}) or I{dflt}.
        '''
        ns = NSSavePanel.savePanel()
        #       ns.setTitleHidden_(bool(False))  # "does nothing now"

        if name:
            ns.setNameFieldStringValue_(release(NSStr(name)))

        if dir:
            if dir.lower().startswith('file:///'):
                ns.setDirectoryURL_(release(NSStr(dir)))
            else:
                ns.setDirectory_(release(NSStr(dir)))

        if filetype:
            ns.setRequiredFileType_(release(NSStr(filetype.lstrip('.'))))
            hidexts = False

        ns.setShowsHiddenFiles_(YES if hidden else NO)
        # ns.setCanSelectHiddenExtension_(bool(hidden))
        ns.setExtensionHidden_(YES if hidexts else NO)

        if label:
            ns.setNameFieldLabel_(release(NSStr(label)))

        ns.setTreatsFilePackagesAsDirectories_(YES if packages else NO)

        if prompt:
            ns.setPrompt_(release(NSStr(prompt)))

        if tags:
            ns.setTagNames_(py2NS(tags))
            ns.setShowsTagField_(True)
        else:
            ns.setShowsTagField_(False)

        while True:
            r = _runModal(ns)  # == runModalForDirectory_file_(None, None)
            if r == NSOKButton:
                r = nsString2str(ns.filename())  # == ns.URL().path()
                break
            elif r == NSCancelButton:
                r = dflt
                break
        # ns.release()  # XXX may crash on Cancel
        return r