Example #1
0
    def initialise (self, univers):
        model = QStandardItemModel (3,1)
    
        i = 0
        for faction in univers.faction_list :
            item = QStandardItem(faction.name)
            item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled);
            item.setData(QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole);

            model.setItem(i, 0, item)
            i = i + 1

        combo = QComboBox()
        combo.setModel(model)

        list_v = QListView()
        list_v.setModel(model)

        table = QTableView()
        table.setModel(model)

        container = QWidget()
        containerLayout = QVBoxLayout()
        container.setLayout(containerLayout)
        containerLayout.addWidget(combo)
        containerLayout.addWidget(list_v)
        containerLayout.addWidget(table)
Example #2
0
def create_filterable_names_list(names, filter_text=None, parent=None, model=NamesModel):
    nl = QListView(parent)
    nl.m = m = model(names, parent=nl)
    m.filtered.connect(lambda all_items: nl.scrollTo(m.index(0)))
    nl.setModel(m)
    if model is NamesModel:
        nl.d = NamesDelegate(nl)
        nl.setItemDelegate(nl.d)
    f = QLineEdit(parent)
    f.setPlaceholderText(filter_text or '')
    f.textEdited.connect(m.filter)
    return nl, f
Example #3
0
class SelectFormats(QDialog):
    def __init__(self,
                 fmt_count,
                 msg,
                 single=False,
                 parent=None,
                 exclude=False):
        QDialog.__init__(self, parent)
        self._l = QVBoxLayout(self)
        self.single_fmt = single
        self.setLayout(self._l)
        self.setWindowTitle(_('Choose formats'))
        self._m = QLabel(msg)
        self._m.setWordWrap(True)
        self._l.addWidget(self._m)
        self.formats = Formats(fmt_count)
        self.fview = QListView(self)
        self.fview.doubleClicked.connect(
            self.double_clicked, type=Qt.ConnectionType.QueuedConnection)
        if exclude:
            if QApplication.instance().is_dark_theme:
                sheet = 'background-color: #DAA520; color: black'
            else:
                sheet = 'background-color: #fae7b5'
            self.fview.setStyleSheet('QListView { %s }' % sheet)
        self._l.addWidget(self.fview)
        self.fview.setModel(self.formats)
        self.fview.setSelectionMode(
            QAbstractItemView.SelectionMode.SingleSelection
            if single else QAbstractItemView.SelectionMode.MultiSelection)
        self.bbox = \
        QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel,
                Qt.Orientation.Horizontal, self)
        self._l.addWidget(self.bbox)
        self.bbox.accepted.connect(self.accept)
        self.bbox.rejected.connect(self.reject)
        self.fview.setIconSize(QSize(48, 48))
        self.fview.setSpacing(2)

        self.resize(350, 500)
        self.selected_formats = set()

    def accept(self, *args):
        for idx in self.fview.selectedIndexes():
            self.selected_formats.add(self.formats.fmt(idx))
        QDialog.accept(self, *args)

    def double_clicked(self, index):
        if self.single_fmt:
            self.accept()
Example #4
0
class SelectFormats(QDialog):
    def __init__(self,
                 fmt_count,
                 msg,
                 single=False,
                 parent=None,
                 exclude=False):
        QDialog.__init__(self, parent)
        self._l = QVBoxLayout(self)
        self.single_fmt = single
        self.setLayout(self._l)
        self.setWindowTitle(_('Choose formats'))
        self._m = QLabel(msg)
        self._m.setWordWrap(True)
        self._l.addWidget(self._m)
        self.formats = Formats(fmt_count)
        self.fview = QListView(self)
        self.fview.doubleClicked.connect(self.double_clicked,
                                         type=Qt.QueuedConnection)
        if exclude:
            self.fview.setStyleSheet('''
                    QListView { background-color: #FAE7B5}
                    ''')
        self._l.addWidget(self.fview)
        self.fview.setModel(self.formats)
        self.fview.setSelectionMode(self.fview.SingleSelection
                                    if single else self.fview.MultiSelection)
        self.bbox = \
        QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
                Qt.Horizontal, self)
        self._l.addWidget(self.bbox)
        self.bbox.accepted.connect(self.accept)
        self.bbox.rejected.connect(self.reject)
        self.fview.setIconSize(QSize(48, 48))
        self.fview.setSpacing(2)

        self.resize(350, 500)
        self.selected_formats = set([])

    def accept(self, *args):
        for idx in self.fview.selectedIndexes():
            self.selected_formats.add(self.formats.fmt(idx))
        QDialog.accept(self, *args)

    def double_clicked(self, index):
        if self.single_fmt:
            self.accept()
Example #5
0
class SelectFormats(QDialog):

    def __init__(self, fmt_count, msg, single=False, parent=None, exclude=False):
        QDialog.__init__(self, parent)
        self._l = QVBoxLayout(self)
        self.single_fmt = single
        self.setLayout(self._l)
        self.setWindowTitle(_('Choose formats'))
        self._m = QLabel(msg)
        self._m.setWordWrap(True)
        self._l.addWidget(self._m)
        self.formats = Formats(fmt_count)
        self.fview = QListView(self)
        self.fview.doubleClicked.connect(self.double_clicked,
                type=Qt.QueuedConnection)
        if exclude:
            self.fview.setStyleSheet('''
                    QListView { background-color: #FAE7B5}
                    ''')
        self._l.addWidget(self.fview)
        self.fview.setModel(self.formats)
        self.fview.setSelectionMode(self.fview.SingleSelection if single else
                self.fview.MultiSelection)
        self.bbox = \
        QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
                Qt.Horizontal, self)
        self._l.addWidget(self.bbox)
        self.bbox.accepted.connect(self.accept)
        self.bbox.rejected.connect(self.reject)
        self.fview.setIconSize(QSize(48, 48))
        self.fview.setSpacing(2)

        self.resize(350, 500)
        self.selected_formats = set([])

    def accept(self, *args):
        for idx in self.fview.selectedIndexes():
            self.selected_formats.add(self.formats.fmt(idx))
        QDialog.accept(self, *args)

    def double_clicked(self, index):
        if self.single_fmt:
            self.accept()
Example #6
0
class ShortcutConfig(QWidget):
    def __init__(self, model, parent=None):
        QWidget.__init__(self, parent)
        self._layout = QHBoxLayout()
        self.setLayout(self._layout)
        self.view = QListView(self)
        self._layout.addWidget(self.view)
        self.view.setModel(model)
        self.delegate = Delegate()
        self.view.setItemDelegate(self.delegate)
        self.delegate.sizeHintChanged.connect(self.scrollTo,
                                              type=Qt.QueuedConnection)

    def scrollTo(self, index):
        self.view.scrollTo(index, self.view.EnsureVisible)

    @property
    def is_editing(self):
        return self.view.state() == self.view.EditingState
Example #7
0
class GameListWidget(QWidget):
    def __init__(self, main):
        super(GameListWidget, self).__init__()
        self.main_win = main
        self.keystore_exchanged = False

        self.setObjectName("GameListWidget")
        v_layout = QVBoxLayout()

        h_layout1 = QHBoxLayout()
        self.game_list_view = QListView()
        self.game_list_view.setViewMode(QListView.ListMode)
        self.game_list_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.game_list_model = GameListModel(self.main_win.games)
        self.game_list_view.setModel(self.game_list_model)
        self.game_list_view.clicked.connect(self.list_item_onclick)
        h_layout1.addWidget(self.game_list_view, 1)
        self.game_list_view.setCurrentIndex(
            self.game_list_model.index(self.main_win.game_index))
        self.game = self.main_win.games[self.main_win.game_index]

        form_layout = QFormLayout()
        form_layout.setContentsMargins(20, 50, 20, 50)
        self.game_name_value = QLineEdit()
        form_layout.addRow("游戏名称:", self.game_name_value)
        self.game_desc_value = QTextEdit()
        form_layout.addRow("游戏简介:", self.game_desc_value)
        self.game_appid_value = QLabel()
        self.game_appid_value.setTextInteractionFlags(Qt.TextSelectableByMouse)
        form_layout.addRow("游戏ID:", self.game_appid_value)
        self.game_appkey_value = QLabel()
        self.game_appkey_value.setTextInteractionFlags(
            Qt.TextSelectableByMouse)
        form_layout.addRow("客户端Key:", self.game_appkey_value)
        h_layout = QHBoxLayout()
        self.keystore_path = QLineEdit()
        select_key_btn = QPushButton("浏览")
        select_key_btn.setStyleSheet('QPushButton{border-radius: 0px;}')
        select_key_btn.clicked.connect(self.select_ketstore)
        h_layout.addWidget(self.keystore_path)
        h_layout.addWidget(select_key_btn)
        form_layout.addRow("KeyStore:", h_layout)
        self.keystore_pwd_value = QLineEdit()
        form_layout.addRow("KeyPass:"******"Alias:", self.keystore_alias_value)
        self.keystore_aliaspwd_value = QLineEdit()
        form_layout.addRow("AliasPass:"******"更换Icon")
        icon_exchange_btn.setFixedWidth(100)
        icon_exchange_btn.clicked.connect(self.exchange_icon)
        v_layout1.addWidget(icon_exchange_btn, alignment=Qt.AlignHCenter)
        v_layout1.addStretch(2)
        h_layout1.addLayout(v_layout1, 1)
        v_layout.addLayout(h_layout1)

        h_layout2 = QHBoxLayout()
        create_game_btn = QPushButton("返 回")
        create_game_btn.setFixedWidth(100)
        create_game_btn.clicked.connect(self.back)
        h_layout2.addWidget(create_game_btn,
                            alignment=Qt.AlignLeft | Qt.AlignBottom)
        back_btn = QPushButton("创建游戏")
        back_btn.setFixedWidth(100)
        back_btn.clicked.connect(self.add_game)
        h_layout2.addWidget(back_btn, alignment=Qt.AlignHCenter)
        next_btn = QPushButton("下一步")
        next_btn.setFixedWidth(100)
        next_btn.clicked.connect(self.next)
        h_layout2.addWidget(next_btn, alignment=Qt.AlignRight | Qt.AlignBottom)
        v_layout.addLayout(h_layout2)
        self.setLayout(v_layout)
        self.set_game_info()

    def set_game_info(self):
        self.game_name_value.setText(self.game['name'])
        self.game_desc_value.setText(self.game['desc'])
        self.game_appid_value.setText(self.game['id'])
        self.game_appkey_value.setText(self.game['key'])
        self.keystore_path.setText(self.game['keystore'])
        self.keystore_pwd_value.setText(self.game['keypwd'])
        self.keystore_alias_value.setText(self.game['alias'])
        self.keystore_aliaspwd_value.setText(self.game['aliaspwd'])

        icon = Utils.get_full_path('games/' + self.game['id'] +
                                   '/icon/icon.png')
        if not os.path.exists(icon):
            icon = 'icon.png'
        self.icon_img.setPixmap(QPixmap(icon))

    def list_item_onclick(self):
        self.main_win.game_index = self.game_list_view.currentIndex().row()
        self.game = self.main_win.games[self.main_win.game_index]
        self.set_game_info()

    def back(self):
        self.main_win.set_main_widget()

    def add_game(self):
        if not self.save_data():
            return
        self.main_win.set_create_game_widget(self.main_win.games)

    def select_ketstore(self):
        fname = QFileDialog.getOpenFileName(
            self, '选择签名文件',
            Utils.get_full_path('games/' + self.game['id'] + '/keystore/'))
        if fname[0]:
            if os.path.samefile(
                    fname[0],
                    Utils.get_full_path('games/' + self.game['id'] +
                                        '/keystore/' + self.game['keystore'])):
                self.keystore_path.setText(self.game['keystore'])
                self.keystore_pwd_value.setText(self.game['keypwd'])
                self.keystore_alias_value.setText(self.game['alias'])
                self.keystore_aliaspwd_value.setText(self.game['aliaspwd'])
                self.keystore_exchanged = False
            else:
                self.keystore_path.setText(fname[0])
                self.keystore_pwd_value.clear()
                self.keystore_alias_value.clear()
                self.keystore_aliaspwd_value.clear()
                self.keystore_exchanged = True

    def exchange_icon(self):
        fname = QFileDialog.getOpenFileName(
            self, '选择icon',
            Utils.get_full_path('games/' + self.game['id'] + '/icon/'),
            ("Images (*.png)"))
        if fname[0]:
            pix = QPixmap(fname[0])
            if pix.width() != 512 or pix.height() != 512:
                QMessageBox.warning(self, "警告", "必须上传512*512.png图片")
                return
            self.icon_img.setPixmap(pix)
            current_icon = Utils.get_full_path('games/' + self.game['id'] +
                                               '/icon/icon.png')
            if os.path.exists(current_icon):
                if os.path.samefile(os.path.dirname(fname[0]),
                                    os.path.dirname(current_icon)):
                    if not os.path.samefile(
                            fname[0], current_icon
                    ):  # 如果选中的,在game的icon目录下,但不是当前icon,则进行重命名
                        count = 0
                        temp = 'icon0.png'
                        while os.path.exists(
                                Utils.get_full_path('games/' +
                                                    self.game['id'] +
                                                    '/icon/' + temp)):
                            count += 1
                            temp = 'icon' + str(count) + '.png'
                        os.renames(
                            current_icon,
                            Utils.get_full_path('games/' + self.game['id'] +
                                                '/icon/' + temp))
                        os.renames(fname[0], current_icon)
                    else:  # 如果所选的是当前icon,不做处理
                        return
                else:  # 如果选中的不在game的icon目录下,则重命名当前icon,并将选中的icon复制到目录下作为当前icon
                    count = 0
                    temp = 'icon0.png'
                    while os.path.exists(
                            Utils.get_full_path('games/' + self.game['id'] +
                                                '/icon/' + temp)):
                        count += 1
                        temp = 'icon' + str(count) + '.png'
                    os.renames(
                        current_icon,
                        Utils.get_full_path('games/' + self.game['id'] +
                                            '/icon/' + temp))
                    Utils.copy_file(fname[0], current_icon)
            else:
                Utils.copy_file(fname[0], current_icon)

    def save_data(self):
        if self.game_name_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "游戏名称不能为空!")
            return False
        if self.keystore_path.text().strip() == "":
            QMessageBox.warning(self, "警告", "必须上传keystore签名文件!")
            return False
        if self.keystore_pwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "keystore密码不能为空!")
            return False
        if self.keystore_alias_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias不能为空!")
            return False
        if self.keystore_aliaspwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias密码不能为空!")
            return False
        self.game['name'] = self.game_name_value.text().strip()
        self.game['desc'] = self.game_desc_value.toPlainText().strip()
        if self.keystore_exchanged:
            keystore = os.path.basename(self.keystore_path.text().strip())
            self.game['keystore'] = keystore
            self.game['keypwd'] = self.keystore_pwd_value.text().strip()
            self.game['alias'] = self.keystore_alias_value.text().strip()
            self.game['aliaspwd'] = self.keystore_aliaspwd_value.text().strip()
            keystore_path = Utils.get_full_path('games/' + self.game['id'] +
                                                '/keystore/' + keystore)
            if not os.path.exists(keystore_path):
                Utils.copy_file(self.keystore_path.text().strip(),
                                keystore_path)

        self.main_win.games[self.main_win.game_index] = self.game
        self.game_list_model.update_item(self.main_win.game_index, self.game)
        return Utils.update_games(Utils.get_full_path('games/games.xml'),
                                  self.game, self.main_win.game_index)

    def next(self):
        if not self.save_data():
            return
        channels = Utils.get_channels(
            Utils.get_full_path('games/' + self.game['id'] + '/config.xml'))
        if channels is None:
            if not os.path.exists(Utils.get_full_path('channelsdk')):
                QMessageBox.warning(
                    self, "警告",
                    os.path.dirname(os.getcwd()) + " 没有channelsdk文件夹")
                return
            elif len(os.listdir(Utils.get_full_path('channelsdk'))) <= 0:
                QMessageBox.warning(
                    self, "警告", "本地没有渠道sdk,请手动添加sdk文件夹到" +
                    Utils.get_full_path('channelsdk'))
                return
            channels = []
            self.main_win.set_add_channel_widget(channels)
        else:
            self.main_win.set_channel_list_widget(channels)
Example #8
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()
Example #9
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()
Example #10
0
class Config(QDialog):
    '''
    Configuration dialog for single book conversion. If accepted, has the
    following important attributes

    output_format - Output format (without a leading .)
    input_format  - Input format (without a leading .)
    opf_path - Path to OPF file with user specified metadata
    cover_path - Path to user specified cover (can be None)
    recommendations - A pickled list of 3 tuples in the same format as the
    recommendations member of the Input/Output plugins.
    '''
    def __init__(self,
                 parent,
                 db,
                 book_id,
                 preferred_input_format=None,
                 preferred_output_format=None):
        QDialog.__init__(self, parent)
        self.setupUi()
        self.opt_individual_saved_settings.setVisible(False)
        self.db, self.book_id = db, book_id

        self.setup_input_output_formats(self.db, self.book_id,
                                        preferred_input_format,
                                        preferred_output_format)
        self.setup_pipeline()

        self.input_formats.currentIndexChanged[native_string_type].connect(
            self.setup_pipeline)
        self.output_formats.currentIndexChanged[native_string_type].connect(
            self.setup_pipeline)
        self.groups.setSpacing(5)
        self.groups.activated[(QModelIndex)].connect(self.show_pane)
        self.groups.clicked[(QModelIndex)].connect(self.show_pane)
        self.groups.entered[(QModelIndex)].connect(self.show_group_help)
        rb = self.buttonBox.button(self.buttonBox.RestoreDefaults)
        rb.setText(_('Restore &defaults'))
        rb.clicked.connect(self.restore_defaults)
        self.groups.setMouseTracking(True)
        geom = gprefs.get('convert_single_dialog_geom', None)
        if geom:
            self.restoreGeometry(geom)
        else:
            self.resize(self.sizeHint())

    def setupUi(self):
        self.setObjectName("Dialog")
        self.resize(1024, 700)
        self.setWindowIcon(QIcon(I('convert.png')))
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.input_label = QLabel(self)
        self.input_label.setObjectName("input_label")
        self.horizontalLayout.addWidget(self.input_label)
        self.input_formats = QComboBox(self)
        self.input_formats.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        self.input_formats.setMinimumContentsLength(5)
        self.input_formats.setObjectName("input_formats")
        self.horizontalLayout.addWidget(self.input_formats)
        self.opt_individual_saved_settings = QCheckBox(self)
        self.opt_individual_saved_settings.setObjectName(
            "opt_individual_saved_settings")
        self.horizontalLayout.addWidget(self.opt_individual_saved_settings)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.label_2 = QLabel(self)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout.addWidget(self.label_2)
        self.output_formats = QComboBox(self)
        self.output_formats.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        self.output_formats.setMinimumContentsLength(5)
        self.output_formats.setObjectName("output_formats")
        self.horizontalLayout.addWidget(self.output_formats)
        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2)
        self.groups = QListView(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.groups.sizePolicy().hasHeightForWidth())
        self.groups.setSizePolicy(sizePolicy)
        self.groups.setTabKeyNavigation(True)
        self.groups.setIconSize(QSize(48, 48))
        self.groups.setWordWrap(True)
        self.groups.setObjectName("groups")
        self.gridLayout.addWidget(self.groups, 1, 0, 3, 1)
        self.scrollArea = QScrollArea(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(4)
        sizePolicy.setVerticalStretch(10)
        sizePolicy.setHeightForWidth(
            self.scrollArea.sizePolicy().hasHeightForWidth())
        self.scrollArea.setSizePolicy(sizePolicy)
        self.scrollArea.setFrameShape(QFrame.NoFrame)
        self.scrollArea.setLineWidth(0)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QWidget()
        self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 810, 494))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.verticalLayout_3 = QVBoxLayout(self.scrollAreaWidgetContents)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.stack = QStackedWidget(self.scrollAreaWidgetContents)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.stack.sizePolicy().hasHeightForWidth())
        self.stack.setSizePolicy(sizePolicy)
        self.stack.setObjectName("stack")
        self.page = QWidget()
        self.page.setObjectName("page")
        self.stack.addWidget(self.page)
        self.page_2 = QWidget()
        self.page_2.setObjectName("page_2")
        self.stack.addWidget(self.page_2)
        self.verticalLayout_3.addWidget(self.stack)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.gridLayout.addWidget(self.scrollArea, 1, 1, 1, 1)
        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok
                                          | QDialogButtonBox.RestoreDefaults)
        self.buttonBox.setObjectName("buttonBox")
        self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1)
        self.help = QTextEdit(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.help.sizePolicy().hasHeightForWidth())
        self.help.setSizePolicy(sizePolicy)
        self.help.setMaximumHeight(80)
        self.help.setObjectName("help")
        self.gridLayout.addWidget(self.help, 2, 1, 1, 1)
        self.input_label.setBuddy(self.input_formats)
        self.label_2.setBuddy(self.output_formats)
        self.input_label.setText(_("&Input format:"))
        self.opt_individual_saved_settings.setText(
            _("Use &saved conversion settings for individual books"))
        self.label_2.setText(_("&Output format:"))

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def sizeHint(self):
        desktop = QCoreApplication.instance().desktop()
        geom = desktop.availableGeometry(self)
        nh, nw = max(300, geom.height() - 100), max(400, geom.width() - 70)
        return QSize(nw, nh)

    def restore_defaults(self):
        delete_specifics(self.db, self.book_id)
        self.setup_pipeline()

    @property
    def input_format(self):
        return unicode_type(self.input_formats.currentText()).lower()

    @property
    def output_format(self):
        return unicode_type(self.output_formats.currentText()).lower()

    @property
    def manually_fine_tune_toc(self):
        for i in range(self.stack.count()):
            w = self.stack.widget(i)
            if hasattr(w, 'manually_fine_tune_toc'):
                return w.manually_fine_tune_toc.isChecked()

    def setup_pipeline(self, *args):
        oidx = self.groups.currentIndex().row()
        input_format = self.input_format
        output_format = self.output_format
        self.plumber = create_dummy_plumber(input_format, output_format)

        def widget_factory(cls):
            return cls(self.stack, self.plumber.get_option_by_name,
                       self.plumber.get_option_help, self.db, self.book_id)

        self.mw = widget_factory(MetadataWidget)
        self.setWindowTitle(
            _('Convert') + ' ' + unicode_type(self.mw.title.text()))
        lf = widget_factory(LookAndFeelWidget)
        hw = widget_factory(HeuristicsWidget)
        sr = widget_factory(SearchAndReplaceWidget)
        ps = widget_factory(PageSetupWidget)
        sd = widget_factory(StructureDetectionWidget)
        toc = widget_factory(TOCWidget)
        from calibre.gui2.actions.toc_edit import SUPPORTED
        toc.manually_fine_tune_toc.setVisible(
            output_format.upper() in SUPPORTED)
        debug = widget_factory(DebugWidget)

        output_widget = self.plumber.output_plugin.gui_configuration_widget(
            self.stack, self.plumber.get_option_by_name,
            self.plumber.get_option_help, self.db, self.book_id)
        input_widget = self.plumber.input_plugin.gui_configuration_widget(
            self.stack, self.plumber.get_option_by_name,
            self.plumber.get_option_help, self.db, self.book_id)
        while True:
            c = self.stack.currentWidget()
            if not c:
                break
            self.stack.removeWidget(c)

        widgets = [self.mw, lf, hw, ps, sd, toc, sr]
        if input_widget is not None:
            widgets.append(input_widget)
        if output_widget is not None:
            widgets.append(output_widget)
        widgets.append(debug)
        for w in widgets:
            self.stack.addWidget(w)
            w.set_help_signal.connect(self.help.setPlainText)

        self._groups_model = GroupModel(widgets)
        self.groups.setModel(self._groups_model)

        idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0
        self.groups.setCurrentIndex(self._groups_model.index(idx))
        self.stack.setCurrentIndex(idx)
        try:
            shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True)
        except:
            pass

    def setup_input_output_formats(self, db, book_id, preferred_input_format,
                                   preferred_output_format):
        if preferred_output_format:
            preferred_output_format = preferred_output_format.upper()
        output_formats = get_output_formats(preferred_output_format)
        input_format, input_formats = get_input_format_for_book(
            db, book_id, preferred_input_format)
        preferred_output_format = preferred_output_format if \
            preferred_output_format in output_formats else \
            sort_formats_by_preference(output_formats,
                    [prefs['output_format']])[0]
        self.input_formats.addItems(
            (unicode_type(x.upper()) for x in input_formats))
        self.output_formats.addItems(
            (unicode_type(x.upper()) for x in output_formats))
        self.input_formats.setCurrentIndex(input_formats.index(input_format))
        self.output_formats.setCurrentIndex(
            output_formats.index(preferred_output_format))

    def show_pane(self, index):
        self.stack.setCurrentIndex(index.row())

    def accept(self):
        recs = GuiRecommendations()
        for w in self._groups_model.widgets:
            if not w.pre_commit_check():
                return
            x = w.commit(save_defaults=False)
            recs.update(x)
        self.opf_file, self.cover_file = self.mw.opf_file, self.mw.cover_file
        self._recommendations = recs
        if self.db is not None:
            recs['gui_preferred_input_format'] = self.input_format
            save_specifics(self.db, self.book_id, recs)
        self.break_cycles()
        QDialog.accept(self)

    def reject(self):
        self.break_cycles()
        QDialog.reject(self)

    def done(self, r):
        if self.isVisible():
            gprefs['convert_single_dialog_geom'] = \
                bytearray(self.saveGeometry())
        return QDialog.done(self, r)

    def break_cycles(self):
        for i in range(self.stack.count()):
            w = self.stack.widget(i)
            w.break_cycles()

    @property
    def recommendations(self):
        recs = [(k, v, OptionRecommendation.HIGH)
                for k, v in self._recommendations.items()]
        return recs

    def show_group_help(self, index):
        widget = self._groups_model.widgets[index.row()]
        self.help.setPlainText(widget.HELP)
Example #11
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()
Example #12
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()
Example #13
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")
Example #14
0
class PackageWidgetM(QWidget):
    def __init__(self, main):
        super(PackageWidgetM, self).__init__()
        self.setObjectName("PackageWidgetM")
        self.main_win = main
        self.game_index = 0
        self.selected = [
        ]  # 已选中的channel及所属game列表 如:[{"game": 当前game字典, "channel": 当前channel字典}, {}, {}]
        self.selected_name = [
        ]  # 已选中的渠道显示名称列表 如:["10878922-765321", "", "", ""]
        self.lbps = {}  # 打包信息及进度条组合字典 {"765321": {}, "": {}}
        self.progress = None
        self.monitor = PackageMonitor()
        self.monitor.signal.connect(self.complete)

        v_layout = QVBoxLayout()
        h_layout1 = QHBoxLayout()
        # 全部游戏及其下的渠道列表
        self.tool_box = QToolBox(self)
        self.tool_box.setFixedWidth(100)
        for game in self.main_win.games:
            clv = QListView()
            clv.setEditTriggers(QAbstractItemView.NoEditTriggers)
            clv.setContextMenuPolicy(Qt.CustomContextMenu)
            self.tool_box.addItem(clv, game['id'])
        self.tool_box.currentChanged.connect(self.select_game)
        self.tool_box.setCurrentIndex(self.game_index)
        channel_list_area = QScrollArea()
        channel_list_area.setWidget(self.tool_box)
        h_layout1.addWidget(channel_list_area, 1)
        # 已选择的渠道列表
        self.cslv_model = QStringListModel()
        self.cslv_model.setStringList([])
        self.cslv = QListView()
        self.cslv.setModel(self.cslv_model)
        self.cslv.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.cslv.doubleClicked.connect(self.delete_channel)
        self.cslv.setContextMenuPolicy(Qt.CustomContextMenu)
        h_layout1.addWidget(self.cslv, 2)
        # 打包进度条显示列表
        self.qpb_list_widget = QListWidget()
        self.qpb_list_widget.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.qpb_list_widget.itemDoubleClicked.connect(self.select_qpb_list)
        h_layout1.addWidget(self.qpb_list_widget, 5)
        v_layout.addLayout(h_layout1)

        h_layout2 = QHBoxLayout()
        self.back_btn = QPushButton("返 回")
        self.back_btn.setFixedWidth(100)
        self.back_btn.clicked.connect(self.back)
        h_layout2.addWidget(self.back_btn,
                            alignment=Qt.AlignLeft | Qt.AlignBottom)

        h_layout2.addSpacing(100)
        select_apk_btn = QPushButton("选择母包:")
        select_apk_btn.setFixedWidth(100)
        select_apk_btn.clicked.connect(self.select_apk)
        h_layout2.addWidget(select_apk_btn)
        self.apk_path = QLabel()
        self.apk_path.setText("<h3><font color=%s>%s</font></h3>" %
                              ('red', "请浏览选择本地母包路径"))
        h_layout2.addWidget(self.apk_path)
        h_layout2.addSpacing(100)

        self.pack_btn = QPushButton("打 包")
        self.pack_btn.setFixedWidth(100)
        self.pack_btn.clicked.connect(self.click)
        h_layout2.addWidget(self.pack_btn,
                            alignment=Qt.AlignRight | Qt.AlignBottom)

        v_layout.addLayout(h_layout2)
        self.setLayout(v_layout)

    def select_game(self, p_int):
        self.game_index = p_int
        if 'apk' in self.main_win.games[self.game_index]:
            self.apk_path.setText(self.main_win.games[self.game_index]['apk'])
        else:
            self.apk_path.setText("<h3><font color=%s>%s</font></h3>" %
                                  ('red', "请浏览选择本地母包路径"))
            # self.apk_path.setText("请浏览选择本地母包路径")
        # 当前选中的game,其下的所有渠道列表
        self.channels = Utils.get_channels(
            Utils.get_full_path('games/' + self.main_win.games[p_int]['id'] +
                                '/config.xml'))
        channel_ids = []
        for channel in self.channels:
            channel_ids.append(channel['channelId'])
        list_model = QStringListModel()
        list_model.setStringList(channel_ids)
        self.clv = self.tool_box.currentWidget()
        self.clv.doubleClicked.connect(self.select_channel)
        self.clv.setModel(list_model)

    # 双击选中当前渠道,更新已选中列表的model
    def select_channel(self):
        if 'apk' not in self.main_win.games[self.game_index]:
            QMessageBox.warning(self, "警告", "请先添加母包!")
            return
        channel = self.channels[self.clv.currentIndex().row()]
        name = self.main_win.games[
            self.game_index]['id'] + '-' + channel['channelId']
        if name in self.selected_name:
            return
        self.selected_name.append(name)
        self.cslv_model.setStringList(self.selected_name)
        package = {
            'game': self.main_win.games[self.game_index],
            'channel': channel
        }
        self.selected.append(package)

    # 双击移除当前渠道,更新已选中列表的model
    def delete_channel(self):
        name = self.selected_name[self.cslv.currentIndex().row()]
        self.selected_name.remove(name)
        self.cslv_model.setStringList(self.selected_name)
        package = self.selected[self.cslv.currentIndex().row()]
        self.selected.remove(package)

    def select_qpb_list(self):
        index = self.qpb_list_widget.currentIndex().row()
        game_id = self.selected[index]['game']['id']
        channel_id = self.selected[index]['channel']['channelId']
        success = self.lbps[channel_id]['success']
        dest_apk_dir = Utils.get_full_path('output/' + game_id + '/' +
                                           channel_id)
        if success:
            os.startfile(dest_apk_dir)
        else:
            QMessageBox.warning(self, "警告", "打包成功了吗?")

    def back(self):
        self.monitor.deleteLater()
        self.main_win.set_main_widget()

    def select_apk(self):
        f_name = QFileDialog.getOpenFileName(
            self, '选择母包', os.path.join(os.path.expanduser('~'), "Desktop"),
            ("Apk (*.apk)"))
        if f_name[0]:
            self.apk_path.setStyleSheet("font-size:12px")
            self.apk_path.setText(f_name[0])
            self.main_win.games[self.game_index]['apk'] = f_name[0]

    def click(self):
        if self.pack_btn.text() == "打 包":
            self.package()
        elif self.pack_btn.text() == "取 消":
            self.cancel()

    def package(self):
        # 清空上次打包完成后的进度条显示列表
        count = self.qpb_list_widget.count()
        if count > 0:
            for i in range(count):
                item = self.qpb_list_widget.takeItem(0)
                del item

        if len(self.selected) <= 0:
            QMessageBox.warning(self, "警告", "请选择需要打包的渠道!")
            return
        for package in self.selected:
            # {"success": 是否成功, "label": 进度条文本view, "qpb": 进度条view, "runnable": 打包任务}
            lbp = {'success': False}
            self.set_qpb_list_item(package['channel']['channelId'], lbp)
            runnable = PackRunnable(package['game'], package['channel'],
                                    package['game']['apk'])
            runnable.signal.signal.connect(self.set_value)
            self.monitor.add_runnable(runnable)
            lbp['runnable'] = runnable
            self.lbps[package['channel']['channelId']] = lbp
        # 开启监听线程
        self.monitor.start()
        # 开始打包,不可返回,返回按钮禁用;设置打包按钮文本为"取 消"
        self.back_btn.setDisabled(True)
        self.pack_btn.setText("取 消")

    def set_qpb_list_item(self, channel_id, lbp):
        item = QListWidgetItem(self.qpb_list_widget)
        item.setSizeHint(QSize(400, 80))
        widget = QWidget(self.qpb_list_widget)
        v_layout = QVBoxLayout()
        label = QLabel(channel_id + "==>>>等待出包...")
        v_layout.addWidget(label)
        lbp['label'] = label
        qpb = QProgressBar(self.qpb_list_widget)
        v_layout.addWidget(qpb)
        lbp['qpb'] = qpb
        widget.setLayout(v_layout)
        self.qpb_list_widget.addItem(item)
        self.qpb_list_widget.setItemWidget(item, widget)

    def set_value(self, channel_id, result, msg, step):
        lbp = self.lbps[channel_id]
        if result:  # 打包步骤异常,提示异常,关闭进度条
            lbp['label'].setText(channel_id + "==>>>" + msg)
            lbp['qpb'].close()
            if step == 100:
                lbp['success'] = True
                self.lbps[channel_id] = lbp
        else:  # 打包正常,设置进度条进度
            lbp['qpb'].setValue(step)
            if step == 0:
                lbp['label'].setText(channel_id + "==>>>" + msg)

    # 取消打包(全部取消)
    def cancel(self):
        self.progress = QProgressDialog(self)
        self.progress.setFixedWidth(500)
        self.progress.setFixedHeight(80)
        self.progress.setWindowTitle("正在取消,请稍等...")
        self.progress.setCancelButtonText("取消")
        self.progress.setMinimumDuration(1)
        self.progress.setWindowModality(Qt.ApplicationModal)
        self.progress.setRange(0, 0)
        self.progress.show()
        # 清空进度条显示列表
        count = self.qpb_list_widget.count()
        for i in range(count):
            item = self.qpb_list_widget.takeItem(0)
            del item

        # 清空任务线程池;线程池清空后,会触发监听线程的完成信号,重置返回和打包按钮
        # 因为打包任务调用外部程序,并不能立即终止外部程序连接,所以清空过程有延迟
        for channel_id in self.lbps:
            self.lbps[channel_id]['runnable'].is_close = True
        self.monitor.clear()

    # 取消打包(清空任务完成),或打包完成,
    def complete(self):
        if self.progress is not None:
            self.progress.cancel()
        # 返回按钮解禁;设置打包按钮文本为"打 包"
        self.back_btn.setDisabled(False)
        self.pack_btn.setText("打 包")
class ChannelListWidget(QWidget):
    def __init__(self, main, channels):
        super(ChannelListWidget, self).__init__()
        self.main_win = main
        self.channels = channels
        self.channel_index = len(channels) - 1
        self.linedit_list = []
        self.channel_ids = []
        for channel in self.channels:
            self.channel_ids.append(channel['channelId'])
        self.channel_ids.append(" + 添加渠道")

        self.setObjectName("ChannelListWidget")

        v_layout1 = QVBoxLayout()
        h_layout1 = QHBoxLayout()
        self.list_model = QStringListModel()
        self.list_model.setStringList(self.channel_ids)
        self.channel_list_view = QListView()
        self.channel_list_view.setModel(self.list_model)
        self.channel_list_view.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        self.channel_list_view.clicked.connect(self.list_item_onclick)
        self.channel_list_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.channel_list_view.customContextMenuRequested.connect(
            self.show_del_menu)
        h_layout1.addWidget(self.channel_list_view, 1)

        self.channel = self.channels[self.channel_index]

        form_layout = QFormLayout()
        form_layout.setContentsMargins(10, 100, 10, 50)
        form_layout.addRow(
            "游戏ID:",
            QLabel(self.main_win.games[self.main_win.game_index]['id']))
        self.channel_id_value = QLabel(self.channel['channelId'])
        self.channel_id_value.setTextInteractionFlags(Qt.TextSelectableByMouse)
        form_layout.addRow("渠道ID:", self.channel_id_value)
        self.game_name_value = QLineEdit()
        form_layout.addRow("游戏名称:", self.game_name_value)
        self.game_package_value = QLineEdit()
        form_layout.addRow("游戏包名:", self.game_package_value)
        self.game_vcode_value = QLineEdit()
        form_layout.addRow("游戏版本号:", self.game_vcode_value)
        self.game_vname_value = QLineEdit()
        form_layout.addRow("游戏版本名:", self.game_vname_value)
        self.debug_value = QLineEdit()
        form_layout.addRow("打印日志:", self.debug_value)
        h_layout1.addLayout(form_layout, 4)

        self.form_layout2 = QFormLayout()
        self.form_layout2.setContentsMargins(10, 100, 10, 50)
        self.set_info()
        h_layout1.addLayout(self.form_layout2, 4)
        v_layout1.addLayout(h_layout1)

        h_layout2 = QHBoxLayout()
        back_btn = QPushButton("返 回")
        back_btn.setFixedWidth(100)
        back_btn.clicked.connect(self.back)
        h_layout2.addWidget(back_btn, alignment=Qt.AlignLeft | Qt.AlignBottom)

        save_btn = QPushButton("保 存")
        save_btn.setFixedWidth(100)
        save_btn.clicked.connect(self.save_data)
        h_layout2.addWidget(save_btn, alignment=Qt.AlignHCenter)

        pack_btn = QPushButton("打 包")
        pack_btn.setFixedWidth(100)
        pack_btn.clicked.connect(self.to_package)
        h_layout2.addWidget(pack_btn, alignment=Qt.AlignRight | Qt.AlignBottom)

        v_layout1.addLayout(h_layout2)
        self.setLayout(v_layout1)

    def set_info(self):
        self.channel_id_value.setText(self.channel['channelId'])
        self.game_name_value.setText(self.channel['gameName'])
        self.game_package_value.setText(self.channel['package'])
        self.game_vcode_value.setText(self.channel['gameVersionCode'])
        self.game_vname_value.setText(self.channel['gameVersionName'])
        self.debug_value.setText(self.channel['debug'])
        # 先清空之前渠道参数表单,再添加
        for i in range(self.form_layout2.rowCount()):
            # 因为formlayout清除一行,会自动上移,所以只需remove第一行
            self.form_layout2.removeRow(0)
        self.linedit_list.clear()
        # 再添加当前选择的渠道参数
        channel_name = QLabel(self.channel['name'] + '\t\t\tVersion:' +
                              self.channel['sdkVersionName'] + '\t\tUpdate:' +
                              self.channel['sdkUpdateTime'])
        channel_name.setAlignment(Qt.AlignRight)
        self.form_layout2.addRow(channel_name)
        for param in self.channel['sdkParams']:
            line_edit = QLineEdit(param['value'])
            self.form_layout2.addRow(param['showName'] + ':', line_edit)
            self.linedit_list.append(line_edit)

    def list_item_onclick(self):
        if self.channel_list_view.currentIndex().row() == len(
                self.channel_ids) - 1:
            self.main_win.set_add_channel_widget(self.channels, self.channel)
        else:
            self.channel_index = self.channel_list_view.currentIndex().row()
            self.channel = self.channels[self.channel_index]
            self.set_info()

    def back(self):
        self.main_win.set_game_list_widget(self.main_win.games)

    def to_package(self):
        if not self.save_data():
            return
        self.main_win.set_package_widget(self.channels)

    def save_data(self):
        self.channel['gameName'] = self.game_name_value.text().strip()
        self.channel['package'] = self.game_package_value.text().strip()
        self.channel['gameVersionCode'] = self.game_vcode_value.text().strip()
        self.channel['gameVersionName'] = self.game_vname_value.text().strip()
        self.channel['debug'] = self.debug_value.text().strip()
        i = 0
        while i < len(self.linedit_list):
            if self.linedit_list[i].text().strip() == "":
                QMessageBox.warning(self, "警告", "渠道参数不能为空!")
                return False
            self.channel['sdkParams'][i]['value'] = self.linedit_list[i].text(
            ).strip()
            i += 1
        self.channels[self.channel_index] = self.channel
        game_id = self.main_win.games[self.main_win.game_index]['id']
        return Utils.update_channels(
            Utils.get_full_path('games/' + game_id + '/config.xml'),
            self.channel, self.channel_index)

    def show_del_menu(self, point):
        self.list_item_onclick()
        if -1 < self.channel_index < len(self.channel_ids) - 1:
            menu = QMenu(self.channel_list_view)
            del_action = QAction("删 除", menu)
            del_action.triggered.connect(self.del_channel)
            menu.addAction(del_action)
            menu.popup(self.channel_list_view.mapToGlobal(point))

    def del_channel(self):
        reply = QMessageBox.warning(self, "警告", "确定删除当前渠道?",
                                    QMessageBox.Yes | QMessageBox.No,
                                    QMessageBox.No)
        if reply == QMessageBox.Yes:
            # 更新listview
            self.channel_ids.pop(self.channel_index)
            self.list_model.setStringList(self.channel_ids)
            # 更新表单view(index前移一位)
            self.channel = self.channels[self.channel_index - 1]
            self.set_info()
            # 更新本地数据
            self.channels.pop(self.channel_index)
            game_id = self.main_win.games[self.main_win.game_index]['id']
            Utils.del_channel(
                Utils.get_full_path('games/' + game_id + '/config.xml'),
                self.channel_index)
            # 重置index,防止 index out of range
            self.channel_index = self.channel_index - 1
            if self.channel_index < 0:
                reply = QMessageBox.warning(self, "警告", "当前游戏未添加渠道,将返回游戏列表界面!",
                                            QMessageBox.Yes)
                if reply == QMessageBox.Yes:
                    self.back()
Example #16
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
Example #17
-2
class ShortcutConfig(QWidget):
    def __init__(self, model, parent=None):
        QWidget.__init__(self, parent)
        self._layout = QHBoxLayout()
        self.setLayout(self._layout)
        self.view = QListView(self)
        self._layout.addWidget(self.view)
        self.view.setModel(model)
        self.delegate = Delegate()
        self.view.setItemDelegate(self.delegate)
        self.delegate.sizeHintChanged.connect(self.scrollTo, type=Qt.QueuedConnection)

    def scrollTo(self, index):
        self.view.scrollTo(index, self.view.EnsureVisible)

    @property
    def is_editing(self):
        return self.view.state() == self.view.EditingState