Beispiel #1
0
class EditRules(QWidget):  # {{{

    changed = pyqtSignal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.enabled = c = QCheckBox(self)
        l.addWidget(c, l.rowCount(), 0, 1, 2)
        c.setVisible(False)
        c.stateChanged.connect(self.changed)

        self.l1 = l1 = QLabel('')
        l1.setWordWrap(True)
        l.addWidget(l1, l.rowCount(), 0, 1, 2)

        self.add_button = QPushButton(QIcon(I('plus.png')), _('&Add rule'),
                self)
        self.remove_button = QPushButton(QIcon(I('minus.png')),
                _('&Remove rule(s)'), self)
        self.add_button.clicked.connect(self.add_rule)
        self.remove_button.clicked.connect(self.remove_rule)
        l.addWidget(self.add_button, l.rowCount(), 0)
        l.addWidget(self.remove_button, l.rowCount() - 1, 1)

        self.g = g = QGridLayout()
        self.rules_view = QListView(self)
        self.rules_view.doubleClicked.connect(self.edit_rule)
        self.rules_view.setSelectionMode(self.rules_view.ExtendedSelection)
        self.rules_view.setAlternatingRowColors(True)
        self.rtfd = RichTextDelegate(parent=self.rules_view, max_width=400)
        self.rules_view.setItemDelegate(self.rtfd)
        g.addWidget(self.rules_view, 0, 0, 2, 1)

        self.up_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        b.setToolTip(_('Move the selected rule up'))
        b.clicked.connect(self.move_up)
        g.addWidget(b, 0, 1, 1, 1, Qt.AlignTop)
        self.down_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        b.setToolTip(_('Move the selected rule down'))
        b.clicked.connect(self.move_down)
        g.addWidget(b, 1, 1, 1, 1, Qt.AlignBottom)

        l.addLayout(g, l.rowCount(), 0, 1, 2)
        l.setRowStretch(l.rowCount() - 1, 10)

        self.add_advanced_button = b = QPushButton(QIcon(I('plus.png')),
                _('Add ad&vanced rule'), self)
        b.clicked.connect(self.add_advanced)
        self.hb = hb = QHBoxLayout()
        l.addLayout(hb, l.rowCount(), 0, 1, 2)
        hb.addWidget(b)
        hb.addStretch(10)
        self.export_button = b = QPushButton(_('E&xport'), self)
        b.clicked.connect(self.export_rules)
        b.setToolTip(_('Export these rules to a file'))
        hb.addWidget(b)
        self.import_button = b = QPushButton(_('&Import'), self)
        b.setToolTip(_('Import rules from a file'))
        b.clicked.connect(self.import_rules)
        hb.addWidget(b)

    def initialize(self, fm, prefs, mi, pref_name):
        self.pref_name = pref_name
        self.model = RulesModel(prefs, fm, self.pref_name)
        self.rules_view.setModel(self.model)
        self.fm = fm
        self.mi = mi
        if pref_name == 'column_color_rules':
            text = _(
                'You can control the color of columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what color to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'column_icon_rules':
            text = _(
                'You can add icons to columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what icon to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'cover_grid_icon_rules':
            text = _('You can add emblems (small icons) that are displayed on the side of covers'
                     ' in the Cover grid by creating "rules" that tell calibre'
                ' what image to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
            self.enabled.setVisible(True)
            self.enabled.setChecked(gprefs['show_emblems'])
            self.enabled.setText(_('Show &emblems next to the covers'))
            self.enabled.stateChanged.connect(self.enabled_toggled)
            self.enabled.setToolTip(_(
                'If checked, you can tell calibre to display icons of your choosing'
                ' next to the covers shown in the Cover grid, controlled by the'
                ' metadata of the book.'))
            self.enabled_toggled()
        self.l1.setText('<p>'+ text)

    def enabled_toggled(self):
        enabled = self.enabled.isChecked()
        for x in ('add_advanced_button', 'rules_view', 'up_button', 'down_button', 'add_button', 'remove_button'):
            getattr(self, x).setEnabled(enabled)

    def add_rule(self):
        d = RuleEditor(self.model.fm, self.pref_name)
        d.add_blank_condition()
        if d.exec_() == d.Accepted:
            kind, col, r = d.rule
            if kind and r and col:
                idx = self.model.add_rule(kind, col, r)
                self.rules_view.scrollTo(idx)
                self.changed.emit()

    def add_advanced(self):
        if self.pref_name == 'column_color_rules':
            td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, color_field='')
            if td.exec_() == td.Accepted:
                col, r = td.rule
                if r and col:
                    idx = self.model.add_rule('color', col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()
        else:
            if self.pref_name == 'cover_grid_icon_rules':
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, doing_emblem=True)
            else:
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, icon_field_key='')
            if td.exec_() == td.Accepted:
                typ, col, r = td.rule
                if typ and r and col:
                    idx = self.model.add_rule(typ, col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()

    def edit_rule(self, index):
        try:
            kind, col, rule = self.model.data(index, Qt.UserRole)
        except:
            return
        if isinstance(rule, Rule):
            d = RuleEditor(self.model.fm, self.pref_name)
            d.apply_rule(kind, col, rule)
        elif self.pref_name == 'column_color_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col)
        elif self.pref_name == 'cover_grid_icon_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, doing_emblem=True)
        else:
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, icon_field_key=col,
                               icon_rule_kind=kind)

        if d.exec_() == d.Accepted:
            if len(d.rule) == 2:  # Convert template dialog rules to a triple
                d.rule = ('color', d.rule[0], d.rule[1])
            kind, col, r = d.rule
            if kind and r is not None and col:
                self.model.replace_rule(index, kind, col, r)
                self.rules_view.scrollTo(index)
                self.changed.emit()

    def get_selected_row(self, txt):
        sm = self.rules_view.selectionModel()
        rows = list(sm.selectedRows())
        if not rows:
            error_dialog(self, _('No rule selected'),
                    _('No rule selected for %s.')%txt, show=True)
            return None
        return sorted(rows, reverse=True)

    def remove_rule(self):
        rows = self.get_selected_row(_('removal'))
        if rows is not None:
            for row in rows:
                self.model.remove_rule(row)
            self.changed.emit()

    def move_up(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, -1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def move_down(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, 1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def clear(self):
        self.model.clear()
        self.changed.emit()

    def commit(self, prefs):
        self.model.commit(prefs)
        if self.pref_name == 'cover_grid_icon_rules':
            gprefs['show_emblems'] = self.enabled.isChecked()

    def export_rules(self):
        path = choose_save_file(self, 'export-coloring-rules', _('Choose file to export to'),
                                filters=[(_('Rules'), ['rules'])], all_files=False, initial_filename=self.pref_name + '.rules')
        if path:
            rules = {
                'version': self.model.EXIM_VERSION,
                'type': self.model.pref_name,
                'rules': self.model.rules_as_list(for_export=True)
            }
            with lopen(path, 'wb') as f:
                f.write(json.dumps(rules, indent=2))

    def import_rules(self):
        files = choose_files(self, 'import-coloring-rules', _('Choose file to import from'),
                                filters=[(_('Rules'), ['rules'])], all_files=False, select_only_single_file=True)
        if files:
            with lopen(files[0], 'rb') as f:
                raw = f.read()
            try:
                rules = json.loads(raw)
                if rules['version'] != self.model.EXIM_VERSION:
                    raise ValueError('Unsupported rules version: {}'.format(rules['version']))
                if rules['type'] != self.pref_name:
                    raise ValueError('Rules are not of the correct type')
                rules = list(rules['rules'])
            except Exception as e:
                return error_dialog(self, _('No valid rules found'), _(
                    'No valid rules were found in {}.').format(files[0]), det_msg=as_unicode(e), show=True)
            self.model.import_rules(rules)
            self.changed.emit()
Beispiel #2
0
class EditRules(QWidget):  # {{{

    changed = pyqtSignal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.enabled = c = QCheckBox(self)
        l.addWidget(c, l.rowCount(), 0, 1, 2)
        c.setVisible(False)
        c.stateChanged.connect(self.changed)

        self.l1 = l1 = QLabel('')
        l1.setWordWrap(True)
        l.addWidget(l1, l.rowCount(), 0, 1, 2)

        self.add_button = QPushButton(QIcon(I('plus.png')), _('Add Rule'),
                                      self)
        self.remove_button = QPushButton(QIcon(I('minus.png')),
                                         _('Remove Rule(s)'), self)
        self.add_button.clicked.connect(self.add_rule)
        self.remove_button.clicked.connect(self.remove_rule)
        l.addWidget(self.add_button, l.rowCount(), 0)
        l.addWidget(self.remove_button, l.rowCount() - 1, 1)

        self.g = g = QGridLayout()
        self.rules_view = QListView(self)
        self.rules_view.doubleClicked.connect(self.edit_rule)
        self.rules_view.setSelectionMode(self.rules_view.ExtendedSelection)
        self.rules_view.setAlternatingRowColors(True)
        self.rtfd = RichTextDelegate(parent=self.rules_view, max_width=400)
        self.rules_view.setItemDelegate(self.rtfd)
        g.addWidget(self.rules_view, 0, 0, 2, 1)

        self.up_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        b.setToolTip(_('Move the selected rule up'))
        b.clicked.connect(self.move_up)
        g.addWidget(b, 0, 1, 1, 1, Qt.AlignTop)
        self.down_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        b.setToolTip(_('Move the selected rule down'))
        b.clicked.connect(self.move_down)
        g.addWidget(b, 1, 1, 1, 1, Qt.AlignBottom)

        l.addLayout(g, l.rowCount(), 0, 1, 2)
        l.setRowStretch(l.rowCount() - 1, 10)

        self.add_advanced_button = b = QPushButton(QIcon(I('plus.png')),
                                                   _('Add Advanced Rule'),
                                                   self)
        b.clicked.connect(self.add_advanced)
        l.addWidget(b, l.rowCount(), 0, 1, 2)

    def initialize(self, fm, prefs, mi, pref_name):
        self.pref_name = pref_name
        self.model = RulesModel(prefs, fm, self.pref_name)
        self.rules_view.setModel(self.model)
        self.fm = fm
        self.mi = mi
        if pref_name == 'column_color_rules':
            text = _(
                'You can control the color of columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what color to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'column_icon_rules':
            text = _(
                'You can add icons to columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what icon to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'cover_grid_icon_rules':
            text = _(
                'You can add emblems (small icons) that are displayed on the side of covers'
                ' in the cover grid by creating "rules" that tell calibre'
                ' what image to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
            self.enabled.setVisible(True)
            self.enabled.setChecked(gprefs['show_emblems'])
            self.enabled.setText(_('Show &emblems next to the covers'))
            self.enabled.stateChanged.connect(self.enabled_toggled)
            self.enabled.setToolTip(
                _('If checked, you can tell calibre to display icons of your choosing'
                  ' next to the covers shown in the cover grid, controlled by the'
                  ' metadata of the book.'))
            self.enabled_toggled()
        self.l1.setText('<p>' + text)

    def enabled_toggled(self):
        enabled = self.enabled.isChecked()
        for x in ('add_advanced_button', 'rules_view', 'up_button',
                  'down_button', 'add_button', 'remove_button'):
            getattr(self, x).setEnabled(enabled)

    def add_rule(self):
        d = RuleEditor(self.model.fm, self.pref_name)
        d.add_blank_condition()
        if d.exec_() == d.Accepted:
            kind, col, r = d.rule
            if kind and r and col:
                idx = self.model.add_rule(kind, col, r)
                self.rules_view.scrollTo(idx)
                self.changed.emit()

    def add_advanced(self):
        if self.pref_name == 'column_color_rules':
            td = TemplateDialog(self,
                                '',
                                mi=self.mi,
                                fm=self.fm,
                                color_field='')
            if td.exec_() == td.Accepted:
                col, r = td.rule
                if r and col:
                    idx = self.model.add_rule('color', col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()
        else:
            if self.pref_name == 'cover_grid_icon_rules':
                td = TemplateDialog(self,
                                    '',
                                    mi=self.mi,
                                    fm=self.fm,
                                    doing_emblem=True)
            else:
                td = TemplateDialog(self,
                                    '',
                                    mi=self.mi,
                                    fm=self.fm,
                                    icon_field_key='')
            if td.exec_() == td.Accepted:
                typ, col, r = td.rule
                if typ and r and col:
                    idx = self.model.add_rule(typ, col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()

    def edit_rule(self, index):
        try:
            kind, col, rule = self.model.data(index, Qt.UserRole)
        except:
            return
        if isinstance(rule, Rule):
            d = RuleEditor(self.model.fm, self.pref_name)
            d.apply_rule(kind, col, rule)
        elif self.pref_name == 'column_color_rules':
            d = TemplateDialog(self,
                               rule,
                               mi=self.mi,
                               fm=self.fm,
                               color_field=col)
        elif self.pref_name == 'cover_grid_icon_rules':
            d = TemplateDialog(self,
                               rule,
                               mi=self.mi,
                               fm=self.fm,
                               doing_emblem=True)
        else:
            d = TemplateDialog(self,
                               rule,
                               mi=self.mi,
                               fm=self.fm,
                               icon_field_key=col,
                               icon_rule_kind=kind)

        if d.exec_() == d.Accepted:
            if len(d.rule) == 2:  # Convert template dialog rules to a triple
                d.rule = ('color', d.rule[0], d.rule[1])
            kind, col, r = d.rule
            if kind and r is not None and col:
                self.model.replace_rule(index, kind, col, r)
                self.rules_view.scrollTo(index)
                self.changed.emit()

    def get_selected_row(self, txt):
        sm = self.rules_view.selectionModel()
        rows = list(sm.selectedRows())
        if not rows:
            error_dialog(self,
                         _('No rule selected'),
                         _('No rule selected for %s.') % txt,
                         show=True)
            return None
        return sorted(rows, reverse=True)

    def remove_rule(self):
        rows = self.get_selected_row(_('removal'))
        if rows is not None:
            for row in rows:
                self.model.remove_rule(row)
            self.changed.emit()

    def move_up(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, -1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def move_down(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, 1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def clear(self):
        self.model.clear()
        self.changed.emit()

    def commit(self, prefs):
        self.model.commit(prefs)
        if self.pref_name == 'cover_grid_icon_rules':
            gprefs['show_emblems'] = self.enabled.isChecked()
Beispiel #3
0
class EditRules(QWidget):  # {{{

    changed = pyqtSignal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.enabled = c = QCheckBox(self)
        l.addWidget(c, l.rowCount(), 0, 1, 2)
        c.setVisible(False)
        c.stateChanged.connect(self.changed)

        self.l1 = l1 = QLabel('')
        l1.setWordWrap(True)
        l.addWidget(l1, l.rowCount(), 0, 1, 2)

        self.add_button = QPushButton(QIcon(I('plus.png')), _('&Add rule'),
                self)
        self.remove_button = QPushButton(QIcon(I('minus.png')),
                _('&Remove rule(s)'), self)
        self.add_button.clicked.connect(self.add_rule)
        self.remove_button.clicked.connect(self.remove_rule)
        l.addWidget(self.add_button, l.rowCount(), 0)
        l.addWidget(self.remove_button, l.rowCount() - 1, 1)

        self.g = g = QGridLayout()
        self.rules_view = QListView(self)
        self.rules_view.doubleClicked.connect(self.edit_rule)
        self.rules_view.setSelectionMode(self.rules_view.ExtendedSelection)
        self.rules_view.setAlternatingRowColors(True)
        self.rtfd = RichTextDelegate(parent=self.rules_view, max_width=400)
        self.rules_view.setItemDelegate(self.rtfd)
        g.addWidget(self.rules_view, 0, 0, 2, 1)

        self.up_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        b.setToolTip(_('Move the selected rule up'))
        b.clicked.connect(self.move_up)
        g.addWidget(b, 0, 1, 1, 1, Qt.AlignTop)
        self.down_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        b.setToolTip(_('Move the selected rule down'))
        b.clicked.connect(self.move_down)
        g.addWidget(b, 1, 1, 1, 1, Qt.AlignBottom)

        l.addLayout(g, l.rowCount(), 0, 1, 2)
        l.setRowStretch(l.rowCount() - 1, 10)

        self.add_advanced_button = b = QPushButton(QIcon(I('plus.png')),
                _('Add ad&vanced rule'), self)
        b.clicked.connect(self.add_advanced)
        self.hb = hb = QHBoxLayout()
        l.addLayout(hb, l.rowCount(), 0, 1, 2)
        hb.addWidget(b)
        hb.addStretch(10)
        self.export_button = b = QPushButton(_('E&xport'), self)
        b.clicked.connect(self.export_rules)
        b.setToolTip(_('Export these rules to a file'))
        hb.addWidget(b)
        self.import_button = b = QPushButton(_('&Import'), self)
        b.setToolTip(_('Import rules from a file'))
        b.clicked.connect(self.import_rules)
        hb.addWidget(b)

    def initialize(self, fm, prefs, mi, pref_name):
        self.pref_name = pref_name
        self.model = RulesModel(prefs, fm, self.pref_name)
        self.rules_view.setModel(self.model)
        self.fm = fm
        self.mi = mi
        if pref_name == 'column_color_rules':
            text = _(
                'You can control the color of columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what color to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'column_icon_rules':
            text = _(
                'You can add icons to columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what icon to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'cover_grid_icon_rules':
            text = _('You can add emblems (small icons) that are displayed on the side of covers'
                     ' in the Cover grid by creating "rules" that tell calibre'
                ' what image to use. Click the "Add rule" button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
            self.enabled.setVisible(True)
            self.enabled.setChecked(gprefs['show_emblems'])
            self.enabled.setText(_('Show &emblems next to the covers'))
            self.enabled.stateChanged.connect(self.enabled_toggled)
            self.enabled.setToolTip(_(
                'If checked, you can tell calibre to display icons of your choosing'
                ' next to the covers shown in the Cover grid, controlled by the'
                ' metadata of the book.'))
            self.enabled_toggled()
        self.l1.setText('<p>'+ text)

    def enabled_toggled(self):
        enabled = self.enabled.isChecked()
        for x in ('add_advanced_button', 'rules_view', 'up_button', 'down_button', 'add_button', 'remove_button'):
            getattr(self, x).setEnabled(enabled)

    def add_rule(self):
        d = RuleEditor(self.model.fm, self.pref_name)
        d.add_blank_condition()
        if d.exec_() == d.Accepted:
            kind, col, r = d.rule
            if kind and r and col:
                idx = self.model.add_rule(kind, col, r)
                self.rules_view.scrollTo(idx)
                self.changed.emit()

    def add_advanced(self):
        if self.pref_name == 'column_color_rules':
            td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, color_field='')
            if td.exec_() == td.Accepted:
                col, r = td.rule
                if r and col:
                    idx = self.model.add_rule('color', col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()
        else:
            if self.pref_name == 'cover_grid_icon_rules':
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, doing_emblem=True)
            else:
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, icon_field_key='')
            if td.exec_() == td.Accepted:
                typ, col, r = td.rule
                if typ and r and col:
                    idx = self.model.add_rule(typ, col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()

    def edit_rule(self, index):
        try:
            kind, col, rule = self.model.data(index, Qt.UserRole)
        except:
            return
        if isinstance(rule, Rule):
            d = RuleEditor(self.model.fm, self.pref_name)
            d.apply_rule(kind, col, rule)
        elif self.pref_name == 'column_color_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col)
        elif self.pref_name == 'cover_grid_icon_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, doing_emblem=True)
        else:
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, icon_field_key=col,
                               icon_rule_kind=kind)

        if d.exec_() == d.Accepted:
            if len(d.rule) == 2:  # Convert template dialog rules to a triple
                d.rule = ('color', d.rule[0], d.rule[1])
            kind, col, r = d.rule
            if kind and r is not None and col:
                self.model.replace_rule(index, kind, col, r)
                self.rules_view.scrollTo(index)
                self.changed.emit()

    def get_selected_row(self, txt):
        sm = self.rules_view.selectionModel()
        rows = list(sm.selectedRows())
        if not rows:
            error_dialog(self, _('No rule selected'),
                    _('No rule selected for %s.')%txt, show=True)
            return None
        return sorted(rows, reverse=True)

    def remove_rule(self):
        rows = self.get_selected_row(_('removal'))
        if rows is not None:
            for row in rows:
                self.model.remove_rule(row)
            self.changed.emit()

    def move_up(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, -1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def move_down(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, 1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def clear(self):
        self.model.clear()
        self.changed.emit()

    def commit(self, prefs):
        self.model.commit(prefs)
        if self.pref_name == 'cover_grid_icon_rules':
            gprefs['show_emblems'] = self.enabled.isChecked()

    def export_rules(self):
        path = choose_save_file(self, 'export-coloring-rules', _('Choose file to export to'),
                                filters=[(_('Rules'), ['rules'])], all_files=False, initial_filename=self.pref_name + '.rules')
        if path:
            rules = {
                'version': self.model.EXIM_VERSION,
                'type': self.model.pref_name,
                'rules': self.model.rules_as_list(for_export=True)
            }
            with lopen(path, 'wb') as f:
                f.write(json.dumps(rules, indent=2))

    def import_rules(self):
        files = choose_files(self, 'import-coloring-rules', _('Choose file to import from'),
                                filters=[(_('Rules'), ['rules'])], all_files=False, select_only_single_file=True)
        if files:
            with lopen(files[0], 'rb') as f:
                raw = f.read()
            try:
                rules = json.loads(raw)
                if rules['version'] != self.model.EXIM_VERSION:
                    raise ValueError('Unsupported rules version: {}'.format(rules['version']))
                if rules['type'] != self.pref_name:
                    raise ValueError('Rules are not of the correct type')
                rules = list(rules['rules'])
            except Exception as e:
                return error_dialog(self, _('No valid rules found'), _(
                    'No valid rules were found in {}.').format(files[0]), det_msg=as_unicode(e), show=True)
            self.model.import_rules(rules)
            self.changed.emit()
Beispiel #4
0
class EditRules(QWidget):  # {{{

    changed = pyqtSignal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.enabled = c = QCheckBox(self)
        l.addWidget(c, l.rowCount(), 0, 1, 2)
        c.setVisible(False)
        c.stateChanged.connect(self.changed)

        self.l1 = l1 = QLabel('')
        l1.setWordWrap(True)
        l.addWidget(l1, l.rowCount(), 0, 1, 2)

        self.add_button = QPushButton(QIcon(I('plus.png')), _('Add Rule'),
                self)
        self.remove_button = QPushButton(QIcon(I('minus.png')),
                _('Remove Rule'), self)
        self.add_button.clicked.connect(self.add_rule)
        self.remove_button.clicked.connect(self.remove_rule)
        l.addWidget(self.add_button, l.rowCount(), 0)
        l.addWidget(self.remove_button, l.rowCount() - 1, 1)

        self.g = g = QGridLayout()
        self.rules_view = QListView(self)
        self.rules_view.doubleClicked.connect(self.edit_rule)
        self.rules_view.setSelectionMode(self.rules_view.SingleSelection)
        self.rules_view.setAlternatingRowColors(True)
        self.rtfd = RichTextDelegate(parent=self.rules_view, max_width=400)
        self.rules_view.setItemDelegate(self.rtfd)
        g.addWidget(self.rules_view, 0, 0, 2, 1)

        self.up_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        b.setToolTip(_('Move the selected rule up'))
        b.clicked.connect(self.move_up)
        g.addWidget(b, 0, 1, 1, 1, Qt.AlignTop)
        self.down_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        b.setToolTip(_('Move the selected rule down'))
        b.clicked.connect(self.move_down)
        g.addWidget(b, 1, 1, 1, 1, Qt.AlignBottom)

        l.addLayout(g, l.rowCount(), 0, 1, 2)
        l.setRowStretch(l.rowCount() - 1, 10)

        self.add_advanced_button = b = QPushButton(QIcon(I('plus.png')),
                _('Add Advanced Rule'), self)
        b.clicked.connect(self.add_advanced)
        l.addWidget(b, l.rowCount(), 0, 1, 2)

    def initialize(self, fm, prefs, mi, pref_name):
        self.pref_name = pref_name
        self.model = RulesModel(prefs, fm, self.pref_name)
        self.rules_view.setModel(self.model)
        self.fm = fm
        self.mi = mi
        if pref_name == 'column_color_rules':
            text = _(
                'You can control the color of columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what color to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'column_icon_rules':
            text = _(
                'You can add icons to columns in the'
                ' book list by creating "rules" that tell calibre'
                ' what icon to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
        elif pref_name == 'cover_grid_icon_rules':
            text = _('You can add emblems (small icons) that are displayed on the side of covers'
                     ' in the cover grid by creating "rules" that tell calibre'
                ' what image to use. Click the Add Rule button below'
                ' to get started.<p>You can <b>change an existing rule</b> by'
                ' double clicking it.')
            self.enabled.setVisible(True)
            self.enabled.setChecked(gprefs['show_emblems'])
            self.enabled.setText(_('Show &emblems next to the covers'))
            self.enabled.stateChanged.connect(self.enabled_toggled)
            self.enabled.setToolTip(_(
                'If checked, you can tell calibre to displays icons of your choosing'
                ' next to the covers shown in the cover grid, controlled by the'
                ' metadata of the book.'))
            self.enabled_toggled()
        self.l1.setText('<p>'+ text)

    def enabled_toggled(self):
        enabled = self.enabled.isChecked()
        for x in ('add_advanced_button', 'rules_view', 'up_button', 'down_button', 'add_button', 'remove_button'):
            getattr(self, x).setEnabled(enabled)

    def add_rule(self):
        d = RuleEditor(self.model.fm, self.pref_name)
        d.add_blank_condition()
        if d.exec_() == d.Accepted:
            kind, col, r = d.rule
            if kind and r and col:
                idx = self.model.add_rule(kind, col, r)
                self.rules_view.scrollTo(idx)
                self.changed.emit()

    def add_advanced(self):
        if self.pref_name == 'column_color_rules':
            td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, color_field='')
            if td.exec_() == td.Accepted:
                col, r = td.rule
                if r and col:
                    idx = self.model.add_rule('color', col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()
        else:
            if self.pref_name == 'cover_grid_icon_rules':
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, doing_emblem=True)
            else:
                td = TemplateDialog(self, '', mi=self.mi, fm=self.fm, icon_field_key='')
            if td.exec_() == td.Accepted:
                typ, col, r = td.rule
                if typ and r and col:
                    idx = self.model.add_rule(typ, col, r)
                    self.rules_view.scrollTo(idx)
                    self.changed.emit()

    def edit_rule(self, index):
        try:
            kind, col, rule = self.model.data(index, Qt.UserRole)
        except:
            return
        if isinstance(rule, Rule):
            d = RuleEditor(self.model.fm, self.pref_name)
            d.apply_rule(kind, col, rule)
        elif self.pref_name == 'column_color_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col)
        elif self.pref_name == 'cover_grid_icon_rules':
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, doing_emblem=True)
        else:
            d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, icon_field_key=col,
                               icon_rule_kind=kind)

        if d.exec_() == d.Accepted:
            if len(d.rule) == 2:  # Convert template dialog rules to a triple
                d.rule = ('color', d.rule[0], d.rule[1])
            kind, col, r = d.rule
            if kind and r is not None and col:
                self.model.replace_rule(index, kind, col, r)
                self.rules_view.scrollTo(index)
                self.changed.emit()

    def get_selected_row(self, txt):
        sm = self.rules_view.selectionModel()
        rows = list(sm.selectedRows())
        if not rows:
            error_dialog(self, _('No rule selected'),
                    _('No rule selected for %s.')%txt, show=True)
            return None
        return rows[0]

    def remove_rule(self):
        row = self.get_selected_row(_('removal'))
        if row is not None:
            self.model.remove_rule(row)
            self.changed.emit()

    def move_up(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, -1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def move_down(self):
        idx = self.rules_view.currentIndex()
        if idx.isValid():
            idx = self.model.move(idx, 1)
            if idx is not None:
                sm = self.rules_view.selectionModel()
                sm.select(idx, sm.ClearAndSelect)
                self.rules_view.setCurrentIndex(idx)
                self.changed.emit()

    def clear(self):
        self.model.clear()
        self.changed.emit()

    def commit(self, prefs):
        self.model.commit(prefs)
        if self.pref_name == 'cover_grid_icon_rules':
            gprefs['show_emblems'] = self.enabled.isChecked()
Beispiel #5
0
class SideView(QObject):
    onBeforeItemDeletion = pyqtSignal(str)
    onEntrySelected = pyqtSignal(str)
    onDirectoryChanged = pyqtSignal(str)
    onRemoveRequested = pyqtSignal(str)

    def __init__(self, dirLister, entryProvider: IEntryProvider,
                 newEntryText: str, itemNameNormalizer: IItemNameNormalizer):
        super().__init__()

        def initListView():
            self.listView = QListView()
            self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)
            self.listView.setModel(self.model)
            self.listView.setMinimumWidth(200)

            actionRemove = QAction("Remove", None)
            self.listView.addAction(actionRemove)

            self.listView.selectionModel().currentChanged.connect(
                lambda selectedItem, unselectedItem: self.onEntrySelected.emit(
                    self.itemNameNormalizer.normalizeName(
                        self.currentDir.filePath(selectedItem.data()))))

            def contextMenu(position):
                menu = QMenu()
                index = self.listView.indexAt(position)
                entry = self.model.data(index, Qt.DisplayRole)

                deleteAction = None
                renameAction = None

                addAction = menu.addAction("Add")

                if entry is not None:
                    deleteAction = menu.addAction("Delete")
                    renameAction = menu.addAction("Rename")

                refreshAction = menu.addAction("Refresh")

                chosenAction = menu.exec_(self.listView.mapToGlobal(position))

                if chosenAction is None:
                    return

                if chosenAction == deleteAction:
                    self.onRemoveRequested.emit(entry)
                elif chosenAction == renameAction:
                    self.renameEntry(index, entry)
                elif chosenAction == addAction:
                    self.onCreateNewEntry()
                elif chosenAction == refreshAction:
                    self.refreshListViewEntries()

            self.listView.customContextMenuRequested.connect(contextMenu)
            self.listView.setContextMenuPolicy(Qt.CustomContextMenu)

        self.currentDir: QDir = None
        self.model = QStringListModel()
        self.directoryLister = dirLister
        self.entryProvider = entryProvider
        self.newEntryText = newEntryText
        self.itemNameNormalizer = itemNameNormalizer
        self.sortingParser: IEntrySorting
        initListView()

    def renameEntry(self, index, oldName):
        def onNewEntryCommited(editedLine: QLineEdit):
            self.listView.itemDelegate().commitData.disconnect(
                onNewEntryCommited)
            try:
                newName = editedLine.text()
                normalizedNameOld = self.itemNameNormalizer.normalizeName(
                    oldName)
                normalizedNameNew = self.itemNameNormalizer.normalizeName(
                    newName)

                self.emitOnItemDeletion(normalizedNameOld)

                self.entryProvider.renameEnty(normalizedNameOld,
                                              normalizedNameNew)
                self.sortingParser.rename(oldName, newName)
                self.refreshListViewEntries()
            except Exception:
                pass

        self.listView.itemDelegate().commitData.connect(onNewEntryCommited)
        self.listView.edit(index)

    def emitOnItemDeletion(self, normalizedName):
        self.onBeforeItemDeletion.emit(
            self.currentDir.filePath(normalizedName))

    def removeEntry(self, entry):
        normalizedName = self.itemNameNormalizer.normalizeName(entry)
        self.emitOnItemDeletion(normalizedName)

        self.entryProvider.removeEntry(normalizedName)
        self.refreshListViewEntries()

    def setDirectory(self, dirPath: str):
        self.currentDir = QDir(dirPath)
        self.sortingParser = EntrySortingFile(
            self.currentDir.filePath('.sorting'))
        self.entryProvider.setContext(dirPath)
        self.refreshListViewEntries()

        self.onDirectoryChanged.emit(self.currentDir.absolutePath())

    def refreshListViewEntries(self):
        if self.currentDir is None:
            return
        entries = self.directoryLister.listEntries(self.currentDir)
        sortedEntries = self.sortingParser.getSortedList(entries)

        self.model.setStringList(sortedEntries)

    def onCreateNewEntry(self):
        def onNewEntryCommited(editedLine: QLineEdit):
            self.listView.itemDelegate().commitData.disconnect(
                onNewEntryCommited)
            try:
                if editedLine.text() == self.newEntryText:
                    raise Exception()

                normalizedName = self.itemNameNormalizer.normalizeName(
                    editedLine.text())
                self.entryProvider.addEntry(normalizedName)
                self.refreshListViewEntries()
                self.listView.setCurrentIndex(index)
            except Exception:
                print(f"Error adding entry {editedLine.text()}",
                      file=sys.stderr)
                self.model.removeRow(self.model.rowCount() - 1)

        if not self.model.insertRow(self.model.rowCount()):
            return

        self.listView.itemDelegate().commitData.connect(onNewEntryCommited)
        index = self.model.index(self.model.rowCount() - 1, 0)
        self.model.setData(index, self.newEntryText)
        self.listView.edit(index)
        pass
Beispiel #6
0
class FITSBrowse(QMainWindow):
    """ The main window of this GUI."""

    imdisp = None

    def __init__(self, parent=None):
        """ 
        """
        print("Skeet")

        super(FITSBrowse, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("FITSBrowse")

        self.current_directory = CurrentDirectory(
            "/data/lemi-archive-2016-04/20160427")
        self.model = FitsFileTableModel(self.current_directory)
        self.d_model = DirectoryListModel(self.current_directory)
        self.main_widget = QWidget(self)

        self.dir_text = "Current Directory: {0}".format(
            self.current_directory.cur_dir_path)
        self.cur_dir_label = QLabel(self.dir_text, self)

        self.listLabel = QLabel("&Directories")

        self.list_view = QListView()
        self.listLabel.setBuddy(self.list_view)
        self.list_view.setModel(self.d_model)
        self.list_view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

        self.list_view.setMinimumWidth(self.list_view.sizeHintForColumn(0))
        self.list_view.setMaximumWidth(self.list_view.sizeHintForColumn(0))

        self.list_view_sm = self.list_view.selectionModel()
        self.list_view.doubleClicked.connect(self.change_directory)

        self.table_view = QTableView()
        self.table_view.setModel(self.model)
        self.table_view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.table_view_sm = self.table_view.selectionModel()
        self.table_view.doubleClicked.connect(self.display_image)

        list_vbox = QVBoxLayout()
        list_vbox.addWidget(self.listLabel)
        list_vbox.addWidget(self.list_view)
        self.list_widget = QWidget()
        self.list_widget.setLayout(list_vbox)

        #self.list_view.size

        main_layout = QHBoxLayout()
        main_layout.addWidget(self.list_widget)
        main_layout.addWidget(self.table_view)

        button_layout = QHBoxLayout()
        quit_button = QPushButton('Quit', self)
        quit_button.setToolTip('This button quits FITSBrowse')
        quit_button.clicked.connect(QApplication.instance().quit)
        button_layout.addStretch()
        button_layout.addWidget(quit_button)

        sep_line = QFrame()
        sep_line.setFrameShape(QFrame.HLine)

        super_layout = QVBoxLayout(self.main_widget)
        super_layout.addWidget(self.cur_dir_label)
        super_layout.addWidget(sep_line)
        super_layout.addLayout(main_layout)
        super_layout.addLayout(button_layout)

        self.setCentralWidget(self.main_widget)
        QtCore.QTimer.singleShot(0, self.initialLoad)
        x = self.table_view.frameSize()
        x = x.width()
        self.table_view.setMinimumWidth(x)
        self.main_widget.setMinimumHeight(500)

    def initialLoad(self):
        for column in (1, 2, 3, 4, 5, 6, 7):
            self.table_view.resizeColumnToContents(column)

    def display_image(self):
        indexes = self.table_view_sm.selectedIndexes()
        index = indexes[0]
        file_name = str(index.data())
        if (file_name.endswith("fits") or file_name.endswith("fit")):
            file_with_path = os.path.join(self.current_directory.cur_dir_path,
                                          file_name)
            self.im_disp = ImageAnalyzer(file_with_path, parent=self)

    def change_directory(self):
        indexes = self.list_view_sm.selectedRows()
        if (indexes != []):
            index = indexes[0]
            new_directory = str(index.data())
            current_path = self.current_directory.cur_dir_path
            if (new_directory == ".."):
                # Go up one directory
                if (current_path == "/"):
                    # Do nothing.
                    pass
                else:
                    self.current_directory = CurrentDirectory(
                        os.path.dirname(current_path))
            else:
                # Go down into the selected directory.
                self.current_directory = CurrentDirectory(
                    os.path.join(current_path, new_directory))
            print("change directory, new directory is:",
                  self.current_directory.cur_dir_path)
            self.model = FitsFileTableModel(self.current_directory)
            self.d_model = DirectoryListModel(self.current_directory)

            self.dir_text = "Current Directory: {0}".format(
                self.current_directory.cur_dir_path)
            self.cur_dir_label.setText(self.dir_text)

            self.list_view.setModel(self.d_model)
            self.list_view_sm = self.list_view.selectionModel()
            self.list_view.update()
            self.list_view.setMinimumWidth(self.list_view.sizeHintForColumn(0))
            self.list_view.setMaximumWidth(self.list_view.sizeHintForColumn(0))

            self.table_view.setModel(self.model)
            self.table_view_sm = self.table_view.selectionModel()
            self.table_view.update()
            QtCore.QTimer.singleShot(0, self.initialLoad)
            x = self.table_view.frameSize()
            x = x.width()
            self.table_view.setMinimumWidth(x)
        else:
            print("no directory selected")