コード例 #1
0
ファイル: puddletag.py プロジェクト: RaphaelRochet/puddletag
    def closeEvent(self, e):
        preview_msg = translate('Previews',
            'Some files have uncommited previews. '
            'These changes will be lost once you exit puddletag. <br />'
            'Do you want to exit without writing those changes?<br />')
        if tagmodel.has_previews(parent=self, msg=preview_msg):
            e.ignore()
            return False
        controls = PuddleDock._controls
        for control in PuddleDock._controls.values():
            if hasattr(control, 'saveSettings'):
                try:
                    control.saveSettings(self)
                except TypeError:
                    control.saveSettings()

        cparser = PuddleConfig()
        settings = QSettings(constants.QT_CONFIG, QSettings.IniFormat)
        if self._lastdir:
            cparser.set('main', 'lastfolder', unicode(self._lastdir[0], 'utf8'))
        cparser.set("main", "maximized", self.isMaximized())
        settings.setValue('main/state', QVariant(self.saveState()))

        headstate = self._table.horizontalHeader().saveState()
        settings.setValue('table/header', QVariant(headstate))
        genres.save_genres(status['genres'])
        e.accept()
コード例 #2
0
ファイル: algwin.py プロジェクト: korala1968/tago
def loadsets():
    algos = []
    if not os.path.exists(DUPEDIR):
        os.makedirs(DUPEDIR)
        saveset(**DEFAULTSET)
    files = [os.path.join(DUPEDIR, z) for z in os.listdir(DUPEDIR)]
    sets = []

    cparser = PuddleConfig()
    for f in files:
        cparser.filename = f
        name = cparser.get('info', 'name', '')
        disp = cparser.get('info', 'disp', [])
        algos = []
        for section in cparser.sections():
            if section == 'info':
                continue
            tags = cparser.get(section, 'tags', [])
            threshold = float(cparser.get(section, 'threshold', '0.85'))
            func = cparser.get(section, 'func', '')
            matchcase = cparser.get(section, 'matchcase', True)
            maintag = cparser.get(section, 'maintag', 'artist')
            algos.append(Algo(tags, threshold, func, matchcase))
        sets.append([name, disp, algos, maintag])
    return sets
コード例 #3
0
def parse_shortcuts():
    def tr(s):
        s = s.replace('"', r'\"')
        return 'translate("Menus", "%s")' % s
        
    f = tempfile.NamedTemporaryFile('rb+')
    fn = f.name

    loadshortcuts.check_file(fn, ':/shortcuts')
    cparser = PuddleConfig(fn)

    action_strings = []
    setting = cparser.data
    for section in cparser.sections():
        if section.startswith('shortcut'):
            values = dict([(str(k), v) for k,v in  setting[section].items()])
            action_strings.append(tr(values['name']))
            if 'tooltip' in values:
                action_strings.append(tr(values['tooltip']))

    f.close()
    menus = tempfile.NamedTemporaryFile('rb+')
    fn = menus.name
    loadshortcuts.check_file(fn, ':/menus')
    cparser = PuddleConfig(fn)

    action_strings.extend(map(tr, cparser.data['menu']))
    menus.close()

    return action_strings
コード例 #4
0
    def applySettings(self, *args):
        cparser = PuddleConfig(CONFIGPATH)
        fields = self.getItems()
        cparser.set('view_all_fields', 'fields', fields)

        if state:
            show_all_fields()
コード例 #5
0
ファイル: puddletag.py プロジェクト: korala1968/tago
def connect_action_shortcuts(actions):
    cparser = PuddleConfig()
    cparser.filename = ls.menu_path
    for action in actions:
        shortcut = cparser.get('shortcuts', unicode(action.text()), '')
        if shortcut:
            action.setShortcut(shortcut)
コード例 #6
0
def parse_shortcuts():
    def tr(s):
        s = s.replace('"', r'\"')
        return 'translate("Menus", "%s")' % s

    f = tempfile.NamedTemporaryFile('rb+')
    fn = f.name

    loadshortcuts.check_file(fn, ':/shortcuts')
    cparser = PuddleConfig(fn)

    action_strings = []
    setting = cparser.data
    for section in cparser.sections():
        if section.startswith('shortcut'):
            values = dict([(str(k), v) for k, v in setting[section].items()])
            action_strings.append(tr(values['name']))
            if 'tooltip' in values:
                action_strings.append(tr(values['tooltip']))

    f.close()
    menus = tempfile.NamedTemporaryFile('rb+')
    fn = menus.name
    loadshortcuts.check_file(fn, ':/menus')
    cparser = PuddleConfig(fn)

    action_strings.extend(list(map(tr, cparser.data['menu'])))
    menus.close()

    return action_strings
コード例 #7
0
    def loadSettings(self, filename=None, actions=None):
        self._names = []
        self._hotkeys = []

        if filename is None:
            filename = os.path.join(ACTIONDIR, 'action_shortcuts')

        self._listbox.clear()
        cparser = PuddleConfig(filename)

        if actions is None:
            self._actions = load_actions()
        else:
            self._actions = actions

        from puddlestuff.puddletag import status
        if status['actions']:
            shortcuts = dict(
                (unicode(a.text()), unicode(a.shortcut().toString()))
                for a in status['actions'])
        else:
            shortcuts = {}

        for section in sorted(cparser.sections()):
            if section.startswith('Shortcut'):
                name = cparser.get(section, NAME, 'Default')
                self._names.append(name)
                filenames = cparser.get(section, FILENAMES, [])
                shortcut = shortcuts.get(name, u'')
                self.addShortcut(name, filenames, shortcut, select=False)
                self._hotkeys.append(shortcut)
コード例 #8
0
ファイル: __init__.py プロジェクト: RaphaelRochet/puddletag
    def applySettings(self, *args):
        cparser = PuddleConfig(CONFIGPATH)
        fields = self.getItems()
        cparser.set('view_all_fields', 'fields', fields)

        if state:
            show_all_fields()
コード例 #9
0
ファイル: dialogs.py プロジェクト: korala1968/tago
 def changeProfile(self, index):
     try:
         self.profile = self.profiles[index]
     except IndexError:
         return
     cparser = PuddleConfig()
     cparser.set('masstagging', 'lastindex', index)
コード例 #10
0
    def loadSettings(self):
        settings = QSettings(QT_CONFIG, QSettings.IniFormat)
        header = self.header()
        header.restoreState(settings.value('dirview/header').toByteArray())
        hide = settings.value('dirview/hide', QVariant(True)).toBool()
        self.setHeaderHidden(hide)

        if self.isVisible() == False:
            return
        
        cparser = PuddleConfig()
        d = cparser.get('main', 'lastfolder', '/')
        while not os.path.exists(d):
            d = os.path.dirname(d)
            if not d:
                return

        def expand_thread_func():
            index = self.model().index(d)
            parents = []
            while index.isValid():
                parents.append(index)
                index = index.parent()
            return parents
        
        def expandindexes(indexes):
            self.setEnabled(False)
            [self.expand(index) for index in indexes]
            self.setEnabled(True)
        
        thread = PuddleThread(expand_thread_func, self)
        thread.connect(thread, SIGNAL('threadfinished'), expandindexes)
        thread.start()
コード例 #11
0
    def loadSettings(self, filename=None, actions=None):
        self._names = []
        self._hotkeys = []

        if filename is None:
            filename = os.path.join(ACTIONDIR, 'action_shortcuts')

        self._listbox.clear()
        cparser = PuddleConfig(filename)

        if actions is None:
            self._actions = load_actions()
        else:
            self._actions = actions

        from puddlestuff.puddletag import status
        if status['actions']:
            shortcuts = dict((unicode(a.text()), unicode(a.shortcut().toString()))
                for a in status['actions'])
        else:
            shortcuts = {}

        for section in sorted(cparser.sections()):
            if section.startswith('Shortcut'):
                name = cparser.get(section, NAME, 'Default')
                self._names.append(name)
                filenames = cparser.get(section, FILENAMES, [])
                shortcut = shortcuts.get(name, u'')
                self.addShortcut(name, filenames, shortcut, select=False)
                self._hotkeys.append(shortcut)
コード例 #12
0
ファイル: puddletag.py プロジェクト: RaphaelRochet/puddletag
def connect_action_shortcuts(actions):
    cparser = PuddleConfig()
    cparser.filename = ls.menu_path
    for action in actions:
        shortcut = cparser.get('shortcuts', unicode(action.text()), '')
        if shortcut:
            action.setShortcut(shortcut)
コード例 #13
0
ファイル: config.py プロジェクト: RaphaelRochet/puddletag
def convert_mtp(filename):
        
    cparser = PuddleConfig(filename)
    info_section = 'info'
    name = cparser.get(info_section, NAME, u'')
    numsources = cparser.get(info_section, 'numsources', 0)
    album_bound = cparser.get(info_section, ALBUM_BOUND, 70) / 100.0
    track_bound = cparser.get(info_section, TRACK_BOUND, 80) / 100.0
    match_fields = cparser.get(info_section, FIELDS, ['artist', 'title'])
    pattern = cparser.get(info_section, PATTERN,
        u'%artist% - %album%/%track% - %title%')
    jfdi = cparser.get(info_section, JFDI, True)
    desc = cparser.get(info_section, DESC, u'')
    existing = cparser.get(info_section, EXISTING_ONLY, False)

    ts_profiles = []
    for num in range(numsources):
        section = 'config%s' % num
        get = lambda key, default: cparser.get(section, key, default)

        source = DummyTS()
        source.name = get('source', u'')
        fields = fields_from_text(get('fields', u''))
        no_result = get('no_match', 0)

        ts_profiles.append(TagSourceProfile(None, source, fields,
            no_result))
    
    return MassTagProfile(name, desc, match_fields, None,
            pattern, ts_profiles, album_bound, track_bound, jfdi, existing,
            u'')
コード例 #14
0
ファイル: patterncombo.py プロジェクト: korala1968/tago
 def saveSettings(self):
     patterns = [
         unicode(self.listbox.item(row).text())
         for row in xrange(self.listbox.count())
     ]
     cparser = PuddleConfig()
     cparser.setSection('editor', 'patterns', patterns)
コード例 #15
0
    def _loadSettings(self, actions):
        
        cparser = PuddleConfig(os.path.join(CONFIGDIR, 'user_shortcuts'))

        for action in actions:
            shortcut = cparser.get('shortcuts', unicode(action.text()), '')
            if shortcut:
                action.setShortcut(QKeySequence(shortcut))
コード例 #16
0
def load_patterns(filepath=None):
    settings = PuddleConfig(filepath)
    return [settings.get('editor', 'patterns',
                            ['%artist% - $num(%track%,2) - %title%',
                            '%artist% - %album% - $num(%track%,2) - %title%',
                            '%artist% - %title%', '%artist% - %album%',
                            '%artist% - Track %track%', '%artist% - %title%']),
           settings.get('editor', 'index', 0, True)]
コード例 #17
0
def load_gen_settings(setlist, extras=False):
    settings = PuddleConfig()
    settings.filename = os.path.join(settings.savedir, 'gensettings')
    ret = []
    for setting in setlist:
        desc = setting[0]
        default = setting[1]
        ret.append([desc, settings.get(desc, 'value', default)])
    return ret
コード例 #18
0
def load_gen_settings(setlist, extras=False):
    settings = PuddleConfig()
    settings.filename = os.path.join(settings.savedir, 'gensettings')
    ret = []
    for setting in setlist:
        desc = setting[0]
        default = setting[1]
        ret.append([desc, settings.get(desc, 'value', default)])
    return ret
コード例 #19
0
ファイル: example.py プロジェクト: puddletag/puddletag
 def applyPrefs(self, values):
     musicdir = values[0]
     self.musicdir = musicdir
     cparser = PuddleConfig()
     cparser.set('exampletagsource', 'musicdir', musicdir)
     self.preferences[0][2] = musicdir
     isdir = os.path.isdir
     join = os.path.join
     self._dirs = [z for z in os.listdir(musicdir) if isdir(join(musicdir, z))]
コード例 #20
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        cparser = PuddleConfig()
        get_color = lambda key, default: QColor.fromRgb(*cparser.get(
            'extendedtags', key, default, True))
        add = get_color('add', [0, 255, 0])
        edit = get_color('edit', [255, 255, 0])
        remove = get_color('remove', [255, 0, 0])

        get_color = lambda key, default: QColor.fromRgb(*cparser.get(
            'table', key, default, True))

        preview = get_color('preview_color', [192, 255, 192])
        selection_default = QPalette().color(QPalette.Mid).getRgb()[:-1]

        selection = get_color('selected_color', selection_default)

        colors = (add, edit, remove, preview, selection)

        text = translate(
            "Colour Settings",
            '<p>Below are the backgrounds used for various controls in puddletag. <br /> Double click the desired action to change its colour.</p>'
        )
        label = QLabel(text)

        self.listbox = QTableWidget(0, 1, self)
        self.listbox.setEditTriggers(QAbstractItemView.NoEditTriggers)
        header = self.listbox.horizontalHeader()
        self.listbox.setSortingEnabled(False)
        header.setVisible(True)
        header.setStretchLastSection(True)
        self.listbox.setHorizontalHeaderLabels(['Action'])
        self.listbox.setRowCount(len(colors))

        titles = [
            (translate("Colour Settings",
                       'Row selected in file-view.'), selection),
            (translate("Colour Settings",
                       'Row colour for files with previews.'), preview),
            (translate("Colour Settings",
                       'Field added in Extended Tags.'), add),
            (translate("Colour Settings",
                       'Field edited in Extended Tags.'), edit),
            (translate("Colour Settings",
                       'Field removed in Extended Tags.'), remove),
        ]

        for i, z in enumerate(titles):
            self.listbox.setItem(i, 0, StatusWidgetItem(*z))

        vbox = QVBoxLayout()
        vbox.addWidget(label)
        vbox.addWidget(self.listbox)
        self.setLayout(vbox)
        self.connect(self.listbox, SIGNAL('cellDoubleClicked(int,int)'),
                     self.edit)
コード例 #21
0
    def editSortOptions(self):
        cparser = PuddleConfig()
        options = cparser.get('table', 'sortoptions', 
            ['__filename,track,__dirpath','track, album', 
            '__filename,album,__dirpath'])

        from puddlestuff.webdb import SortOptionEditor
        win = SortOptionEditor(options, self)
        self.connect(win, SIGNAL('options'), self.applySortOptions)
        win.show()
コード例 #22
0
ファイル: tagpanel.py プロジェクト: korala1968/tago
def savesettings(d, filepath=None):
    settings = PuddleConfig()
    if filepath:
        settings.filename = filepath
    else:
        settings.filename = os.path.join(settings.savedir, 'tagpanel')
    settings.set('panel', 'numrows', unicode(len(d)))
    for row, rowtags in d.items():
        settings.set(unicode(row), 'tags', [z[1] for z in rowtags])
        settings.set(unicode(row), 'titles', [z[0] for z in rowtags])
コード例 #23
0
ファイル: example.py プロジェクト: RaphaelRochet/puddletag
 def applyPrefs(self, values):
     musicdir = values[0]
     self.musicdir = musicdir
     cparser = PuddleConfig()
     cparser.set('exampletagsource', 'musicdir', musicdir)
     self.preferences[0][2] = musicdir
     isdir = os.path.isdir
     join = os.path.join
     musicdir = musicdir.encode('utf8')
     self._dirs = [z for z in os.listdir(musicdir) if isdir(join(musicdir,z))]
コード例 #24
0
def _load(filename):
    cparser = PuddleConfig(filename)
    confirmations = {}
    for section in cparser.sections():
        if section.startswith(SECTION):
            name = cparser.get(section, NAME, u'')
            desc = cparser.get(section, DESC, u'')
            value = cparser.get(section, VALUE, True)
            confirmations[name] = [value, desc]
    return confirmations
コード例 #25
0
ファイル: algwin.py プロジェクト: RaphaelRochet/puddletag
def loadsets():
    algos = []
    if not os.path.exists(DUPEDIR):
        os.makedirs(DUPEDIR)
        saveset(**DEFAULTSET)
    files = [os.path.join(DUPEDIR, z) for z in os.listdir(DUPEDIR)]
    sets = []

    cparser = PuddleConfig()
    for f in files:
        cparser.filename = f
        name = cparser.get('info', 'name', '')
        disp = cparser.get('info', 'disp', [])
        algos = []
        for section in cparser.sections():
            if section == 'info':
                continue
            tags = cparser.get(section, 'tags', [])
            threshold = float(cparser.get(section, 'threshold', '0.85'))
            func = cparser.get(section, 'func', '')
            matchcase = cparser.get(section, 'matchcase', True)
            maintag = cparser.get(section, 'maintag', 'artist')
            algos.append(Algo(tags, threshold, func, matchcase))
        sets.append([name, disp, algos, maintag])
    return sets
コード例 #26
0
ファイル: puddletag.py プロジェクト: chincheta0815/puddletag
def create_tool_windows(parent, extra=None):
    """Creates the dock widgets for the main window (parent) using
    the modules stored in puddlestuff/mainwin.

    Returns (the toggleViewActions of the docks, the dockWidgets the
    mselves)."""
    actions = []
    docks = []
    cparser = PuddleConfig()
    cparser.filename = ls.menu_path
    widgets = (
        mainwin.tagpanel,
        mainwin.artwork,
        mainwin.dirview,
        mainwin.patterncombo,
        mainwin.filterwin,
        puddlestuff.webdb,
        mainwin.storedtags,
        mainwin.logdialog,
        puddlestuff.masstag.dialogs,
    )

    controls = [z.control for z in widgets]
    controls.extend(mainwin.action_dialogs.controls)
    if extra:
        controls.extend(extra)
    for z in controls:
        name = z[0]
        try:
            if not z[2]:
                PuddleDock._controls[name] = z[1](status=status)
                continue
        except IndexError:
            pass

        p = PuddleDock(z[0], z[1], parent, status)

        parent.addDockWidget(z[2], p)

        try:
            if z[4]:
                p.setFloating(True)
            p.move(parent.rect().center())
        except IndexError:
            pass

        p.setVisible(z[3])
        docks.append(p)
        action = p.toggleViewAction()
        action.setText(name)
        scut = cparser.get("winshortcuts", name, "")
        if scut:
            action.setShortcut(scut)
        actions.append(action)
    return actions, docks
コード例 #27
0
ファイル: patterncombo.py プロジェクト: korala1968/tago
def load_patterns(filepath=None):
    settings = PuddleConfig(filepath)
    return [
        settings.get('editor', 'patterns', [
            '%artist% - $num(%track%,2) - %title%',
            '%artist% - %album% - $num(%track%,2) - %title%',
            '%artist% - %title%', '%artist% - %album%',
            '%artist% - Track %track%', '%artist% - %title%'
        ]),
        settings.get('editor', 'index', 0, True)
    ]
コード例 #28
0
    def editSortOptions(self):
        cparser = PuddleConfig()
        options = cparser.get('table', 'sortoptions', [
            '__filename,track,__dirpath', 'track, album',
            '__filename,album,__dirpath'
        ])

        from puddlestuff.webdb import SortOptionEditor
        win = SortOptionEditor(options, self)
        self.connect(win, SIGNAL('options'), self.applySortOptions)
        win.show()
コード例 #29
0
def load_plugins(plugins=None, parent=None):
    [sys.path.insert(0, d) for d in PLUGIN_DIRS]
    cparser = PuddleConfig()
    to_load = cparser.get('plugins', 'to_load', [])
    functions = {}
    tagsources = []
    dialogs = []
    musiclibs = []
    modules = []
    functions_no_preview = []

    join = os.path.join
    if plugins is None:
        plugins = []
        [plugins.extend(get_plugins(d)) for d in PLUGIN_DIRS]

    plugins.sort(key=lambda d: d.get(NAME, u''))

    for plugin in plugins:
        if plugin[MODULE_NAME] not in to_load:
            continue
        try:
            module = __import__(plugin[MODULE_NAME])
        except:
            logging.exception(u'Failed to load plugin: ' + plugin['name'])
            continue
        if hasattr(module, 'functions'):
            functions.update(module.functions)

        if hasattr(module, 'functions_no_preview'):
            functions_no_preview.extend(module.functions_no_preview)

        if hasattr(module, 'tagsources'):
            tagsources.extend(module.tagsources)

        if hasattr(module, 'dialogs'):
            dialogs.extend(module.dialogs)

        if hasattr(module, 'musiclibs'):
            musiclibs.extend(module.musiclibs)

        modules.append(module)

    for d in PLUGIN_DIRS:
        del (sys.path[0])

    return {
        FUNCTIONS: functions,
        TAGSOURCE: tagsources,
        DIALOGS: dialogs,
        MUSICLIBS: musiclibs,
        MODULES: modules,
        FUNCTIONS_NO_PREVIEW: functions_no_preview
    }
コード例 #30
0
def save(filename=None, confirmations=None):
    if filename is None:
        filename = _filename
    cparser = PuddleConfig(filename)
    
    if confirmations is None:
        confirmations = _confirmations
    
    for i, name in enumerate(confirmations):
        set_value = lambda k,v: cparser.set(SECTION + unicode(i), k, v)
        set_value(NAME, name)
        set_value(VALUE, confirmations[name][0])
        set_value(DESC, confirmations[name][1])
コード例 #31
0
def load_plugins(plugins=None, parent=None):
    [sys.path.insert(0, d) for d in PLUGIN_DIRS]
    cparser = PuddleConfig()
    to_load = cparser.get('plugins', 'to_load', [])
    functions = {}
    tagsources = []
    dialogs = []
    musiclibs = []
    modules = []
    functions_no_preview = []
    
    join = os.path.join
    if plugins is None:
        plugins = []
        [plugins.extend(get_plugins(d)) for d in PLUGIN_DIRS]

    
    plugins.sort(key=lambda d: d.get(NAME, u''))

    for plugin in plugins:
        if plugin[MODULE_NAME] not in to_load:
            continue
        try:
            module = __import__(plugin[MODULE_NAME])
        except:
            print u'Failed to load plugin: ', plugin['name']
            traceback.print_exc()
            continue
        if hasattr(module, 'functions'):
            functions.update(module.functions)

        if hasattr(module, 'functions_no_preview'):
            functions_no_preview.extend(module.functions_no_preview)

        if hasattr(module, 'tagsources'):
            tagsources.extend(module.tagsources)

        if hasattr(module, 'dialogs'):
            dialogs.extend(module.dialogs)

        if hasattr(module, 'musiclibs'):
            musiclibs.extend(module.musiclibs)

        modules.append(module)
        
    for d in PLUGIN_DIRS:
        del(sys.path[0])

    return {FUNCTIONS: functions, TAGSOURCE: tagsources, DIALOGS: dialogs,
            MUSICLIBS: musiclibs, MODULES: modules, FUNCTIONS_NO_PREVIEW: functions_no_preview}
コード例 #32
0
 def updateOrder(self):
     self.listbox.clear()
     self.macros = self.loadMacros()
     cparser = PuddleConfig()
     to_check = cparser.get('actions', 'checked', [])
     for i, m in sorted(self.macros.items()):
         func_name = m.name
         item = QListWidgetItem(func_name)
         item.setFlags(item.flags() | Qt.ItemIsEditable)
         if func_name in to_check:
             item.setCheckState(Qt.Checked)
         else:
             item.setCheckState(Qt.Unchecked)
         self.listbox.addItem(item)
コード例 #33
0
ファイル: puddletag.py プロジェクト: korala1968/tago
def create_tool_windows(parent, extra=None):
    """Creates the dock widgets for the main window (parent) using
    the modules stored in puddlestuff/mainwin.

    Returns (the toggleViewActions of the docks, the dockWidgets the
    mselves)."""
    actions = []
    docks = []
    cparser = PuddleConfig()
    cparser.filename = ls.menu_path
    widgets = (mainwin.tagpanel, mainwin.artwork, mainwin.dirview,
               mainwin.patterncombo, mainwin.filterwin, puddlestuff.webdb,
               mainwin.storedtags, mainwin.logdialog,
               puddlestuff.masstag.dialogs)

    controls = [z.control for z in widgets]
    controls.extend(mainwin.action_dialogs.controls)
    if extra:
        controls.extend(extra)
    for z in controls:
        name = z[0]
        try:
            if not z[2]:
                PuddleDock._controls[name] = z[1](status=status)
                continue
        except IndexError:
            pass

        p = PuddleDock(z[0], z[1], parent, status)

        parent.addDockWidget(z[2], p)

        try:
            if z[4]: p.setFloating(True)
            p.move(parent.rect().center())
        except IndexError:
            pass

        p.setVisible(z[3])
        docks.append(p)
        action = p.toggleViewAction()
        action.setText(name)
        scut = cparser.get('winshortcuts', name, '')
        if scut:
            action.setShortcut(scut)
        actions.append(action)
    return actions, docks
コード例 #34
0
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        cparser = PuddleConfig()
        get_color = lambda key, default: QColor.fromRgb(
            *cparser.get('extendedtags', key, default, True))
        add = get_color('add', [0,255,0])
        edit = get_color('edit', [255,255,0])
        remove = get_color('remove', [255,0,0])

        get_color = lambda key, default: QColor.fromRgb(
            *cparser.get('table', key, default, True))

        preview = get_color('preview_color', [192, 255, 192])
        selection_default = QPalette().color(QPalette.Mid).getRgb()[:-1]
        
        selection = get_color('selected_color', selection_default)
        
        colors = (add, edit, remove, preview, selection)

        text = translate("Colour Settings", '<p>Below are the backgrounds used for various controls in puddletag. <br /> Double click the desired action to change its colour.</p>')
        label = QLabel(text)

        self.listbox = QTableWidget(0, 1, self)
        self.listbox.setEditTriggers(QAbstractItemView.NoEditTriggers)
        header = self.listbox.horizontalHeader()
        self.listbox.setSortingEnabled(False)
        header.setVisible(True)
        header.setStretchLastSection (True)
        self.listbox.setHorizontalHeaderLabels(['Action'])
        self.listbox.setRowCount(len(colors))

        titles = [
            (translate("Colour Settings", 'Row selected in file-view.'), selection),
            (translate("Colour Settings", 'Row colour for files with previews.'), preview),
            (translate("Colour Settings", 'Field added in Extended Tags.'), add),
            (translate("Colour Settings", 'Field edited in Extended Tags.'), edit),
            (translate("Colour Settings", 'Field removed in Extended Tags.'), remove),]

        for i, z in enumerate(titles):
            self.listbox.setItem(i, 0, StatusWidgetItem(*z))

        vbox = QVBoxLayout()
        vbox.addWidget(label)
        vbox.addWidget(self.listbox)
        self.setLayout(vbox)
        self.connect(self.listbox, SIGNAL('cellDoubleClicked(int,int)'), self.edit)
コード例 #35
0
ファイル: dialogs.py プロジェクト: korala1968/tago
 def loadSettings(self):
     convert_mtps(PROFILEDIR)
     if not os.path.exists(PROFILEDIR):
         os.mkdir(PROFILEDIR)
     self.setProfiles(load_all_mtps(PROFILEDIR, self.tag_sources))
     index = PuddleConfig().get('masstagging', 'lastindex', 0)
     if index < self.profileCombo.count():
         self.profileCombo.setCurrentIndex(index)
コード例 #36
0
ファイル: puddletag.py プロジェクト: korala1968/tago
    def savePlayList(self):
        tags = status['selectedfiles']
        if not tags:
            tags = status['alltags']
        settings = PuddleConfig()
        try:
            dirname = self._lastdir[0]
        except IndexError:
            dirname = constants.HOMEDIR
        filepattern = settings.get('playlist', 'filepattern', 'puddletag.m3u')
        default = encode_fn(findfunc.tagtofilename(filepattern, tags[0]))
        f = unicode(
            QFileDialog.getSaveFileName(
                self, translate("Playlist", 'Save Playlist...'),
                os.path.join(dirname, default)))
        if f:
            if settings.get('playlist', 'extinfo', 1, True):
                pattern = settings.get('playlist', 'extpattern',
                                       '%artist% - %title%')
            else:
                pattern = None

            reldir = settings.get('playlist', 'reldir', 0, True)
            windows_separator = settings.get('playlist', 'windows_separator',
                                             0, False)
            m3u.exportm3u(tags, f, pattern, reldir, windows_separator)
コード例 #37
0
def load_settings(filename=None, actions=None):
    if filename is None:
        filename = FILENAME

    if not os.path.exists(os.path.dirname(filename)):
        os.makedirs(os.path.dirname(filename))

    cparser = PuddleConfig(filename)

    actions = load_actions() if actions is None else actions

    shortcuts = []
    for section in sorted(cparser.sections()):
        if section.startswith(SHORTCUT_SECTION):
            name = cparser.get(section, NAME, 'Default')
            filenames = cparser.get(section, FILENAMES, [])
            shortcuts.append([name, filenames])
    return actions, shortcuts
コード例 #38
0
def load_settings(filename=None, actions=None):
    if filename is None:
        filename = FILENAME

    if not os.path.exists(os.path.dirname(filename)):
        os.makedirs(os.path.dirname(filename))

    cparser = PuddleConfig(filename)

    actions = load_actions() if actions is None else actions

    shortcuts = []
    for section in sorted(cparser.sections()):
        if section.startswith(SHORTCUT_SECTION):
            name = cparser.get(section, NAME, 'Default')
            filenames = cparser.get(section, FILENAMES, [])
            shortcuts.append([name, filenames])
    return actions, shortcuts
コード例 #39
0
ファイル: previews.py プロジェクト: korala1968/tago
def create_actions(parent):
    enable_preview = QAction('Enabl&e Preview Mode', parent)
    enable_preview.setShortcut('Ctrl+Shift+P')
    obj.connect(enable_preview, SIGNAL('triggered()'), toggle_preview_mode)

    clear_selection = PreviewAction('Clear Selected &Files', parent)
    clear_selection.setShortcut('Ctrl+Shift+F')
    obj.connect(clear_selection, SIGNAL('triggered()'), clear_selected)

    write = PreviewAction('&Write Previews', parent)
    write.setShortcut('Ctrl+W')

    obj.connect(write, SIGNAL('triggered()'), lambda: emit('writepreview'))

    revert = PreviewAction('&Undo Last Clear', parent)
    revert.setShortcut('Ctrl+Shift+Z')
    obj.connect(revert, SIGNAL('triggered()'), undo_last)

    sort = QAction('Sort &By', parent)
    obj.connect(sort, SIGNAL('triggered()'), sort_by_fields)

    clear_cells = PreviewAction('Clear Selected &Cells', parent)
    obj.connect(clear_cells, SIGNAL('triggered()'), clear_selected_cells)

    cparser = PuddleConfig()
    options = cparser.get('table', 'sortoptions', [
        '__filename,track,__dirpath', 'track, album',
        '__filename,album,__dirpath'
    ])
    global _sort_action
    _sort_action = sort
    sort_actions = set_sort_options(options)

    preview_actions = [clear_selection, write, revert, clear_cells]

    toggle = partial(toggle_preview_display, enable_preview, preview_actions)

    obj.receives.append(['previewModeChanged', toggle])

    [connect_shortcut(z, FILESSELECTED) for z in preview_actions]

    return [enable_preview, clear_selection, write, revert, sort, clear_cells
            ] + sort_actions
コード例 #40
0
ファイル: algwin.py プロジェクト: korala1968/tago
def saveset(setname, disp, algs, maintag):
    cparser = PuddleConfig()
    filename = os.path.join(DUPEDIR, setname)
    open(filename, 'w').close() #I have to clear the file because if a previous
                                #set had more algos then the extra algos will get loaded.
    cparser.filename = filename
    algs = [{'tags': a.tags, 'threshold': a.threshold,
            'func': a.func.__name__, 'matchcase': a.matchcase,
            'maintag': maintag} for a in algs]

    cparser.set('info', 'name', setname)
    cparser.set('info', 'disp', disp)
    for i, a in enumerate(algs):
        setname = u'alg' + unicode(i)
        for key, val in a.items():
            cparser.set(setname, key, val)
コード例 #41
0
    def __init__(self, controls, parent=None):
        QWidget.__init__(self, parent)
        settings = []
        for control in controls:
            if hasattr(control, 'gensettings'):
                settings.extend(load_gen_settings(control.gensettings, True))
        self._controls = []

        def create_control(desc, val):
            if isinstance(val, bool):
                return SettingsCheckBox(val, desc)
            elif isinstance(val, basestring):
                return SettingsLineEdit(desc, val)

        vbox = QVBoxLayout()
        for desc, val in settings:
            widget = create_control(desc, val)
            vbox.addWidget(widget)
            self._controls.append(widget)

        edit_sort_options = QPushButton(
            translate("GenSettings", '&Edit sort options'))

        self._lang_combo = QComboBox()
        self._lang_combo.addItems([
            translate('GenSettings', '<Autodetect>'),
            translate('GenSettings', 'Default')
        ])
        self._lang_combo.setCurrentIndex(0)

        lang = PuddleConfig().get('main', 'lang', u'auto')
        self._lang_combo.addItems(list(get_languages([TRANSDIR])))

        if lang != u'auto':
            i = self._lang_combo.findText(lang, Qt.MatchFixedString)
            if i > 0:
                self._lang_combo.setCurrentIndex(i)

        self.connect(edit_sort_options, SIGNAL('clicked()'),
                     self.editSortOptions)

        hbox = QHBoxLayout()
        hbox.addWidget(edit_sort_options)
        hbox.addStretch()

        vbox.addLayout(hbox)
        if self._lang_combo.count() > 2:
            vbox.addLayout(
                create_buddy(
                    translate('GenSettings', 'Language (Requires a restart)'),
                    self._lang_combo))
        else:
            self._lang_combo.setCurrentIndex(0)
        vbox.addStretch()
        self.setLayout(vbox)
コード例 #42
0
ファイル: previews.py プロジェクト: RaphaelRochet/puddletag
def create_actions(parent):
    enable_preview = QAction('Enabl&e Preview Mode', parent)
    enable_preview.setShortcut('Ctrl+Shift+P')
    obj.connect(enable_preview, SIGNAL('triggered()'), toggle_preview_mode)

    clear_selection = PreviewAction('Clear Selected &Files', parent)
    clear_selection.setShortcut('Ctrl+Shift+F')
    obj.connect(clear_selection, SIGNAL('triggered()'), clear_selected)
    
    write = PreviewAction('&Write Previews', parent)
    write.setShortcut('Ctrl+W')
    
    obj.connect(write, SIGNAL('triggered()'), lambda: emit('writepreview'))
    
    revert = PreviewAction('&Undo Last Clear', parent)
    revert.setShortcut('Ctrl+Shift+Z')
    obj.connect(revert, SIGNAL('triggered()'), undo_last)
    
    sort = QAction('Sort &By', parent)
    obj.connect(sort, SIGNAL('triggered()'), sort_by_fields)

    clear_cells = PreviewAction('Clear Selected &Cells', parent)
    obj.connect(clear_cells, SIGNAL('triggered()'), clear_selected_cells)
    
    cparser = PuddleConfig()
    options = cparser.get('table', 'sortoptions', 
        ['__filename,track,__dirpath','track, album', 
            '__filename,album,__dirpath'])
    global _sort_action
    _sort_action = sort
    sort_actions = set_sort_options(options)

    preview_actions = [clear_selection, write, revert, clear_cells]

    toggle = partial(toggle_preview_display, enable_preview, preview_actions)
    
    obj.receives.append(['previewModeChanged', toggle])

    [connect_shortcut(z, FILESSELECTED) for z in preview_actions]

    return [enable_preview, clear_selection, write, revert, sort,
        clear_cells] + sort_actions
コード例 #43
0
    def applySettings(self, control = None):
        from puddlestuff.puddletag import remove_shortcuts, add_shortcuts
        remove_shortcuts('&Actions', self._names)

        f = open(FILENAME, 'w')
        f.close()
        
        cparser = PuddleConfig(FILENAME)
        for i, item in enumerate(self._listbox.items()):
            section = SHORTCUT_SECTION + unicode(i)
            cparser.set(section, NAME, item.actionName)
            cparser.set(section, FILENAMES, item.filenames)

        from puddlestuff.mainwin.funcs import applyaction

        shortcuts = create_action_shortcuts(applyaction, control)
        for item, shortcut in zip(self._listbox.items(), shortcuts):
            if item.shortcut:
                shortcut.setShortcut(item.shortcut)
        add_shortcuts('&Actions', shortcuts, save=True)
コード例 #44
0
ファイル: funcs.py プロジェクト: korala1968/tago
def clipboard_to_tag(parent=None):
    win = helperwin.ImportTextFile(parent, clipboard=True)
    win.setModal(True)
    win.patterncombo.addItems(status['patterns'])

    cparser = PuddleConfig()
    last_dir = cparser.get('importwindow', 'lastdir', HOMEDIR)
    win.lastDir = last_dir
    last_pattern = cparser.get('importwindow', 'lastpattern', u'')
    if last_pattern:
        win.patterncombo.setEditText(last_pattern)

    def fin_edit(taglist, pattern):
        cparser.set('importwindow', 'lastdir', win.lastDir)
        cparser.set('importwindow', 'lastpattern', pattern)
        emit('writeselected', taglist)

    win.connect(win, SIGNAL("Newtags"), fin_edit)

    win.show()
コード例 #45
0
ファイル: funcs.py プロジェクト: keithgg/puddletag
def clipboard_to_tag(parent=None):
    win = helperwin.ImportTextFile(parent, clipboard = True)
    win.setModal(True)
    win.patterncombo.addItems(status['patterns'])

    cparser = PuddleConfig()
    last_dir = cparser.get('importwindow', 'lastdir', HOMEDIR)
    win.lastDir = last_dir
    last_pattern = cparser.get('importwindow', 'lastpattern', u'')
    if last_pattern:
        win.patterncombo.setEditText(last_pattern)

    def fin_edit(taglist, pattern):
        cparser.set('importwindow', 'lastdir', win.lastDir)
        cparser.set('importwindow', 'lastpattern', pattern)
        emit('writeselected', taglist)
    
    win.connect(win, SIGNAL("Newtags"), fin_edit)
    
    win.show()
コード例 #46
0
ファイル: puddletag.py プロジェクト: korala1968/tago
    def closeEvent(self, e):
        preview_msg = translate(
            'Previews', 'Some files have uncommited previews. '
            'These changes will be lost once you exit puddletag. <br />'
            'Do you want to exit without writing those changes?<br />')
        if tagmodel.has_previews(parent=self, msg=preview_msg):
            e.ignore()
            return False
        controls = PuddleDock._controls
        for control in PuddleDock._controls.values():
            if hasattr(control, 'saveSettings'):
                try:
                    control.saveSettings(self)
                except TypeError:
                    control.saveSettings()

        cparser = PuddleConfig()
        settings = QSettings(constants.QT_CONFIG, QSettings.IniFormat)
        if self._lastdir:
            cparser.set('main', 'lastfolder', unicode(self._lastdir[0],
                                                      'utf8'))
        cparser.set("main", "maximized", self.isMaximized())
        settings.setValue('main/state', QVariant(self.saveState()))

        headstate = self._table.horizontalHeader().saveState()
        settings.setValue('table/header', QVariant(headstate))
        genres.save_genres(status['genres'])
        e.accept()
コード例 #47
0
ファイル: config.py プロジェクト: RaphaelRochet/puddletag
def mtp_from_file(filename=CONFIG, tag_sources=None):

    if tag_sources is None:
        tag_sources = {}
    else:
        tag_sources = dict((z.name, z) for z in tag_sources)

    cparser = PuddleConfig(filename)
    info_section = 'info'

    name = cparser.get(info_section, NAME, '')
    numsources = cparser.get(info_section, 'numsources', 0)
    album_bound = cparser.get(info_section, ALBUM_BOUND, 70) / 100.0
    track_bound = cparser.get(info_section, TRACK_BOUND, 80) / 100.0
    match_fields = cparser.get(info_section, FIELDS, ['artist', 'title'])
    pattern = cparser.get(info_section, PATTERN,
        '%artist% - %album%/%track% - %title%')
    jfdi = cparser.get(info_section, JFDI, True)
    desc = cparser.get(info_section, DESC, u'')
    leave_existing = cparser.get(info_section, EXISTING_ONLY, False)
    regexps = u''

    ts_profiles = []
    for num in range(numsources):
        section = 'config%s' % num
        get = lambda key, default: cparser.get(section, key, default)

        source = tag_sources.get(get('source', u''), None)
        no_result = get('no_match', 0)
        fields = fields_from_text(get('fields', u''))
        replace_fields = fields_from_text(get('replace_fields', u''))

        ts_profiles.append(TagSourceProfile(None, source, fields,
            no_result, replace_fields))

    mtp = MassTagProfile(name, desc, match_fields, None,
        pattern, ts_profiles, album_bound, track_bound, jfdi,
        leave_existing, regexps)

    return mtp
コード例 #48
0
    def __init__(self, parent=None):
        super(PluginConfig, self).__init__(parent)
        winsettings('pluginconfig', self)
        self._listbox = QListWidget()
        info_display = InfoWidget()

        hbox = QHBoxLayout()
        hbox.addWidget(self._listbox, 0)
        hbox.addWidget(info_display, 1)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(
            QLabel(
                translate(
                    "Plugin Settings",
                    '<b>Loading/unloading plugins requires a restart.</b>')))
        self.setLayout(vbox)

        plugins = []
        [plugins.extend(get_plugins(d)) for d in PLUGIN_DIRS]

        cparser = PuddleConfig()
        to_load = cparser.get('plugins', 'to_load', [])
        plugins.sort(key=lambda d: d.get(NAME, u''))
        for plugin in plugins:
            item = QListWidgetItem()
            item.setText(plugin[NAME])
            if plugin[MODULE_NAME] in to_load:
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)
            item.plugin = plugin
            self._listbox.addItem(item)

        self.connect(
            self._listbox,
            SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem *)'),
            lambda item, previous: info_display.changeInfo(item.plugin))
コード例 #49
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        def inttocheck(value):
            if value:
                return Qt.Checked
            return Qt.Unchecked

        cparser = PuddleConfig()

        self.extpattern = QLineEdit()
        self.extpattern.setText(
            cparser.load('playlist', 'extpattern', '%artist% - %title%'))

        self.extinfo = QCheckBox(
            translate("Playlist Settings", '&Write extended info'), self)
        self.connect(self.extinfo, SIGNAL('stateChanged(int)'),
                     self.extpattern.setEnabled)
        self.extinfo.setCheckState(
            inttocheck(cparser.load('playlist', 'extinfo', 1, True)))
        self.extpattern.setEnabled(self.extinfo.checkState())

        self.reldir = QCheckBox(
            translate("Playlist Settings",
                      'Entries &relative to working directory'))
        self.reldir.setCheckState(
            inttocheck(cparser.load('playlist', 'reldir', 0, True)))

        self.windows_separator = QCheckBox(
            translate("Playlist Settings", 'Use windows path separator (\\)'))
        self.windows_separator.setCheckState(
            inttocheck(cparser.load('playlist', 'windows_separator', 0, True)))

        self.filename = QLineEdit()
        self.filename.setText(
            cparser.load('playlist', 'filepattern', 'puddletag.m3u'))
        label = QLabel(translate("Playlist Settings", '&Filename pattern.'))
        label.setBuddy(self.filename)

        hbox = QHBoxLayout()
        hbox.addSpacing(10)
        hbox.addWidget(self.extpattern)

        vbox = QVBoxLayout()
        [
            vbox.addWidget(z)
            for z in (self.extinfo, self.reldir, self.windows_separator, label,
                      self.filename)
        ]
        vbox.insertLayout(1, hbox)
        vbox.addStretch()
        vbox.insertSpacing(3, 5)
        vbox.insertSpacing(5, 5)
        self.setLayout(vbox)
コード例 #50
0
    def __init__(self, parent=None):
        filename = os.path.join(PuddleConfig().savedir, 'mappings')
        self._edited = deepcopy(audioinfo.mapping)
        self._mappings = audioinfo.mapping

        QWidget.__init__(self, parent)
        tooltip = translate(
            "Mapping Settings",
            '''<ul><li>Tag is the format that the mapping applies to.
            One of <b>ID3, APEv2, MP4, or VorbisComment</b>.
            </li><li>Fields will be mapped from Source to Target,
            meaning that if Source is found in a tag, it'll be
            editable in puddletag using Target.</li>
            <li>Eg. For <b>Tag=VorbisComment, Source=organization,
            and Target=publisher</b> means that writing to the publisher
            field for VorbisComments in puddletag will in actuality
            write to the organization field.</li><li>Mappings for
            tag sources are also supported, just use the name of the
            tag source as Tag, eg. <b>Tag=MusicBrainz,
            Source=artist,Target=performer</b>.</li></ul>''')

        self._table = QTableWidget()
        self._table.setToolTip(tooltip)
        self._table.setColumnCount(3)
        self._table.setHorizontalHeaderLabels([
            translate("Mapping Settings", 'Tag'),
            translate("Mapping Settings", 'Original Field'),
            translate("Mapping Settings", 'Target')
        ])
        header = self._table.horizontalHeader()
        header.setVisible(True)
        self._table.verticalHeader().setVisible(False)
        header.setStretchLastSection(True)
        buttons = ListButtons()
        buttons.connectToWidget(self)
        buttons.moveup.setVisible(False)
        buttons.movedown.setVisible(False)
        self.connect(buttons, SIGNAL('duplicate'), self.duplicate)

        hbox = QHBoxLayout()
        hbox.addWidget(self._table, 1)
        hbox.addLayout(buttons, 0)

        self._setMappings(self._mappings)
        label = QLabel(
            translate("Mapping Settings",
                      '<b>A restart is required to apply these settings.</b>'))
        vbox = QVBoxLayout()
        vbox.addLayout(hbox, 1)
        vbox.addWidget(label)
        self.setLayout(vbox)
コード例 #51
0
ファイル: algwin.py プロジェクト: RaphaelRochet/puddletag
def saveset(setname, disp, algs, maintag):
    cparser = PuddleConfig()
    filename = os.path.join(DUPEDIR, setname)
    open(filename, 'w').close() #I have to clear the file because if a previous
                                #set had more algos then the extra algos will get loaded.
    cparser.filename = filename
    algs = [{'tags': a.tags, 'threshold': a.threshold,
            'func': a.func.__name__, 'matchcase': a.matchcase,
            'maintag': maintag} for a in algs]

    cparser.set('info', 'name', setname)
    cparser.set('info', 'disp', disp)
    for i, a in enumerate(algs):
        setname = u'alg' + unicode(i)
        for key, val in a.items():
            cparser.set(setname, key, val)
コード例 #52
0
ファイル: funcs.py プロジェクト: keithgg/puddletag
def text_file_to_tag(parent=None):
    dirpath = status['selectedfiles'][0].dirpath

    win = helperwin.ImportTextFile(parent)
    cparser = PuddleConfig()
    last_dir = cparser.get('importwindow', 'lastdir', HOMEDIR)
    if win.openFile(dirpath=last_dir):
        win.close()
        return
    win.setModal(True)
    win.patterncombo.addItems(status['patterns'])

    last_pattern = cparser.get('importwindow', 'lastpattern', u'')
    if last_pattern:
        win.patterncombo.setEditText(last_pattern)

    def fin_edit(taglist, pattern):
        cparser.set('importwindow', 'lastdir', win.lastDir)
        cparser.set('importwindow', 'lastpattern', pattern)
        emit('writeselected', taglist)

    win.connect(win, SIGNAL("Newtags"), fin_edit)
    win.show()
コード例 #53
0
    def __init__(self, parent = None):
        super(PluginConfig, self).__init__(parent)
        winsettings('pluginconfig', self)
        self._listbox = QListWidget()
        info_display = InfoWidget()
        
        hbox = QHBoxLayout()
        hbox.addWidget(self._listbox, 0)
        hbox.addWidget(info_display, 1)
        
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(
            QLabel(translate("Plugin Settings",
                '<b>Loading/unloading plugins requires a restart.</b>')))
        self.setLayout(vbox)

        plugins = []
        [plugins.extend(get_plugins(d)) for d in PLUGIN_DIRS]
        
        cparser = PuddleConfig()
        to_load = cparser.get('plugins', 'to_load', [])
        plugins.sort(key=lambda d: d.get(NAME, u''))
        for plugin in plugins:
            item = QListWidgetItem()
            item.setText(plugin[NAME])
            if plugin[MODULE_NAME] in to_load:
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)
            item.plugin = plugin
            self._listbox.addItem(item)
        
        self.connect(self._listbox, 
            SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem *)'),
            lambda item, previous: info_display.changeInfo(item.plugin))
コード例 #54
0
    def applySettings(self, controls):

        cparser = PuddleConfig()
        index = self._lang_combo.currentIndex()
        if index > 1:
            cparser.set('main', 'lang', unicode(self._lang_combo.currentText()))
        elif index == 0:
            cparser.set('main', 'lang', u'auto')
        elif index == 1:
            cparser.set('main', 'lang', u'default')
        
        vals =  dict([c.settingValue for c in self._controls])
        for c in controls:
            if hasattr(c, 'applyGenSettings'):
                c.applyGenSettings(vals)
        save_gen_settings(vals)