def __init__(self,parent=None):
        super(QtReduceFontComboBox,self).__init__()
        fdb = QFontDatabase()
        l = []
        self.fontDict = {}
        for fam in fdb.families(QFontDatabase.Latin):
            for sty in fdb.styles(fam):
                if not fam in l and fdb.isFixedPitch(fam,sty) \
                and not fdb.bold(fam,sty) and not fdb.italic(fam,sty) \
                and self.__osxHack(fam):
                    fontLogger.debug("family=%s, style=%s, isFixedPitch=%s" %
                                     (fam, sty, fdb.isFixedPitch(fam,sty)))
                    sizes = fdb.smoothSizes(fam,sty)
                    if sizes:
                        font = fdb.font(fam,sty,sizes[0])
                        if not font.exactMatch():
                            fontLogger.debug("no exactMatch for  %s %s %s" %
                                             (fam,sty,sizes[0]))

                        l += [fam]
                        self.fontDict.update({str(fam):font})
        l.sort
        self.addItems(l)
        self.currentIndexChanged.connect(self.currentIndexChangedHandler)
Exemplo n.º 2
0
class StylesheetManager(object):
    """
    The StylesheetManager reads and parses stylesheet data, plus does some basic sass 
    substitution via external config files.

    :param QtGui.QWidget parent: parent UI.
    :param str style: default style name.
    :param list paths: additional search paths.
    """
    def __init__(self, parent=None, style='default', paths=[]):
        from PySide.QtGui import QFontDatabase

        self._ui = parent  # parent UI
        self._style = style  # style to parse
        self._font_db = QFontDatabase()  # font database
        self._fonts = dict()  # dictionary of valid font types (ui, mono)

        self._config_paths = ()  # paths for cfg mods
        self._config_files = dict()  # cfg files

        self._qss_paths = ()  # qss file paths
        self._qss_files = dict()  # qss files
        self._initialized = False

        # debugging data
        self._data = dict()

        if not self._initialized:
            self.run(paths=paths)

    def run(self, paths=[]):
        """
        Read all of the currently defined config files/stylesheets.

        :param str style: style name to parse.
        :param list paths: additional search paths.
        """
        self._fonts = self.initializeFontsList()

        self._config_paths = self._get_config_paths(paths=paths)
        self._config_files = self._get_config_files(self._config_paths)
        self._qss_paths = self._get_qss_paths(paths=paths)
        self._qss_files = self._get_qss_files(self._qss_paths)

        # set parent defaults if not already set
        defaults = self.font_defaults()
        for default in defaults.keys():
            if hasattr(self._ui, default):
                if getattr(self._ui, default) is None:
                    value = defaults.get(default)
                    #print '# DEBUG: setting UI default; "%s", "%s"' % (default, value)
                    setattr(self._ui, default, value)

        self._initialized = True

    @property
    def style(self):
        return self._style

    def style_data(self, **kwargs):
        """
        Return the stylesheet data.

        :returns: parsed stylesheet data.
        :rtype: str
        """
        stylesheet_name = kwargs.pop('stylesheet_name', 'default')
        palette_style = kwargs.pop('palette_style', 'default')
        font_style = kwargs.pop('font_style', 'default')

        self._data = dict()
        parser = StyleParser(self,
                             style=stylesheet_name,
                             palette_style=palette_style,
                             font_style=font_style)
        parser.run(style=stylesheet_name,
                   palette_style=palette_style,
                   font_style=font_style)
        data = parser.data(**kwargs)

        # grab data here for debugging
        self._data = parser._data
        return data

    @property
    def config_names(self):
        """
        Returns a list of config file names.

        :returns: list of config names.
        :rtype: list
        """
        return self._config_files.keys()

    def config_files(self, style='default'):
        """
        Returns a dictionary of config files for the given style.

        :param str style: style name to return.

        :returns: font/palette config files.
        :rtype: dict
        """
        return self._config_files.get(style, {})

    @property
    def qss_names(self):
        """
        Returns a list of stylesheet file names.

        :returns: list of stylesheet names.
        :rtype: list
        """
        return self._qss_files.keys()

    @property
    def palette_styles(self):
        """
        Returns a list of palette style names.

        :returns: list of palette names.
        :rtype: list
        """
        styles = []
        for style_name, files in self._config_files.iteritems():
            if 'palette' in files:
                value = files.get('palette', None)
                if value is not None:
                    if os.path.exists(value):
                        styles.append(style_name)
        return styles

    @property
    def font_styles(self):
        """
        Returns a list of font style names.

        :returns: list of font style names.
        :rtype: list
        """
        styles = []
        for style_name, files in self._config_files.iteritems():
            if 'fonts' in files:
                value = files.get('fonts', None)
                if value is not None:
                    if os.path.exists(value):
                        styles.append(style_name)
        return styles

    @property
    def qss_files(self):
        return self._qss_files.values()

    def _get_config_paths(self, paths=[]):
        """
        Read configs from config paths.

        :param list paths: list of paths to add to the scan.

        :returns: array of search paths.
        :rtype: tuple
        """
        if paths and type(paths) in [str, unicode]:
            paths = [
                paths,
            ]

        cfg_paths = ()
        cfg_paths = cfg_paths + (options.SCENEGRAPH_CONFIG_PATH, )

        # read external paths
        if 'SCENEGRAPH_CONFIG_PATH' in os.environ:
            spaths = os.getenv('SCENEGRAPH_CONFIG_PATH').split(':')
            if paths:
                for p in paths:
                    if p not in spaths:
                        spaths.append(p)

            for path in spaths:
                if path not in cfg_paths:
                    if not os.path.exists(path):
                        log.warning(
                            'config path "%s" does not exist, skipping.' %
                            path)
                        continue
                    log.debug('reading config external path: "%s".' % path)
                    cfg_paths = cfg_paths + (path, )

        return cfg_paths

    def _get_qss_paths(self, paths=[]):
        """
        Read stylesheets from config paths.

        :param list paths: list of paths to add to the scan.

        :returns: array of search paths.
        :rtype: tuple
        """
        if paths and type(paths) in [str, unicode]:
            paths = [
                paths,
            ]

        qss_paths = ()
        qss_paths = qss_paths + (options.SCENEGRAPH_STYLESHEET_PATH, )

        # read external paths
        if 'SCENEGRAPH_STYLESHEET_PATH' in os.environ:
            qpaths = os.getenv('SCENEGRAPH_STYLESHEET_PATH').split(':')
            if paths:
                for p in paths:
                    if p not in qpaths:
                        qpaths.append(p)

            for path in qpaths:
                if path not in qss_paths:
                    if not os.path.exists(path):
                        log.warning(
                            'stylesheet path "%s" does not exist, skipping.' %
                            path)
                        continue
                    log.debug('reading external stylesheet path: "%s".' % path)
                    qss_paths = qss_paths + (path, )

        return qss_paths

    def _get_config_files(self, paths=[]):
        """
        Get config files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of config names/filenames.
        :rtype: dict
        """
        cfg_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.ini', '.cfg']:
                    cfg_file = os.path.join(path, fn)

                    names = bn.split('-')
                    if len(names) < 2:
                        log.warning('improperly named config file: "%s"' %
                                    cfg_file)
                        continue

                    style_name, cfg_type = names
                    if style_name not in cfg_files:
                        cfg_files[style_name] = dict(fonts=None, palette=None)

                    log.debug('adding %s config "%s" from "%s".' %
                              (cfg_type, style_name, cfg_file))
                    cfg_files[style_name][cfg_type] = cfg_file
        return cfg_files

    def _get_qss_files(self, paths=[]):
        """
        Get qss files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of stylesheet names/filenames.
        :rtype: dict
        """
        qss_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.qss', '.css']:
                    qss_file = os.path.join(path, fn)
                    if qss_file not in qss_files.values():
                        style_name = self._parse_stylesheet_name(qss_file)
                        if style_name is None:
                            log.warning('cannot parse style name from "%s".' %
                                        qss_file)
                            style_name = 'no-style'

                        log.debug('adding stylesheet "%s" from "%s".' %
                                  (style_name, qss_file))

                        if style_name not in qss_files:
                            qss_files[style_name] = qss_file
        return qss_files

    def _parse_stylesheet_name(self, filename):
        """
        Parse the stylesheet name from a file.

        :param str: filename to read.

        :returns: style name.
        :rtype: str
        """
        style_name = None
        if os.path.exists(filename):
            for line in open(filename, 'r'):
                line = line.rstrip('\n')
                rline = line.lstrip(' ')
                rline = rline.rstrip()
                smatch = re.search(regex.get('style_name'), rline)
                if smatch:
                    style_name = smatch.group('style')
                    break
        return style_name

    def add_config(self, filename, name=None):
        """
        Add a config to the config files attribute.

        :param str filename: filename to read.
        :param str name: name of the config.
        """
        if filename in self._config_files.values():
            for cfg_name, cfg_file in self._config_files.iteritems():
                if cfg_file == filename:
                    if name != cfg_name:
                        self._config_files.pop(cfg_name)
        self._config_files[name] = filename

    #- Fonts -----
    def initializeFontsList(self, valid=[]):
        """
        Builds the manager fonts list.

        :param list valid: list of valid font names.

        :returns: dictionary of fonts.
        :rtype: dict
        """
        if not valid:
            valid = [
                x for fontlist in options.SCENEGRAPH_VALID_FONTS.values()
                for x in fontlist
            ]

        result = dict(ui=[], mono=[])
        for font_name in self._font_db.families():
            if font_name in valid:
                if not self._font_db.isFixedPitch(font_name):
                    result['ui'].append(font_name)
                else:
                    result['mono'].append(font_name)
        return result

    def buildUIFontList(self, valid=[]):
        """
        Returns a list of monospace fonts.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('ui')

        families = []
        for font_name in self._fonts.get('ui'):
            if font_name in valid:
                families.append(font_name)
        return families

    def buildMonospaceFontList(self, valid=[]):
        """
        Returns a list of monospace fonts.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('mono')

        families = []
        for font_name in self._fonts.get('mono'):
            if font_name in valid:
                families.append(font_name)
        return families

    def buildNodesFontList(self, valid=[]):
        """
        Returns a list of fonts for node display.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('nodes')

        families = []
        all_fonts = [x for fontlist in self._fonts.values() for x in fontlist]
        for font_name in all_fonts:
            if font_name in valid:
                families.append(font_name)
        return families

    def font_defaults(self, platform=None, style='default'):
        """
        Builds a dictionary of font & size defaults by platform.

        :param str platform: os type

        :returns: font and font size defaults dictionary.
        :rtype: dict
        """
        if platform is None:
            platform = options.PLATFORM

        defaults = dict()

        def_font_config = self.config_files(style).get('fonts', None)
        if not os.path.exists(def_font_config):
            log.error('config "%s" does not exist.' % def_font_config)
            return defaults

        parser = StyleParser(self)
        data = parser._parse_configs(def_font_config)
        data = parser._parse_platform_data(data)

        # substitute attribute names
        for attr, val in data.iteritems():
            attr = re.sub('-', '_', attr)
            defaults[attr] = val
        return defaults
Exemplo n.º 3
0
class StylesheetManager(object):
    """
    The StylesheetManager reads and parses stylesheet data, plus does some basic sass 
    substitution via external config files.

    :param QtGui.QWidget parent: parent UI.
    :param str style: default style name.
    :param list paths: additional search paths.
    """
    def __init__(self, parent=None, style='default', paths=[]):
        from PySide.QtGui import QFontDatabase

        self._ui            = parent                    # parent UI
        self._style         = style                     # style to parse
        self._font_db       = QFontDatabase()           # font database
        self._fonts         = dict()                    # dictionary of valid font types (ui, mono)

        self._config_paths  = ()                        # paths for cfg mods
        self._config_files  = dict()                    # cfg files

        self._qss_paths     = ()                        # qss file paths
        self._qss_files     = dict()                    # qss files
        self._initialized   = False

        # debugging data
        self._data          = dict()

        if not self._initialized:
            self.run(paths=paths)

    def run(self, paths=[]):
        """
        Read all of the currently defined config files/stylesheets.

        :param str style: style name to parse.
        :param list paths: additional search paths.
        """
        self._fonts = self.initializeFontsList()

        self._config_paths = self._get_config_paths(paths=paths)
        self._config_files = self._get_config_files(self._config_paths)
        self._qss_paths = self._get_qss_paths(paths=paths)
        self._qss_files = self._get_qss_files(self._qss_paths)

        # set parent defaults if not already set
        defaults = self.font_defaults()
        for default in defaults.keys():
            if hasattr(self._ui, default):
                if getattr(self._ui, default) is None:
                    value = defaults.get(default)
                    #print '# DEBUG: setting UI default; "%s", "%s"' % (default, value)
                    setattr(self._ui, default, value)

        self._initialized = True

    @property
    def style(self):
        return self._style

    def style_data(self, **kwargs):
        """
        Return the stylesheet data.

        :returns: parsed stylesheet data.
        :rtype: str
        """
        stylesheet_name = kwargs.pop('stylesheet_name', 'default')
        palette_style = kwargs.pop('palette_style', 'default')
        font_style = kwargs.pop('font_style', 'default')
        
        self._data = dict()
        parser = StyleParser(self, style=stylesheet_name, palette_style=palette_style, font_style=font_style)
        parser.run(style=stylesheet_name, palette_style=palette_style, font_style=font_style)
        data = parser.data(**kwargs)

        # grab data here for debugging
        self._data = parser._data
        return data

    @property
    def config_names(self):
        """
        Returns a list of config file names.

        :returns: list of config names.
        :rtype: list
        """
        return self._config_files.keys()    

    def config_files(self, style='default'):
        """
        Returns a dictionary of config files for the given style.

        :param str style: style name to return.

        :returns: font/palette config files.
        :rtype: dict
        """
        return self._config_files.get(style, {})

    @property
    def qss_names(self):
        """
        Returns a list of stylesheet file names.

        :returns: list of stylesheet names.
        :rtype: list
        """
        return self._qss_files.keys()    

    @property
    def palette_styles(self):
        """
        Returns a list of palette style names.

        :returns: list of palette names.
        :rtype: list
        """
        styles = []
        for style_name, files in self._config_files.iteritems():
            if 'palette' in files:
                value = files.get('palette', None)
                if value is not None:
                    if os.path.exists(value):
                        styles.append(style_name)
        return styles

    @property
    def font_styles(self):
        """
        Returns a list of font style names.

        :returns: list of font style names.
        :rtype: list
        """
        styles = []
        for style_name, files in self._config_files.iteritems():
            if 'fonts' in files:
                value = files.get('fonts', None)
                if value is not None:
                    if os.path.exists(value):
                        styles.append(style_name)
        return styles

    @property
    def qss_files(self):
        return self._qss_files.values() 

    def _get_config_paths(self, paths=[]):
        """
        Read configs from config paths.

        :param list paths: list of paths to add to the scan.

        :returns: array of search paths.
        :rtype: tuple
        """
        if paths and type(paths) in [str, unicode]:
            paths = [paths,]

        cfg_paths = ()
        cfg_paths = cfg_paths + (options.SCENEGRAPH_CONFIG_PATH,)

        # read external paths
        if 'SCENEGRAPH_CONFIG_PATH' in os.environ:
            spaths = os.getenv('SCENEGRAPH_CONFIG_PATH').split(':')
            if paths:
                for p in paths:
                    if p not in spaths:
                        spaths.append(p)

            for path in spaths:
                if path not in cfg_paths:
                    if not os.path.exists(path):
                        log.warning('config path "%s" does not exist, skipping.' % path)
                        continue
                    log.debug('reading config external path: "%s".' % path)
                    cfg_paths = cfg_paths + (path,)

        return cfg_paths

    def _get_qss_paths(self, paths=[]):
        """
        Read stylesheets from config paths.

        :param list paths: list of paths to add to the scan.

        :returns: array of search paths.
        :rtype: tuple
        """
        if paths and type(paths) in [str, unicode]:
            paths = [paths,]

        qss_paths = ()
        qss_paths = qss_paths + (options.SCENEGRAPH_STYLESHEET_PATH,)

        # read external paths
        if 'SCENEGRAPH_STYLESHEET_PATH' in os.environ:
            qpaths = os.getenv('SCENEGRAPH_STYLESHEET_PATH').split(':')
            if paths:
                for p in paths:
                    if p not in qpaths:
                        qpaths.append(p)

            for path in qpaths:
                if path not in qss_paths:
                    if not os.path.exists(path):
                        log.warning('stylesheet path "%s" does not exist, skipping.' % path)
                        continue
                    log.debug('reading external stylesheet path: "%s".' % path)
                    qss_paths = qss_paths + (path,)

        return qss_paths

    def _get_config_files(self, paths=[]):
        """
        Get config files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of config names/filenames.
        :rtype: dict
        """
        cfg_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.ini', '.cfg']:
                    cfg_file = os.path.join(path, fn)

                    names = bn.split('-')
                    if len(names) < 2:
                        log.warning('improperly named config file: "%s"' % cfg_file)
                        continue

                    style_name, cfg_type = names
                    if style_name not in cfg_files:
                        cfg_files[style_name] = dict(fonts=None, palette=None)

                    log.debug('adding %s config "%s" from "%s".' % (cfg_type, style_name, cfg_file))
                    cfg_files[style_name][cfg_type] = cfg_file
        return cfg_files

    def _get_qss_files(self, paths=[]):
        """
        Get qss files.

        :param list path: ist of paths to add to the scan.

        :returns: dictionary of stylesheet names/filenames.
        :rtype: dict
        """
        qss_files = dict()
        if not paths:
            return []

        for path in paths:
            for fn in os.listdir(path):
                bn, fext = os.path.splitext(fn)
                if fext.lower() in ['.qss', '.css']:
                    qss_file = os.path.join(path, fn)
                    if qss_file not in qss_files.values():
                        style_name = self._parse_stylesheet_name(qss_file)
                        if style_name is None:
                            log.warning('cannot parse style name from "%s".' % qss_file)
                            style_name = 'no-style'

                        log.debug('adding stylesheet "%s" from "%s".' % (style_name, qss_file))

                        if style_name not in qss_files:
                            qss_files[style_name] = qss_file
        return qss_files

    def _parse_stylesheet_name(self, filename):
        """
        Parse the stylesheet name from a file.

        :param str: filename to read.

        :returns: style name.
        :rtype: str
        """
        style_name = None
        if os.path.exists(filename):
            for line in open(filename,'r'):
                line = line.rstrip('\n')
                rline = line.lstrip(' ')
                rline = rline.rstrip()
                smatch = re.search(regex.get('style_name'), rline)
                if smatch:
                    style_name = smatch.group('style')
                    break
        return style_name

    def add_config(self, filename, name=None):
        """
        Add a config to the config files attribute.

        :param str filename: filename to read.
        :param str name: name of the config.
        """
        if filename in self._config_files.values():
            for cfg_name, cfg_file in self._config_files.iteritems():
                if cfg_file == filename:
                    if name != cfg_name:
                        self._config_files.pop(cfg_name)
        self._config_files[name] = filename

    #- Fonts -----
    def initializeFontsList(self, valid=[]):
        """
        Builds the manager fonts list.

        :param list valid: list of valid font names.

        :returns: dictionary of fonts.
        :rtype: dict
        """
        if not valid:
            valid = [x for fontlist in options.SCENEGRAPH_VALID_FONTS.values() for x in fontlist]

        result = dict(ui=[], mono=[])
        for font_name in self._font_db.families():
            if font_name in valid:
                if not self._font_db.isFixedPitch(font_name):                
                    result['ui'].append(font_name)
                else:
                    result['mono'].append(font_name)
        return result

    def buildUIFontList(self, valid=[]):
        """
        Returns a list of monospace fonts.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('ui')

        families = []
        for font_name in self._fonts.get('ui'):
            if font_name in valid:
                families.append(font_name)
        return families

    def buildMonospaceFontList(self, valid=[]):
        """
        Returns a list of monospace fonts.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('mono')

        families = []
        for font_name in self._fonts.get('mono'):
            if font_name in valid:
                families.append(font_name)
        return families

    def buildNodesFontList(self, valid=[]):
        """
        Returns a list of fonts for node display.
        """
        if not valid:
            valid = options.SCENEGRAPH_VALID_FONTS.get('nodes')

        families = []
        all_fonts = [x for fontlist in self._fonts.values() for x in fontlist]
        for font_name in all_fonts:
            if font_name in valid:
                families.append(font_name)
        return families

    def font_defaults(self, platform=None, style='default'):
        """
        Builds a dictionary of font & size defaults by platform.

        :param str platform: os type

        :returns: font and font size defaults dictionary.
        :rtype: dict
        """
        if platform is None:
            platform = options.PLATFORM

        defaults = dict()

        def_font_config = self.config_files(style).get('fonts', None)
        if not os.path.exists(def_font_config):
            log.error('config "%s" does not exist.' % def_font_config)
            return defaults

        parser = StyleParser(self)
        data = parser._parse_configs(def_font_config)
        data = parser._parse_platform_data(data)

        # substitute attribute names
        for attr, val in data.iteritems():
            attr = re.sub('-', '_', attr)
            defaults[attr] = val
        return defaults