class SaveOption(Option):
    """docstring for Save."""

    saveOptionChanged = pyqtSignal(bool)

    def __init__(self, parent, autosaveStatus):
        super(SaveOption, self).__init__(parent)
        self.__autosaveStatus = autosaveStatus

        self.checkBox = QCheckBox(self)
        self.checkBox.setTristate(False)
        self.checkBox.setChecked(self.__autosaveStatus)
        self.checkBox.setText("Autosave")
        self.checkBox.setToolTip("Autosave")
        self.checkBox.stateChanged.connect(self.onCheckBoxStateChanged)
        self.addWidget(self.checkBox)

    def onCheckBoxStateChanged(self, state):
        self.saveOptionChanged.emit(self.checkBox.isChecked())

    def rollback(self):
        self.onCheckBoxStateChanged(self.__autosaveStatus)

    def commit(self):
        self.__autosaveStatus = self.checkBox.isChecked()
Exemple #2
0
class UpdateNotification(QDialog):
    def __init__(self, calibre_version, plugin_updates, parent=None):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_QuitOnClose, False)
        self.resize(400, 250)
        self.l = QGridLayout()
        self.setLayout(self.l)
        self.logo = QLabel()
        self.logo.setMaximumWidth(110)
        self.logo.setPixmap(QIcon(I('lt.png')).pixmap(100, 100))
        ver = calibre_version
        if ver.endswith('.0'):
            ver = ver[:-2]
        self.label = QLabel(
            ('<p>' +
             _('New version <b>{ver}</b> of {app} is available for download. '
               'See the <a href="{url}">new features</a>.').format(
                   url=localize_website_link(
                       'https://calibre-ebook.com/whats-new'),
                   app=__appname__,
                   ver=ver)))
        self.label.setOpenExternalLinks(True)
        self.label.setWordWrap(True)
        self.setWindowTitle(_('Update available!'))
        self.setWindowIcon(QIcon(I('lt.png')))
        self.l.addWidget(self.logo, 0, 0)
        self.l.addWidget(self.label, 0, 1)
        self.cb = QCheckBox(_('Show this notification for future updates'),
                            self)
        self.l.addWidget(self.cb, 1, 0, 1, -1)
        self.cb.setChecked(config.get('new_version_notification'))
        self.cb.stateChanged.connect(self.show_future)
        self.bb = QDialogButtonBox(self)
        b = self.bb.addButton(_('&Get update'), self.bb.AcceptRole)
        b.setDefault(True)
        b.setIcon(QIcon(I('arrow-down.png')))
        if plugin_updates > 0:
            b = self.bb.addButton(_('Update &plugins'), self.bb.ActionRole)
            b.setIcon(QIcon(I('plugins/plugin_updater.png')))
            b.clicked.connect(self.get_plugins, type=Qt.QueuedConnection)
        self.bb.addButton(self.bb.Cancel)
        self.l.addWidget(self.bb, 2, 0, 1, -1)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        dynamic.set('update to version %s' % calibre_version, False)

    def get_plugins(self):
        from calibre.gui2.dialogs.plugin_updater import (
            PluginUpdaterDialog, FILTER_UPDATE_AVAILABLE)
        d = PluginUpdaterDialog(self.parent(),
                                initial_filter=FILTER_UPDATE_AVAILABLE)
        d.exec_()

    def show_future(self, *args):
        config.set('new_version_notification', bool(self.cb.isChecked()))

    def accept(self):
        open_url(QUrl(get_download_url()))

        QDialog.accept(self)
Exemple #3
0
class UpdateNotification(QDialog):

    def __init__(self, calibre_version, plugin_updates, parent=None):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_QuitOnClose, False)
        self.resize(400, 250)
        self.l = QGridLayout()
        self.setLayout(self.l)
        self.logo = QLabel()
        self.logo.setMaximumWidth(110)
        self.logo.setPixmap(QPixmap(I('lt.png')).scaled(100, 100,
            Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
        ver = calibre_version
        if ver.endswith('.0'):
            ver = ver[:-2]
        self.label = QLabel(('<p>'+
            _('New version <b>%(ver)s</b> of %(app)s is available for download. '
            'See the <a href="http://calibre-ebook.com/whats-new'
            '">new features</a>.'))%dict(
                app=__appname__, ver=ver))
        self.label.setOpenExternalLinks(True)
        self.label.setWordWrap(True)
        self.setWindowTitle(_('Update available!'))
        self.setWindowIcon(QIcon(I('lt.png')))
        self.l.addWidget(self.logo, 0, 0)
        self.l.addWidget(self.label, 0, 1)
        self.cb = QCheckBox(
            _('Show this notification for future updates'), self)
        self.l.addWidget(self.cb, 1, 0, 1, -1)
        self.cb.setChecked(config.get('new_version_notification'))
        self.cb.stateChanged.connect(self.show_future)
        self.bb = QDialogButtonBox(self)
        b = self.bb.addButton(_('&Get update'), self.bb.AcceptRole)
        b.setDefault(True)
        b.setIcon(QIcon(I('arrow-down.png')))
        if plugin_updates > 0:
            b = self.bb.addButton(_('Update &plugins'), self.bb.ActionRole)
            b.setIcon(QIcon(I('plugins/plugin_updater.png')))
            b.clicked.connect(self.get_plugins, type=Qt.QueuedConnection)
        self.bb.addButton(self.bb.Cancel)
        self.l.addWidget(self.bb, 2, 0, 1, -1)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        dynamic.set('update to version %s'%calibre_version, False)

    def get_plugins(self):
        from calibre.gui2.dialogs.plugin_updater import (PluginUpdaterDialog,
            FILTER_UPDATE_AVAILABLE)
        d = PluginUpdaterDialog(self.parent(),
                initial_filter=FILTER_UPDATE_AVAILABLE)
        d.exec_()

    def show_future(self, *args):
        config.set('new_version_notification', bool(self.cb.isChecked()))

    def accept(self):
        open_url(QUrl(get_download_url()))

        QDialog.accept(self)
Exemple #4
0
class ConfigWidget(QWidget):
    def __init__(self):
        super().__init__()

        vl = QVBoxLayout()
        self.setLayout(vl)

        self.search_people_box = QCheckBox('Search people')
        self.search_people_box.setChecked(prefs['search_people'])
        vl.addWidget(self.search_people_box)

        model_size_hl = QHBoxLayout()
        model_size_label = QLabel('spaCy model size')
        self.model_size_box = QComboBox()
        for size in ['sm', 'md', 'lg']:
            self.model_size_box.addItem(size)
        self.model_size_box.setCurrentText(prefs['model_size'])
        model_size_hl.addWidget(model_size_label)
        model_size_hl.addWidget(self.model_size_box)
        vl.addLayout(model_size_hl)

        zh_wiki_hl = QHBoxLayout()
        zh_label = QLabel('Chinese Wikipedia variant')
        self.zh_wiki_box = QComboBox()
        zh_variants = {
            'cn': '大陆简体',
            'hk': '香港繁體',
            'mo': '澳門繁體',
            'my': '大马简体',
            'sg': '新加坡简体',
            'tw': '臺灣正體'
        }
        for variant, text in zh_variants.items():
            self.zh_wiki_box.addItem(text, variant)
        self.zh_wiki_box.setCurrentText(zh_variants[prefs['zh_wiki_variant']])
        zh_wiki_hl.addWidget(zh_label)
        zh_wiki_hl.addWidget(self.zh_wiki_box)
        vl.addLayout(zh_wiki_hl)

        donate_button = QPushButton('Donate')
        donate_button.clicked.connect(self.donate)
        vl.addWidget(donate_button)

        github_button = QPushButton('Source code')
        github_button.clicked.connect(self.github)
        vl.addWidget(github_button)

    @staticmethod
    def donate():
        webbrowser.open('https://liberapay.com/xxyzz/donate')

    def github(self):
        webbrowser.open('https://github.com/xxyzz/WordDumb')

    def save_settings(self):
        prefs['search_people'] = self.search_people_box.isChecked()
        prefs['model_size'] = self.model_size_box.currentText()
        prefs['zh_wiki_variant'] = self.zh_wiki_box.currentData()
Exemple #5
0
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.layout = QGridLayout()
        self.setLayout(self.layout)
        labelColumnWidths = []

        self.opdsUrlLabel = QLabel('OPDS URL: ')
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(
            self.layout.itemAtPosition(0, 0).sizeHint().width())

        print(type(prefs.defaults['opds_url']))
        print(type(prefs['opds_url']))
        convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.addItems(prefs['opds_url'])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        self.hideNewsCheckbox = QCheckBox('Hide Newspapers', self)
        self.hideNewsCheckbox.setChecked(prefs['hideNewspapers'])
        self.layout.addWidget(self.hideNewsCheckbox, 1, 0)
        labelColumnWidths.append(
            self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox(
            'Hide books already in library', self)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(
            prefs['hideBooksAlreadyInLibrary'])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 2, 0)
        labelColumnWidths.append(
            self.layout.itemAtPosition(2, 0).sizeHint().width())

        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(1, labelColumnWidth * 2)

    def save_settings(self):
        prefs['hideNewspapers'] = self.hideNewsCheckbox.isChecked()
        prefs[
            'hideBooksAlreadyInLibrary'] = self.hideBooksAlreadyInLibraryCheckbox.isChecked(
            )
        prefs['opds_url'] = saveOpdsUrlCombobox(self.opdsUrlEditor)
Exemple #6
0
    def do_user_config(self, parent=None):
        '''
        This method shows a configuration dialog for this plugin. It returns
        True if the user clicks OK, False otherwise. The changes are
        automatically applied.
        '''
        from PyQt5.Qt import (QDialog, QDialogButtonBox, QVBoxLayout, QLabel,
                              Qt, QLineEdit, QCheckBox)

        config_dialog = QDialog(parent)
        button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok
                                      | QDialogButtonBox.StandardButton.Cancel)
        v = QVBoxLayout(config_dialog)

        def size_dialog():
            config_dialog.resize(config_dialog.sizeHint())

        button_box.accepted.connect(config_dialog.accept)
        button_box.rejected.connect(config_dialog.reject)
        config_dialog.setWindowTitle(_('Customize') + ' ' + self.name)
        from calibre.customize.ui import (plugin_customization,
                                          customize_plugin)
        help_text = self.customization_help(gui=True)
        help_text = QLabel(help_text, config_dialog)
        help_text.setWordWrap(True)
        help_text.setTextInteractionFlags(
            Qt.TextInteractionFlag.LinksAccessibleByMouse
            | Qt.TextInteractionFlag.LinksAccessibleByKeyboard)
        help_text.setOpenExternalLinks(True)
        v.addWidget(help_text)
        bf = QCheckBox(_('Add linked files in breadth first order'))
        bf.setToolTip(
            _('Normally, when following links in HTML files'
              ' calibre does it depth first, i.e. if file A links to B and '
              ' C, but B links to D, the files are added in the order A, B, D, C. '
              ' With this option, they will instead be added as A, B, C, D'))
        sc = plugin_customization(self)
        if not sc:
            sc = ''
        sc = sc.strip()
        enc = sc.partition('|')[0]
        bfs = sc.partition('|')[-1]
        bf.setChecked(bfs == 'bf')
        sc = QLineEdit(enc, config_dialog)
        v.addWidget(sc)
        v.addWidget(bf)
        v.addWidget(button_box)
        size_dialog()
        config_dialog.exec_()

        if config_dialog.result() == QDialog.DialogCode.Accepted:
            sc = unicode_type(sc.text()).strip()
            if bf.isChecked():
                sc += '|bf'
            customize_plugin(self, sc)

        return config_dialog.result()
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.cbox1 = QCheckBox("Reformatting")
        self.cbox1.setChecked(prefs["reformat"])
        self.l.addWidget(self.cbox1)

        self.cbox5 = QCheckBox("Paragraph by Ending mark")
        self.cbox5.setChecked(prefs["para_by_mark"])
        self.l.addWidget(self.cbox5)

        self.cbox2 = QCheckBox("Pretty Quote char")
        self.cbox2.setChecked(prefs["pretty_quote"])
        self.l.addWidget(self.cbox2)

        self.cbox3 = QCheckBox("Guess Chapter")
        self.cbox3.setChecked(prefs["guess_chapter"])
        self.l.addWidget(self.cbox3)

        self.cbox4 = QCheckBox("Allow Empty Paragraph")
        self.cbox4.setChecked(prefs["insert_empty_paragraph"])
        self.l.addWidget(self.cbox4)

        cl = QHBoxLayout()
        cl.addWidget(QLabel("Broken Word over lines"))
        self.combo1 = QComboBox()
        wbrk_list = ["None", "Pattern", "Naver"]
        self.combo1.addItems(wbrk_list)
        self.combo1.setCurrentIndex(wbrk_list.index(prefs["correct_word_break"]))
        cl.addWidget(self.combo1)
        self.l.addLayout(cl)

    def save_settings(self):
        prefs["reformat"] = self.cbox1.isChecked()
        prefs["para_by_mark"] = self.cbox5.isChecked()
        prefs["pretty_quote"] = self.cbox2.isChecked()
        prefs["guess_chapter"] = self.cbox3.isChecked()
        prefs["insert_empty_paragraph"] = self.cbox4.isChecked()
        prefs["correct_word_break"] = str(self.combo1.currentText())
Exemple #8
0
    def do_user_config(self, parent=None):
        '''
        This method shows a configuration dialog for this plugin. It returns
        True if the user clicks OK, False otherwise. The changes are
        automatically applied.
        '''
        from PyQt5.Qt import (QDialog, QDialogButtonBox, QVBoxLayout,
                QLabel, Qt, QLineEdit, QCheckBox)

        config_dialog = QDialog(parent)
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        v = QVBoxLayout(config_dialog)

        def size_dialog():
            config_dialog.resize(config_dialog.sizeHint())

        button_box.accepted.connect(config_dialog.accept)
        button_box.rejected.connect(config_dialog.reject)
        config_dialog.setWindowTitle(_('Customize') + ' ' + self.name)
        from calibre.customize.ui import (plugin_customization,
                customize_plugin)
        help_text = self.customization_help(gui=True)
        help_text = QLabel(help_text, config_dialog)
        help_text.setWordWrap(True)
        help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse
                | Qt.LinksAccessibleByKeyboard)
        help_text.setOpenExternalLinks(True)
        v.addWidget(help_text)
        bf = QCheckBox(_('Add linked files in breadth first order'))
        bf.setToolTip(_('Normally, when following links in HTML files'
            ' calibre does it depth first, i.e. if file A links to B and '
            ' C, but B links to D, the files are added in the order A, B, D, C. '
            ' With this option, they will instead be added as A, B, C, D'))
        sc = plugin_customization(self)
        if not sc:
            sc = ''
        sc = sc.strip()
        enc = sc.partition('|')[0]
        bfs = sc.partition('|')[-1]
        bf.setChecked(bfs == 'bf')
        sc = QLineEdit(enc, config_dialog)
        v.addWidget(sc)
        v.addWidget(bf)
        v.addWidget(button_box)
        size_dialog()
        config_dialog.exec_()

        if config_dialog.result() == QDialog.Accepted:
            sc = unicode(sc.text()).strip()
            if bf.isChecked():
                sc += '|bf'
            customize_plugin(self, sc)

        return config_dialog.result()
Exemple #9
0
class ConfigWidget(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.layout = QGridLayout()
        self.setLayout(self.layout)
        labelColumnWidths = []

        self.opdsUrlLabel = QLabel('OPDS URL: ')
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(0, 0).sizeHint().width())

        print type(prefs.defaults['opds_url'])
        print type(prefs['opds_url'])
        convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.addItems(prefs['opds_url'])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        self.hideNewsCheckbox = QCheckBox('Hide Newspapers', self)
        self.hideNewsCheckbox.setChecked(prefs['hideNewspapers'])
        self.layout.addWidget(self.hideNewsCheckbox, 1, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox('Hide books already in library', self)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(prefs['hideBooksAlreadyInLibrary'])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 2, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(2, 0).sizeHint().width())

        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(1, labelColumnWidth * 2)

    def save_settings(self):
        prefs['hideNewspapers'] = self.hideNewsCheckbox.isChecked()
        prefs['hideBooksAlreadyInLibrary'] = self.hideBooksAlreadyInLibraryCheckbox.isChecked()
        prefs['opds_url'] = saveOpdsUrlCombobox(self.opdsUrlEditor)
def createGuiControls():
    gb = QGroupBox("GUI Controls")

    #-------------------------------------------------

    layout = QVBoxLayout()

    drawShadow_cb = QCheckBox("Draw Shadow")
    drawRotatingVector_cb = QCheckBox("Draw Rotating Vector and projection")

    drawShadow_cb.setChecked(tracker.draw_shadow)
    drawRotatingVector_cb.setChecked(tracker.draw_rotating_vector)

    drawShadow_cb.stateChanged.connect(
        lambda: tracker.show_shadow(drawShadow_cb.isChecked()))
    drawRotatingVector_cb.stateChanged.connect(
        lambda: tracker.show_rotating_vector(drawRotatingVector_cb.isChecked()
                                             ))

    layout.setContentsMargins(0, 0, 0, 0)
    layout.setSpacing(0)

    layout.addWidget(drawShadow_cb)
    layout.addWidget(drawRotatingVector_cb)

    upper = QWidget()
    upper.setLayout(layout)

    #-------------------------------------------------

    vbox = QVBoxLayout()

    vbox.setContentsMargins(0, 0, 0, 0)
    vbox.setSpacing(0)

    vbox.addWidget(upper)
    vbox.addStretch(1)
    gb.setLayout(vbox)
    return gb
class LockSeriesDialog(SizePersistedDialog):
    def __init__(self, parent, title, initial_value):
        SizePersistedDialog.__init__(
            self, parent, 'Manage Series plugin:lock series dialog')
        self.initialize_controls(title, initial_value)

        # Cause our dialog size to be restored from prefs or created on first usage
        self.resize_dialog()

    def initialize_controls(self, title, initial_value):
        self.setWindowTitle('Lock Series Index')
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        title_layout = ImageTitleLayout(self, 'images/lock32.png',
                                        'Lock Series Index')
        layout.addLayout(title_layout)

        layout.addSpacing(10)
        self.title_label = QLabel('Series index for book: \'%s\'' % title,
                                  self)
        layout.addWidget(self.title_label)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.value_spinbox = QDoubleSpinBox(self)
        self.value_spinbox.setRange(0, 99000000)
        self.value_spinbox.setDecimals(2)
        if initial_value is not None:
            self.value_spinbox.setValue(initial_value)
        self.value_spinbox.selectAll()
        hlayout.addWidget(self.value_spinbox, 0)
        hlayout.addStretch(1)

        self.assign_same_checkbox = QCheckBox(
            '&Assign this index value to all remaining books', self)
        layout.addWidget(self.assign_same_checkbox)
        layout.addStretch(1)

        # Dialog buttons
        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)

    def get_value(self):
        return float(unicode(self.value_spinbox.value()))

    def assign_same_value(self):
        return self.assign_same_checkbox.isChecked()
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.spoilers = QCheckBox('Use spoilers when creating x-ray')
        self.spoilers.setChecked(prefs['spoilers'])
        self.l.addWidget(self.spoilers)

        self.send_to_device = QCheckBox('Send x-ray to device if connected')
        self.send_to_device.setChecked(prefs['send_to_device'])
        self.l.addWidget(self.send_to_device)

        self.create_xray_when_sending = QCheckBox('Create x-ray for files that don\'t already have them when sending to device')
        self.create_xray_when_sending.setChecked(prefs['create_xray_when_sending'])
        self.l.addWidget(self.create_xray_when_sending)

        self.book_types_to_create = QGroupBox()
        self.book_types_to_create.setTitle('Book types to create x-ray files for')
        self.book_types_to_create.setLayout(QHBoxLayout (self.book_types_to_create))

        self.mobi = QCheckBox('MOBI')
        self.mobi.setChecked(prefs['mobi'])
        self.book_types_to_create.layout().addWidget(self.mobi)

        self.azw3 = QCheckBox('AZW3')
        self.azw3.setChecked(prefs['azw3'])
        self.book_types_to_create.layout().addWidget(self.azw3)

        self.l.addWidget(self.book_types_to_create)

    def save_settings(self):
        prefs['spoilers'] = self.spoilers.isChecked()
        prefs['send_to_device'] = self.send_to_device.isChecked()
        prefs['create_xray_when_sending'] = self.create_xray_when_sending.isChecked()
        prefs['mobi'] = self.mobi.isChecked()
        prefs['azw3'] = self.azw3.isChecked()
Exemple #13
0
class AddOverDiscardDialog(QDialog):
    def __init__(self, parent, icon, text, over=True):
        QDialog.__init__(self, parent)
        self.state = None

        layout = QVBoxLayout(self)
        self.setLayout(layout)
        self.setWindowTitle(_('UnMerge Epub'))

        label = QLabel(text)
        label.setOpenExternalLinks(True)
        label.setWordWrap(True)
        layout.addWidget(label)

        self.applyall = QCheckBox(_('Apply to all EPUBs?'), self)
        self.applyall.setToolTip(
            _('Apply the same action to the rest of the EPUBs after this.'))
        layout.addWidget(self.applyall)

        button_box = QDialogButtonBox(self)
        button = button_box.addButton(_("Add"), button_box.AcceptRole)
        button.clicked.connect(self.add)

        if over:
            button = button_box.addButton(_("Overwrite"),
                                          button_box.AcceptRole)
            button.clicked.connect(self.over)

        button = button_box.addButton(_("Discard"), button_box.AcceptRole)
        button.clicked.connect(self.discard)
        button_box.accepted.connect(self.accept)

        layout.addWidget(button_box)

    def get_applyall(self):
        return self.applyall.isChecked()

    def add(self):
        self.state = "add"

    def over(self):
        self.state = "over"

    def discard(self):
        self.state = "discard"
Exemple #14
0
class AddOverDiscardDialog(QDialog):

    def __init__(self, parent, icon, text, over=True):
        QDialog.__init__(self, parent)
        self.state=None

        layout = QVBoxLayout(self)
        self.setLayout(layout)
        self.setWindowTitle(_('UnMerge Epub'))

        label = QLabel(text)
        label.setOpenExternalLinks(True)
        label.setWordWrap(True)
        layout.addWidget(label)

        self.applyall = QCheckBox(_('Apply to all EPUBs?'),self)
        self.applyall.setToolTip(_('Apply the same action to the rest of the EPUBs after this.'))
        layout.addWidget(self.applyall)

        button_box = QDialogButtonBox(self)
        button = button_box.addButton(_("Add"), button_box.AcceptRole)
        button.clicked.connect(self.add)

        if over:
            button = button_box.addButton(_("Overwrite"), button_box.AcceptRole)
            button.clicked.connect(self.over)

        button = button_box.addButton(_("Discard"), button_box.AcceptRole)
        button.clicked.connect(self.discard)
        button_box.accepted.connect(self.accept)

        layout.addWidget(button_box)

    def get_applyall(self):
        return self.applyall.isChecked()

    def add(self):
        self.state="add"

    def over(self):
        self.state="over"

    def discard(self):
        self.state="discard"
Exemple #15
0
class Choose(QDialog):
    def __init__(self, fmts, parent=None):
        QDialog.__init__(self, parent)
        self.l = l = QVBoxLayout(self)
        self.setLayout(l)
        self.setWindowTitle(_('Choose format to edit'))

        self.la = la = QLabel(
            _('This book has multiple formats that can be edited. Choose the format you want to edit.'
              ))
        l.addWidget(la)

        self.rem = QCheckBox(
            _('Always ask when more than one format is available'))
        self.rem.setChecked(True)
        l.addWidget(self.rem)

        self.bb = bb = QDialogButtonBox(self)
        l.addWidget(bb)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.buts = buts = []
        for fmt in fmts:
            b = bb.addButton(fmt.upper(), bb.AcceptRole)
            b.setObjectName(fmt)
            connect_lambda(
                b.clicked, self,
                lambda self: self.chosen(self.sender().objectName()))
            buts.append(b)

        self.fmt = None
        self.resize(self.sizeHint())

    def chosen(self, fmt):
        self.fmt = fmt

    def accept(self):
        from calibre.gui2.tweak_book import tprefs
        tprefs['choose_tweak_fmt'] = self.rem.isChecked()
        QDialog.accept(self)
Exemple #16
0
class PopOut(QDialog):
    '''
        Pop Out para modificar ou adicionar nome de um elemento na arvore
        '''
    def __init__(self, name, bOK=False):
        super().__init__()

        self.items = None, None

        self.setWindowFlags(Qt.FramelessWindowHint)

        self.lineEdit = QLineEdit(name)

        self.chbStore = QCheckBox()
        self.chbStore.setText("Guardar dados")
        self.chbStore.setChecked(bOK)

        self.pbOK = QPushButton()
        self.pbOK.setText("OK")
        self.pbOK.clicked.connect(self.getNewName)

        self.pbCancel = QPushButton()
        self.pbCancel.setText("Cancel")
        self.pbCancel.clicked.connect(self.close)

        layout = QVBoxLayout()
        layout.addWidget(self.lineEdit)
        layout.addWidget(self.chbStore)
        layout.addWidget(self.pbOK)
        layout.addWidget(self.pbCancel)

        self.setLayout(layout)

    def getNewName(self):
        nome = self.lineEdit.text()
        toStore = self.chbStore.isChecked()
        self.items = (nome, toStore)
        self.close()
Exemple #17
0
class Choose(QDialog):

    def __init__(self, fmts, parent=None):
        QDialog.__init__(self, parent)
        self.l = l = QVBoxLayout(self)
        self.setLayout(l)
        self.setWindowTitle(_('Choose format to edit'))

        self.la = la = QLabel(_(
            'This book has multiple formats that can be edited. Choose the format you want to edit.'))
        l.addWidget(la)

        self.rem = QCheckBox(_('Always ask when more than one format is available'))
        self.rem.setChecked(True)
        l.addWidget(self.rem)

        self.bb = bb = QDialogButtonBox(self)
        l.addWidget(bb)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.buts = buts = []
        for fmt in fmts:
            b = bb.addButton(fmt.upper(), bb.AcceptRole)
            b.setObjectName(fmt)
            connect_lambda(b.clicked, self, lambda self: self.chosen(self.sender().objectName()))
            buts.append(b)

        self.fmt = None
        self.resize(self.sizeHint())

    def chosen(self, fmt):
        self.fmt = fmt

    def accept(self):
        from calibre.gui2.tweak_book import tprefs
        tprefs['choose_tweak_fmt'] = self.rem.isChecked()
        QDialog.accept(self)
Exemple #18
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self)
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
        self.details.linkClicked.connect(self.link_clicked)
        s = self.details.page().settings()
        s.setAttribute(s.JavascriptEnabled, False)
        self.css = css()
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.page().setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(gprefs.get('book_info_dialog_fit_cover', True))
        l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1)
        self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(_('Next [%s]')%
                unicode(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(_('Previous [%s]')%
                unicode(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width/2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def link_clicked(self, qurl):
        link = unicode(qurl.toString(NO_URL_FORMATTING))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()), bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        self.gui.refresh_cover_browser()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(pixmap.width(),
                    pixmap.height(), self.cover.size().width()-10,
                    self.cover.size().height()-10)
            if scaled:
                try:
                    dpr = self.devicePixelRatioF()
                except AttributeError:
                    dpr = self.devicePixelRatio()
                pixmap = pixmap.scaled(int(dpr * new_width), int(dpr * new_height),
                        Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(dpr)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {True, 'true'} else _(
                'This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d pixels')%dict(width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        try:
            dpr = self.devicePixelRatioF()
        except AttributeError:
            dpr = self.devicePixelRatio()
        self.cover_pixmap.setDevicePixelRatio(dpr)
        self.resize_cover()
        html = render_html(mi, self.css, True, self, all_fields=True)
        self.details.setHtml(html)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Exemple #19
0
class ProceedQuestion(QDialog):

    ask_question = pyqtSignal(object, object, object)

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('dialog_question.png')))

        self.questions = []

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

        self.icon_label = ic = QLabel(self)
        ic.setPixmap(QPixmap(I('dialog_question.png')))
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        ic.setMaximumWidth(110)
        ic.setMaximumHeight(100)
        ic.setScaledContents(True)
        ic.setStyleSheet('QLabel { margin-right: 10px }')
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                                             self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg,
                                                self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
            _('Show detailed information about this error'))
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes | self.bb.No | self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)

        self.checkbox = QCheckBox('', self)

        l.addWidget(ic, 0, 0, 1, 1)
        l.addWidget(msg, 0, 1, 1, 1)
        l.addWidget(self.checkbox, 1, 0, 1, 2)
        l.addWidget(self.det_msg, 2, 0, 1, 2)
        l.addWidget(self.bb, 3, 0, 1, 2)

        self.ask_question.connect(self.do_ask_question,
                                  type=Qt.QueuedConnection)

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
            'calibre, version %s\n%s: %s\n\n%s' %
            (__version__, unicode(self.windowTitle()),
             unicode(self.msg_label.text()), unicode(
                 self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(
            self.show_det_msg if vis else self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        if self.geom_pref:
            geom = gprefs.get(self.geom_pref, None)
            if geom:
                self.restoreGeometry(geom)
                return
        sz = self.sizeHint() + QSize(100, 0)
        sz.setWidth(min(500, sz.width()))
        sz.setHeight(min(500, sz.height()))
        self.resize(sz)

    def show_question(self):
        if self.isVisible():
            return
        if self.questions:
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.setWindowTitle(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(QIcon(
                ) if question.action_icon is None else question.action_icon)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.geom_pref = (
                'proceed question dialog:' +
                question.geom_pref) if question.geom_pref else None
            if question.show_det:
                self.toggle_det_msg()
            else:
                self.do_resize()
            self.show()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            button.setFocus(Qt.OtherFocusReason)

    def __call__(self,
                 callback,
                 payload,
                 html_log,
                 log_viewer_title,
                 title,
                 msg,
                 det_msg='',
                 show_copy_button=False,
                 cancel_callback=None,
                 log_is_file=False,
                 checkbox_msg=None,
                 checkbox_checked=False,
                 action_callback=None,
                 action_label=None,
                 action_icon=None,
                 focus_action=False,
                 show_det=False,
                 show_ok=False,
                 geom_pref=None):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param geom_pref: String for preference name to preserve dialog box geometry

        '''
        question = Question(payload, callback, cancel_callback, title, msg,
                            html_log, log_viewer_title, log_is_file, det_msg,
                            show_copy_button, checkbox_msg, checkbox_checked,
                            action_callback, action_label, action_icon,
                            focus_action, show_det, show_ok, geom_pref)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title, log, parent=self)
Exemple #20
0
class JobError(QDialog):  # {{{

    WIDTH = 600
    do_pop = pyqtSignal()

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
        self.queue = []
        self.do_pop.connect(self.pop, type=Qt.ConnectionType.QueuedConnection)

        self._layout = l = QGridLayout()
        self.setLayout(l)
        self.icon = QIcon(I('dialog_error.png'))
        self.setWindowIcon(self.icon)
        self.icon_widget = Icon(self)
        self.icon_widget.set_icon(self.icon)
        self.msg_label = QLabel('<p>&nbsp;')
        self.msg_label.setStyleSheet('QLabel { margin-top: 1ex; }')
        self.msg_label.setWordWrap(True)
        self.msg_label.setTextFormat(Qt.TextFormat.RichText)
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setVisible(False)

        self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close,
                                   parent=self)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                                            self.bb.ActionRole)
        self.ctc_button.clicked.connect(self.copy_to_clipboard)
        self.retry_button = self.bb.addButton(_('&Retry'), self.bb.ActionRole)
        self.retry_button.clicked.connect(self.retry)
        self.retry_func = None
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg,
                                                self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
            _('Show detailed information about this error'))
        self.suppress = QCheckBox(self)

        l.addWidget(self.icon_widget, 0, 0, 1, 1)
        l.addWidget(self.msg_label, 0, 1, 1, 1)
        l.addWidget(self.det_msg, 1, 0, 1, 2)
        l.addWidget(self.suppress, 2, 0, 1, 2,
                    Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBottom)
        l.addWidget(self.bb, 3, 0, 1, 2,
                    Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignBottom)
        l.setColumnStretch(1, 100)

        self.setModal(False)
        self.suppress.setVisible(False)
        self.do_resize()

    def retry(self):
        if self.retry_func is not None:
            self.accept()
            self.retry_func()

    def update_suppress_state(self):
        self.suppress.setText(
            ngettext('Hide the remaining error message',
                     'Hide the {} remaining error messages',
                     len(self.queue)).format(len(self.queue)))
        self.suppress.setVisible(len(self.queue) > 3)
        self.do_resize()

    def copy_to_clipboard(self, *args):
        d = QTextDocument()
        d.setHtml(self.msg_label.text())
        QApplication.clipboard().setText(
            'calibre, version %s (%s, embedded-python: %s)\n%s: %s\n\n%s' %
            (__version__, sys.platform, isfrozen,
             unicode_type(self.windowTitle()), unicode_type(
                 d.toPlainText()), unicode_type(self.det_msg.toPlainText())))
        if hasattr(self, 'ctc_button'):
            self.ctc_button.setText(_('Copied'))

    def toggle_det_msg(self, *args):
        vis = unicode_type(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(
            self.show_det_msg if vis else self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        h = self.sizeHint().height()
        self.setMinimumHeight(0)  # Needed as this gets set if det_msg is shown
        # Needed otherwise re-showing the box after showing det_msg causes the box
        # to not reduce in height
        self.setMaximumHeight(h)
        self.resize(QSize(self.WIDTH, h))

    def showEvent(self, ev):
        ret = QDialog.showEvent(self, ev)
        self.bb.button(self.bb.Close).setFocus(Qt.FocusReason.OtherFocusReason)
        return ret

    def show_error(self, title, msg, det_msg='', retry_func=None):
        self.queue.append((title, msg, det_msg, retry_func))
        self.update_suppress_state()
        self.pop()

    def pop(self):
        if not self.queue or self.isVisible():
            return
        title, msg, det_msg, retry_func = self.queue.pop(0)
        self.setWindowTitle(title)
        self.msg_label.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.det_msg_toggle.setText(self.show_det_msg)
        self.det_msg_toggle.setVisible(True)
        self.suppress.setChecked(False)
        self.update_suppress_state()
        if not det_msg:
            self.det_msg_toggle.setVisible(False)
        self.retry_button.setVisible(retry_func is not None)
        self.retry_func = retry_func
        self.do_resize()
        self.show()

    def done(self, r):
        if self.suppress.isChecked():
            self.queue = []
        QDialog.done(self, r)
        self.do_pop.emit()
class MainWidget(QWidget):
    signal_cut = pyqtSignal(str)
    def __init__(self,sizeX,sizeY, Parent=None):
        '''
        Constructor
        '''
        super().__init__(Parent)
        self.sizeX = sizeX
        self.sizeY = sizeY

        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()

    def refresh(self):
        QApplication.processEvents()
        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()

    def __InitData(self):
        '''
                  初始化成员变量
        '''
        self.paintBoard = PaintBoard(self.sizeX, self.sizeY)
        # 获取颜色列表(字符串类型)
        self.__colorList = QColor.colorNames()

    def __InitView(self):
        '''
                  初始化界面
        '''
        self.setFixedSize(640-480+self.sizeX, 480-460+self.sizeY)
        self.setWindowTitle("切割")

        # 新建一个水平布局作为本窗体的主布局
        main_layout = QHBoxLayout(self)
        # 设置主布局内边距以及控件间距为10px
        main_layout.setSpacing(10)

        # 在主界面左侧放置画板
        main_layout.addWidget(self.paintBoard)

        # 新建垂直子布局用于放置按键
        sub_layout = QVBoxLayout()

        # 设置此子布局和内部控件的间距为10px
        sub_layout.setContentsMargins(10, 10, 10, 10)

        self.__btn_Clear = QPushButton("清空画板")
        self.__btn_Clear.setParent(self)  # 设置父对象为本界面

        # 将按键按下信号与画板清空函数相关联
        self.__btn_Clear.clicked.connect(self.paintBoard.Clear)
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_Quit = QPushButton("确认")
        self.__btn_Quit.setParent(self)  # 设置父对象为本界面
        self.__btn_Quit.clicked.connect(self.Quit)
        sub_layout.addWidget(self.__btn_Quit)

        self.__btn_Save = QPushButton("保存作品")
        self.__btn_Save.setParent(self)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__cbtn_Eraser = QCheckBox("  使用橡皮擦")
        self.__cbtn_Eraser.setParent(self)
        self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        sub_layout.addWidget(self.__cbtn_Eraser)

        splitter = QSplitter(self)  # 占位符
        sub_layout.addWidget(splitter)

        self.__label_penThickness = QLabel(self)
        self.__label_penThickness.setText("画笔粗细")
        self.__label_penThickness.setFixedHeight(50)
        sub_layout.addWidget(self.__label_penThickness)

        self.__spinBox_penThickness = QSpinBox(self)
        self.__spinBox_penThickness.setMaximum(100)
        self.__spinBox_penThickness.setMinimum(2)
        self.__spinBox_penThickness.setValue(10)  # 默认粗细为10
        self.__spinBox_penThickness.setSingleStep(2)  # 最小变化值为2
        self.__spinBox_penThickness.valueChanged.connect(
            self.on_PenThicknessChange)  # 关联spinBox值变化信号和函数on_PenThicknessChange
        sub_layout.addWidget(self.__spinBox_penThickness)

        self.__label_penColor = QLabel(self)
        self.__label_penColor.setText("画笔颜色")
        self.__label_penColor.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penColor)

        self.__comboBox_penColor = QComboBox(self)
        self.__fillColorList(self.__comboBox_penColor)  # 用各种颜色填充下拉列表
        self.__comboBox_penColor.currentIndexChanged.connect(
            self.on_PenColorChange)  # 关联下拉列表的当前索引变更信号与函数on_PenColorChange
        sub_layout.addWidget(self.__comboBox_penColor)

        main_layout.addLayout(sub_layout)  # 将子布局加入主布局

    def __fillColorList(self, comboBox):

        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    def on_PenColorChange(self):
        color_index = self.__comboBox_penColor.currentIndex()
        color_str = self.__colorList[color_index]
        self.paintBoard.ChangePenColor(color_str)

    def on_PenThicknessChange(self):
        penThickness = self.__spinBox_penThickness.value()
        self.paintBoard.ChangePenThickness(penThickness)

    def on_btn_Save_Clicked(self):
        savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')
        print(savePath)
        if savePath[0] == "":
            print("Save cancel")
            return
        image = self.paintBoard.GetContentAsQImage()
        image.save(savePath[0])

    def on_cbtn_Eraser_clicked(self):
        if self.__cbtn_Eraser.isChecked():
            self.paintBoard.EraserMode = True  # 进入橡皮擦模式
        else:
            self.paintBoard.EraserMode = False  # 退出橡皮擦模式

    def Quit(self):
        self.signal_cut.emit(" ")
        self.close()
Exemple #22
0
class ExportKarmaDialog(QDialog):
    def __init__(self, parent, modal=True, flags=Qt.WindowFlags()):
        QDialog.__init__(self, parent, flags)
        self.model = None
        self.setModal(modal)
        self.setWindowTitle("Export Karma annotations")
        lo = QVBoxLayout(self)
        lo.setContentsMargins(10, 10, 10, 10)
        lo.setSpacing(5)
        # file selector
        self.wfile = FileSelector(self,
                                  label="Filename:",
                                  dialog_label="Karma annotations filename",
                                  default_suffix="ann",
                                  file_types="Karma annotations (*.ann)")
        lo.addWidget(self.wfile)
        # selected sources checkbox
        self.wsel = QCheckBox("selected sources only", self)
        lo.addWidget(self.wsel)
        # OK/cancel buttons
        lo.addSpacing(10)
        lo2 = QHBoxLayout()
        lo.addLayout(lo2)
        lo2.setContentsMargins(5, 5, 5, 5)
        self.wokbtn = QPushButton("OK", self)
        self.wokbtn.setMinimumWidth(128)
        self.wokbtn.clicked.connect(self.accept)
        self.wokbtn.setEnabled(False)
        cancelbtn = QPushButton("Cancel", self)
        cancelbtn.setMinimumWidth(128)
        cancelbtn.clicked.connect(self.reject)
        lo2.addWidget(self.wokbtn)
        lo2.addStretch(1)
        lo2.addWidget(cancelbtn)
        self.setMinimumWidth(384)
        # signals
        self.wfile.valid.connect(self.wokbtn.setEnabled)
        # internal state
        self.qerrmsg = QErrorMessage(self)
        self._model_filename = None

    def setModel(self, model):
        self.model = model
        # set the default annotations filename, whenever a new model filename is set
        filename = self.model.filename()
        if filename and filename != self._model_filename:
            self._model_filename = filename
            self.wfile.setFilename(os.path.splitext(filename)[0] + ".ann")

    def accept(self):
        """Tries to export annotations, and closes the dialog if successful."""
        try:
            filename = self.wfile.filename()
            if os.path.exists(filename) and QMessageBox.question(
                    self, "Exporting Karma annotations",
                    "<P>Overwrite the file %s?</P>" % filename, QMessageBox.Yes
                    | QMessageBox.No, QMessageBox.Yes) != QMessageBox.Yes:
                return
            f = open(self.wfile.filename(), "wt")
            f.write('COORD W\nPA STANDARD\nCOLOR GREEN\nFONT hershey12\n')
            # source list
            if self.wsel.isChecked():
                sources = [src for src in self.model.sources if src.selected]
            else:
                sources = self.model.sources
            # calculate basis size for crosses (TODO: replace min_size with something more sensible, as this value is in degrees)
            brightnesses = [
                abs(src.brightness()) for src in sources
                if src.brightness() != 0
            ]
            min_bright = brightnesses and min(brightnesses)
            min_size = 0.01
            # loop over sources
            busy = BusyIndicator()
            for src in sources:
                ra = src.pos.ra / DEG
                dec = src.pos.dec / DEG
                # figure out source size
                if src.brightness() and min_bright:
                    ysize = (math.log10(abs(src.brightness())) -
                             math.log10(min_bright) + 1) * min_size
                else:
                    ysize = min_size
                xsize = ysize / (math.cos(src.pos.dec) or 1)
                # figure out source style
                style, label = self.model.getSourcePlotStyle(src)
                if style:
                    f.write('# %s\n' % src.name)
                    # write symbol for source
                    f.write('COLOR %s\n' % style.symbol_color)
                    if style.symbol == "plus":
                        f.write('CROSS %.12f %.12f %f %f\n' %
                                (ra, dec, xsize, ysize))
                    elif style.symbol == "cross":
                        f.write('CROSS %.12f %.12f %f %f 45\n' %
                                (ra, dec, ysize, ysize))
                    elif style.symbol == "circle":
                        f.write('CIRCLE %.12f %.12f %f\n' % (ra, dec, ysize))
                    elif style.symbol == "dot":
                        f.write('DOT %.12f %.12f\n' % (ra, dec))
                    elif style.symbol == "square":
                        f.write('CBOX %.12f %.12f %f %f\n' %
                                (ra, dec, xsize, ysize))
                    elif style.symbol == "diamond":
                        f.write('CBOX %.12f %.12f %f %f 45\n' %
                                (ra, dec, xsize, ysize))
                    # write label
                    if label:
                        f.write('FONT hershey%d\n' % (style.label_size * 2))
                        f.write('COLOR %s\n' % style.label_color)
                        f.write('TEXT %.12f %.12f %s\n' % (ra, dec, label))
            f.close()
        except IOError as err:
            busy.reset_cursor()
            self.qerrmsg.showMessage(
                "Error writing Karma annotations file %s: %s" %
                (filename, str(err)))
            return
        busy.reset_cursor()
        self.parent().showMessage(
            "Wrote Karma annotations for %d sources to file %s" %
            (len(sources), filename))
        return QDialog.accept(self)
Exemple #23
0
class OpdsDialog(QDialog):
    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db.new_api

        # The model for the book list
        self.model = OpdsBooksModel(None, self.dummy_books(), self.db)
        self.searchproxymodel = QSortFilterProxyModel(self)
        self.searchproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.searchproxymodel.setFilterKeyColumn(-1)
        self.searchproxymodel.setSourceModel(self.model)

        self.layout = QGridLayout()
        self.setLayout(self.layout)

        self.setWindowTitle("OPDS Client")
        self.setWindowIcon(icon)

        labelColumnWidths = []

        self.opdsUrlLabel = QLabel("OPDS URL: ")
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(0, 0).sizeHint().width())

        config.convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.activated.connect(self.opdsUrlEditorActivated)
        self.opdsUrlEditor.addItems(prefs["opds_url"])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1, 1, 3)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        buttonColumnNumber = 7
        buttonColumnWidths = []
        self.about_button = QPushButton("About", self)
        self.about_button.setAutoDefault(False)
        self.about_button.clicked.connect(self.about)
        self.layout.addWidget(self.about_button, 0, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(0, buttonColumnNumber).sizeHint().width()
        )

        # Initially download the catalogs found in the root catalog of the URL
        # selected at startup.  Fail quietly on failing to open the URL
        catalogsTuple = self.model.downloadOpdsRootCatalog(
            self.gui, self.opdsUrlEditor.currentText(), False
        )
        print(catalogsTuple)
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1]  # A dictionary of title->feedURL

        self.opdsCatalogSelectorLabel = QLabel("OPDS Catalog:")
        self.layout.addWidget(self.opdsCatalogSelectorLabel, 1, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.opdsCatalogSelector = QComboBox(self)
        self.opdsCatalogSelector.setEditable(False)
        self.opdsCatalogSelectorModel = QStringListModel(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setModel(self.opdsCatalogSelectorModel)
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)
        self.layout.addWidget(self.opdsCatalogSelector, 1, 1, 1, 3)

        self.download_opds_button = QPushButton("Download OPDS", self)
        self.download_opds_button.setAutoDefault(False)
        self.download_opds_button.clicked.connect(self.download_opds)
        self.layout.addWidget(self.download_opds_button, 1, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(1, buttonColumnNumber).sizeHint().width()
        )

        # Search GUI
        self.searchEditor = QLineEdit(self)
        self.searchEditor.returnPressed.connect(self.searchBookList)
        self.layout.addWidget(self.searchEditor, 2, buttonColumnNumber - 2, 1, 2)

        self.searchButton = QPushButton("Search", self)
        self.searchButton.setAutoDefault(False)
        self.searchButton.clicked.connect(self.searchBookList)
        self.layout.addWidget(self.searchButton, 2, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(2, buttonColumnNumber).sizeHint().width()
        )

        # The main book list
        self.library_view = QTableView(self)
        self.library_view.setAlternatingRowColors(True)
        self.library_view.setModel(self.searchproxymodel)
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.library_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.library_view.resizeColumnsToContents()
        self.layout.addWidget(self.library_view, 3, 0, 3, buttonColumnNumber + 1)

        self.hideNewsCheckbox = QCheckBox("Hide Newspapers", self)
        self.hideNewsCheckbox.clicked.connect(self.setHideNewspapers)
        self.hideNewsCheckbox.setChecked(prefs["hideNewspapers"])
        self.layout.addWidget(self.hideNewsCheckbox, 6, 0, 1, 3)

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox("Hide books already in library", self)
        self.hideBooksAlreadyInLibraryCheckbox.clicked.connect(self.setHideBooksAlreadyInLibrary)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(prefs["hideBooksAlreadyInLibrary"])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 7, 0, 1, 3)

        # Let the checkbox initial state control the filtering
        self.model.setFilterBooksThatAreNewspapers(self.hideNewsCheckbox.isChecked())
        self.model.setFilterBooksThatAreAlreadyInLibrary(
            self.hideBooksAlreadyInLibraryCheckbox.isChecked()
        )

        self.downloadButton = QPushButton("Download selected books", self)
        self.downloadButton.setAutoDefault(False)
        self.downloadButton.clicked.connect(self.downloadSelectedBooks)
        self.layout.addWidget(self.downloadButton, 6, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(6, buttonColumnNumber).sizeHint().width()
        )

        self.fixTimestampButton = QPushButton("Fix timestamps of selection", self)
        self.fixTimestampButton.setAutoDefault(False)
        self.fixTimestampButton.clicked.connect(self.fixBookTimestamps)
        self.layout.addWidget(self.fixTimestampButton, 7, buttonColumnNumber)
        buttonColumnWidths.append(
            self.layout.itemAtPosition(7, buttonColumnNumber).sizeHint().width()
        )

        # Make all columns of the grid layout the same width as the button column
        buttonColumnWidth = max(buttonColumnWidths)
        for columnNumber in range(0, buttonColumnNumber):
            self.layout.setColumnMinimumWidth(columnNumber, buttonColumnWidth)

        # Make sure the first column isn't wider than the labels it holds
        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(0, labelColumnWidth)

        self.resize(self.sizeHint())

    def opdsUrlEditorActivated(self, text):
        prefs["opds_url"] = config.saveOpdsUrlCombobox(self.opdsUrlEditor)
        catalogsTuple = self.model.downloadOpdsRootCatalog(
            self.gui, self.opdsUrlEditor.currentText(), True
        )
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1]  # A dictionary of title->feedURL
        self.opdsCatalogSelectorModel.setStringList(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)

    def setHideNewspapers(self, checked):
        prefs["hideNewspapers"] = checked
        self.model.setFilterBooksThatAreNewspapers(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def setHideBooksAlreadyInLibrary(self, checked):
        prefs["hideBooksAlreadyInLibrary"] = checked
        self.model.setFilterBooksThatAreAlreadyInLibrary(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def searchBookList(self):
        searchString = self.searchEditor.text()
        print("starting book list search for: %s" % searchString)
        self.searchproxymodel.setFilterFixedString(searchString)

    def about(self):
        text = get_resources("about.txt")
        QMessageBox.about(self, "About the OPDS Client plugin", text.decode("utf-8"))

    def download_opds(self):
        opdsCatalogUrl = self.currentOpdsCatalogs.get(self.opdsCatalogSelector.currentText(), None)
        if opdsCatalogUrl is None:
            # Just give up quietly
            return
        self.model.downloadOpdsCatalog(self.gui, opdsCatalogUrl)
        if self.model.isCalibreOpdsServer():
            self.model.downloadMetadataUsingCalibreRestApi(self.opdsUrlEditor.currentText())
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.resize(self.sizeHint())

    def config(self):
        self.do_user_config(parent=self)

    def downloadSelectedBooks(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.downloadBook(book)

    def downloadBook(self, book):
        if len(book.links) > 0:
            self.gui.download_ebook(book.links[0])

    def fixBookTimestamps(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.fixBookTimestamp(book)

    def fixBookTimestamp(self, book):
        bookTimestamp = book.timestamp
        identicalBookIds = self.findIdenticalBooksForBooksWithMultipleAuthors(book)
        bookIdToValMap = {}
        for identicalBookId in identicalBookIds:
            bookIdToValMap[identicalBookId] = bookTimestamp
        if len(bookIdToValMap) < 1:
            print("Failed to set timestamp of book: %s" % book)
        self.db.set_field("timestamp", bookIdToValMap)

    def findIdenticalBooksForBooksWithMultipleAuthors(self, book):
        authorsList = book.authors
        if len(authorsList) < 2:
            return self.db.find_identical_books(book)
        # Try matching the authors one by one
        identicalBookIds = set()
        for author in authorsList:
            singleAuthorBook = Metadata(book.title, [author])
            singleAuthorIdenticalBookIds = self.db.find_identical_books(singleAuthorBook)
            identicalBookIds = identicalBookIds.union(singleAuthorIdenticalBookIds)
        return identicalBookIds

    def dummy_books(self):
        dummy_author = " " * 40
        dummy_title = " " * 60
        books_list = []
        for line in range(1, 10):
            book = DynamicBook()
            book.author = dummy_author
            book.title = dummy_title
            book.updated = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00")
            book.id = ""
            books_list.append(book)
        return books_list

    def resizeAllLibraryViewLinesToHeaderHeight(self):
        rowHeight = self.library_view.horizontalHeader().height()
        for rowNumber in range(0, self.library_view.model().rowCount()):
            self.library_view.setRowHeight(rowNumber, rowHeight)
Exemple #24
0
class ConvertDialog(QDialog):

    hide_text = _('&Hide styles')
    show_text = _('&Show styles')
    prince_log = ''
    prince_file = ''
    prince_css = ''

    # GUI definition
    def __init__(self, mi, fmt, opf, oeb, icon):
        '''
        :param mi: The book metadata
        :param fmt: The source format used for conversion
        :param opf: The path to the OPF file
        :param oeb: An OEB object for the unpacked book
        :param icon: The window icon
        '''
        self.opf = opf
        self.oeb = oeb
        self.mi = mi
        # The unpacked book needs to be parsed before, to read the contents
        # of the prince-style file, if it exists
        self.parse()

        QDialog.__init__(self)

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowTitle(_('Convert to PDF with Prince'))
        self.setWindowIcon(icon)

        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.title_label = QLabel(_('<b>Title:</b> %s') % self.mi.title)
        self.l.addWidget(self.title_label)

        self.format_label = QLabel(_('<b>Source format:</b> %s') % fmt)
        self.l.addWidget(self.format_label)

        self.add_book = QCheckBox(_('&Add PDF to the book record'))
        self.add_book.setToolTip(_('<qt>Add the converted PDF to the selected book record</qt>'))
        self.add_book.setChecked(prefs['add_book'])
        self.add_book.stateChanged.connect(self.set_add_book)
        self.l.addWidget(self.add_book)

        self.ll = QHBoxLayout()
        self.ll.setAlignment(Qt.AlignLeft)
        self.l.addLayout(self.ll)

        self.label_css = QLabel(_('&Custom style:'))
        self.ll.addWidget(self.label_css)

        self.css_list = QComboBox()
        self.css_list.setToolTip(_('<qt>Select one style to use. Additional styles can be created in the plugin configuration</qt>'))
        for key in sorted(prefs['custom_CSS_list'], key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(prefs['default_CSS']))
        self.css_list.currentIndexChanged.connect(self.set_css)
        self.ll.addWidget(self.css_list)
        self.label_css.setBuddy(self.css_list)

        self.ll_ = QHBoxLayout()
        self.l.addLayout(self.ll_)

        self.label_args = QLabel(_('A&dditional command-line arguments:'))
        self.ll_.addWidget(self.label_args)

        self.args = QLineEdit(self)
        self.args.setText(prefs['custom_args_list'][prefs['default_CSS']])
        self.args.setToolTip(_('<qt>Specify additional command-line arguments for the conversion</qt>'))
        self.ll_.addWidget(self.args)
        self.label_args.setBuddy(self.args)

        self.css = QTabWidget()
        self.l.addWidget(self.css)

        self.css1 = TextEditWithTooltip(self, expected_geometry=(80,20))
        self.css1.setLineWrapMode(TextEditWithTooltip.NoWrap)
        self.css1.load_text(self.replace_templates(prefs['custom_CSS_list'][prefs['default_CSS']]),'css')
        self.css1.setToolTip(_('<qt>This stylesheet can be modified<br/>The default can be configured</qt>'))
        i = self.css.addTab(self.css1, _('C&ustom CSS'))
        self.css.setTabToolTip(i, _('<qt>Custom CSS stylesheet to be used for this conversion</qt>'))

        monofont = QFont('')
        monofont.setStyleHint(QFont.TypeWriter)

        if (self.prince_css):
            self.css2 = QPlainTextEdit()
            self.css2.setStyleSheet('* { font-family: monospace }')
            self.css2.setLineWrapMode(QPlainTextEdit.NoWrap)
            self.css2.setPlainText(self.prince_css)
            self.css2.setReadOnly(True)
            self.css2.setToolTip(_('<qt>This stylesheet cannot be modified</qt>'))
            i = self.css.addTab(self.css2, _('&Book CSS'))
            self.css.setTabToolTip(i, _('<qt>Book-specific CSS stylesheet included in the ebook file</qt>'))

        self.ll = QHBoxLayout()
        self.l.addLayout(self.ll)

        if (prefs['show_CSS']):
            self.toggle = QPushButton(self.hide_text, self)
        else:
            self.toggle = QPushButton(self.show_text, self)
        self.toggle.setToolTip(_('<qt>Show/hide the additional styles used for the conversion</qt>'))
        self.toggle.clicked.connect(self.toggle_tabs)

        self.convert = QPushButton(_('Con&vert'), self)
        self.convert.setToolTip(_('<qt>Run the conversion with Prince</qt>'))
        self.convert.setDefault(True)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Cancel)
        self.buttons.addButton(self.toggle, QDialogButtonBox.ResetRole)
        self.buttons.addButton(self.convert, QDialogButtonBox.AcceptRole)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.prince_convert)
        self.buttons.rejected.connect(self.reject)

        if (not prefs['show_CSS']):
            self.css.hide()
        self.adjustSize()

    def toggle_tabs(self):
        '''
        Enable/disable the CSS tabs, and store the setting
        '''
        if (self.css.isVisible()):
            self.css.hide()
            self.label_args.hide()
            self.args.hide()
            self.toggle.setText(self.show_text)
            self.adjustSize()
        else:
            self.css.show()
            self.label_args.show()
            self.args.show()
            self.toggle.setText(self.hide_text)
            self.adjustSize()
        prefs['show_CSS'] = self.css.isVisible()

    def set_add_book(self):
        '''
        Save the status of the add_book checkbox
        '''
        prefs['add_book'] = self.add_book.isChecked()

    def set_css(self):
        '''
        Fill the custom CSS text box with the selected stylesheet (and command-line arguments)
        '''
        style = unicode(self.css_list.currentText())
        self.css1.load_text(self.replace_templates(prefs['custom_CSS_list'][style]),'css')
        self.args.setText(prefs['custom_args_list'][style])
        prefs['default_CSS'] = style

    def parse(self):
        '''
        Parse the unpacked OPF file to find and read the prince-style file
        '''
        from calibre.constants import DEBUG
        from os.path import dirname, join
        from lxml import etree
        import codecs

        if DEBUG: print(_('Parsing book...'))
        opf_dir = dirname(self.opf)
        root = etree.parse(self.opf).getroot()
        metadata = root.find('{*}metadata')
        for meta in metadata.findall("{*}meta[@name='prince-style']"):
            prince_id = meta.get('content')
            for item in self.oeb.manifest:
                if (item.id == prince_id):
                    self.prince_file = item.href
                    break
        if (self.prince_file):
            fl = codecs.open(join(opf_dir, self.prince_file), 'rb', 'utf-8')
            self.prince_css = fl.read()
            fl.close()

    def replace_templates(self, text):
        '''
        Replace templates (enclosed by '@{@', '@}@') in the input text
        '''
        import re
        import json
        from calibre.ebooks.metadata.book.formatter import SafeFormat
        from calibre.constants import DEBUG

        matches = list(re.finditer('@{@(.+?)@}@',text,re.DOTALL))
        results = {}
        for match in reversed(matches):
            result = SafeFormat().safe_format(match.group(1), self.mi, ('EXCEPTION: '), self.mi)
            # Escape quotes, backslashes and newlines
            result = re.sub(r'''['"\\]''', r'\\\g<0>', result)
            result = re.sub('\n', r'\A ', result)
            results[match.group(1)] = result
            text = text[:match.start(0)] + result + text[match.end(0):]
        if DEBUG:
            print(_('Replacing templates'))
            for match in matches:
                print(_('Found: %s (%d-%d)') % (match.group(1), match.start(0), match.end(0)))
                print(_('Replace with: %s') % results[match.group(1)])
        return text

    def prince_convert(self):
        '''
        Call the actual Prince command to convert to PDF
        '''
        from os import makedirs
        from os.path import dirname, join, exists
        from calibre.ptempfile import PersistentTemporaryFile
        from calibre.constants import DEBUG
        from shlex import split as shsplit

        # All files are relative to the OPF location
        opf_dir = dirname(self.opf)
        base_dir = dirname(self.pdf_file)
        base_dir = join(opf_dir, base_dir)
        try:
            makedirs(base_dir)
        except BaseException:
            if not exists(base_dir): raise

        # Create a temporary CSS file with the box contents
        custom_CSS = PersistentTemporaryFile()
        custom_CSS.write(unicode(self.css1.toPlainText()))
        custom_CSS.close()
        # Create a temporary file with the list of input files
        file_list = PersistentTemporaryFile()
        for item in self.oeb.spine:
            file_list.write(item.href + "\n")
        file_list.close()
        # Build the command line
        command = prefs['prince_exe']
        args = ['-v']
        if self.prince_file:
            args.append('-s')
            args.append(self.prince_file)
        args.append('-s')
        args.append(custom_CSS.name)
        args.append('-l')
        args.append(file_list.name)
        args.append('-o')
        args.append(self.pdf_file)
        # Additional command-line arguments
        args.extend(shsplit(self.args.text()))

        # Hide the convert button and show a busy indicator
        self.convert.setEnabled(False)
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0,0)
        self.progress_bar.setValue(0)
        self.l.addWidget(self.progress_bar)

        # Run the command and return the path to the PDF file
        if DEBUG: print(_('Converting book...'))
        process = QProcess(self)
        process.setWorkingDirectory(opf_dir)
        process.setProcessChannelMode(QProcess.MergedChannels);
        process.error.connect(self.error)
        process.finished.connect(self.end)
        self.process = process
        if DEBUG:
          from subprocess import list2cmdline
          line = list2cmdline([command] + args)
          print(_('Command line: %s') % line)
        process.start(command, args)

    def error(self, rc):
        '''
        Show a message when there is an error in the command
        :param rc: The error code
        '''
        from calibre.gui2 import error_dialog

        # Remove the progress bar while the error message is displayed
        self.progress_bar.hide()
        self.progress_bar.deleteLater()
        error_dialog(self, _('Process error'), _('<p>Error code: %s'
            '<p>make sure Prince (<a href="http://www.princexml.com">www.princexml.com</a>) is installed '
            'and the correct command-line-interface executable is set in the configuration of this plugin, '
            'which is usually:'
            '<ul><li>In Windows: <code><i>Prince_folder</i>\\Engine\\bin\\prince.exe</code>'
            '    <li>In Linux: <code>prince</code>'
            '</ul>') % rc, show=True)
        self.pdf_file = None
        self.accept()

    def end(self, rc):
        '''
        Close and return the filename when the process ends
        :param rc: The return code (0 if successful)
        '''
        from os.path import join

        self.prince_log = unicode(self.process.readAllStandardOutput().data())
        opf_dir = unicode(self.process.workingDirectory())
        if (rc == 0):
            self.pdf_file = join(opf_dir, self.pdf_file)
        else:
            self.pdf_file = None
        self.accept()
Exemple #25
0
class MainWidget(QWidget):
    def __init__(self, Parent=None):

        super().__init__(Parent)

        self.__InitData()
        self.__InitView()
        f = open("params15000.json", "r")
        data = json.load(f)
        f.close()
        self.biase = np.array(data["biase"])
        self.w_in = np.array(data["w_in"])
        self.w_out = np.array(data["w_out"])

    def __InitData(self):

        self.__paintBoard = PaintBoard(self)
        self.__colorList = QColor.colorNames()

    def __InitView(self):

        # self.setFixedSize(640,480)
        # self.setFixedSize(480,410)
        self.setFixedSize(800, 618)
        self.setWindowTitle("基于ELM的快速手写识别软件NeuHandWriting (NeuHWR1.0)")
        self.setWindowIcon(QIcon('ICON.ico'))

        main_layout = QHBoxLayout(self)
        main_layout.setSpacing(10)

        main_layout.addWidget(self.__paintBoard)

        self.font = QtGui.QFont()
        self.font.setFamily("Consolas")
        self.font.setPointSize(15)

        sub_layout = QVBoxLayout()
        sub_layout.setContentsMargins(10, 10, 10, 10)

        self.__btn_Clear = QPushButton("Clear Board")
        self.__btn_Clear.setParent(self)
        self.__btn_Clear.setFixedSize(146, 70)
        self.__btn_Clear.setFont(self.font)
        self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_Quit = QPushButton("Exit")
        self.__btn_Quit.setParent(self)
        self.__btn_Quit.setFixedSize(146, 70)
        self.__btn_Quit.setFont(self.font)
        self.__btn_Quit.clicked.connect(self.Quit)
        sub_layout.addWidget(self.__btn_Quit)

        self.__btn_Save = QPushButton("Save Board")
        self.__btn_Save.setParent(self)
        self.__btn_Save.setFixedSize(146, 70)
        self.__btn_Save.setFont(self.font)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__cbtn_Eraser = QCheckBox("Eraser")
        self.__cbtn_Eraser.setParent(self)
        self.__cbtn_Eraser.setFont(self.font)
        self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        sub_layout.addWidget(self.__cbtn_Eraser)

        self.__label_result = QLabel(self)
        self.__label_result.setAlignment(Qt.AlignCenter)
        self.__label_result.setFixedWidth(146)
        self.__label_result.setFixedHeight(80)
        self.__label_result.setFrameStyle(PyQt5.QtWidgets.QFrame.Box)
        self.__label_result.setFrameShadow(PyQt5.QtWidgets.QFrame.Raised)
        self.__label_result.setLineWidth(6)
        self.__label_result.setMidLineWidth(5)
        self.__label_result.setStyleSheet('background-color: rgb(255,123,100)')
        sub_layout.addWidget(self.__label_result)

        self.__btn_Recognize = QPushButton("Recognition")
        self.__btn_Recognize.setParent(self)
        self.__btn_Recognize.setFixedSize(146, 70)
        self.__btn_Recognize.setFont(self.font)
        self.__btn_Recognize.clicked.connect(self.on_btn_Recognize_clicked)
        sub_layout.addWidget(self.__btn_Recognize)

        self.__label_timage = QLabel(self)
        self.__label_timage.setAlignment(Qt.AlignCenter)
        self.__label_timage.setFixedWidth(146)
        self.__label_timage.setFixedHeight(80)
        self.__label_timage.setFrameStyle(PyQt5.QtWidgets.QFrame.Box)
        self.__label_timage.setFrameShadow(PyQt5.QtWidgets.QFrame.Raised)
        self.__label_timage.setLineWidth(6)
        self.__label_timage.setMidLineWidth(5)
        self.__label_timage.setStyleSheet('background-color: rgb(125,143,50)')
        sub_layout.addWidget(self.__label_timage)

        self.__btn_Random = QPushButton("RandomDigit \nFrom TestSet")
        self.__btn_Random.setParent(self)
        self.__btn_Random.setFixedSize(146, 70)
        self.font.setPointSize(13)
        self.__btn_Random.setFont(self.font)
        self.__btn_Random.clicked.connect(self.on_btn_RandomDigit_Clicked)
        sub_layout.addWidget(self.__btn_Random)

        main_layout.addLayout(sub_layout)

    def __fillColorList(self, comboBox):

        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    def on_PenColorChange(self):
        color_index = self.__comboBox_penColor.currentIndex()
        color_str = self.__colorList[color_index]
        self.__paintBoard.ChangePenColor(color_str)

    def on_PenThicknessChange(self):
        penThickness = self.__spinBox_penThickness.value()
        self.__paintBoard.ChangePenThickness(penThickness)

    def on_btn_Save_Clicked(self):
        savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\',
                                               '*.png')
        print(savePath)
        if savePath[0] == "":
            print("Save cancel")
            return
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath[0])

    def on_cbtn_Eraser_clicked(self):
        if self.__cbtn_Eraser.isChecked():
            self.__paintBoard.EraserMode = True
        else:
            self.__paintBoard.EraserMode = False

    def on_btn_RandomDigit_Clicked(self):
        f = open('x_test_10000.pkl', 'rb')
        x_test = pickle.load(f, encoding='bytes')
        f.close()
        ff = open('y_test_10000.pkl', 'rb')
        y_test = pickle.load(ff, encoding='bytes')
        ff.close()
        random_id = random.randint(0, 9999)
        image = Image.fromarray(np.reshape(x_test[random_id],
                                           (28, 28)) * 255).convert('L')
        new_image = image.resize((44, 44))
        # new_image.show()
        new_image.save('tpic.png')
        pixmap = QPixmap('tpic.png')
        self.__label_timage.setPixmap(pixmap)
        print("begin")
        res = self.judge(np.reshape(x_test[random_id], (28, 28)))
        myres = "{0}|{1}".format(res, int(y_test[random_id]))

        # show my result
        font = QtGui.QFont()
        font.setFamily('Consolas')
        font.setBold(True)
        font.setPointSize(18)
        font.setWeight(75)
        self.__label_result.setFont(font)
        self.__label_result.setText(myres)

    def sigmoid(self, x):
        return 1.0 / (1.0 + np.exp(-x))

    def judge(self, input_v):
        fd = hog(input_v,
                 orientations=5,
                 pixels_per_cell=(4, 4),
                 cells_per_block=(3, 3),
                 block_norm='L1-sqrt',
                 transform_sqrt=True,
                 feature_vector=True,
                 visualise=False)
        length = len(fd)
        y_hat = np.dot(
            self.w_out,
            self.sigmoid(
                np.dot(self.w_in, np.reshape(fd, (length, 1))) +
                self.biase.transpose()))
        res_id = np.argmax(y_hat)
        y_hat[y_hat < 0] = 0
        prapability = y_hat[res_id] / np.sum(y_hat)
        myres = "{0}({1}%)".format(res_id, int(prapability * 100))
        print(myres)
        return myres

    def on_btn_Recognize_clicked(self):

        savePath = "tmp.png"
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath)

        t_image = Image.open(savePath).convert('L')
        newt_image = t_image.resize((28, 28))
        # newt_image.save("tmp1.png")
        np_image = np.array(newt_image) / 255.0
        # print (np_image.shape)
        # print (np_image)

        myres = self.judge(np_image)

        # show my result
        font = QtGui.QFont()
        font.setFamily('Consolas')
        font.setBold(True)
        font.setPointSize(20)
        font.setWeight(75)
        self.__label_result.setFont(font)
        self.__label_result.setText(myres)
        # print (myres)

    def Quit(self):
        self.close()
Exemple #26
0
class ConfigWidget(QWidget):
    def __init__(self):
        self.plugin_prefs = prefs
        self.restart_required = False
        self.inspector = None

        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        #add checkbox
        self.inspector_checkbox = QCheckBox('Show Inspector')
        self.inspector_checkbox.setChecked(
            self.plugin_prefs.get('inspector_enabled', False))
        self.inspector_checkbox.stateChanged.connect(
            self._inspector_enabled_changed)
        self.inspector_checkbox.setToolTip(
            'Enable Javascript Console for debugging WebView requests to QuietThyme API'
        )
        self.l.addWidget(self.inspector_checkbox)

        self.beta_checkbox = QCheckBox('Beta Mode')
        self.beta_checkbox.setChecked(self.plugin_prefs.get(
            'beta_mode', False))
        self.beta_checkbox.stateChanged.connect(self._set_restart_required)
        self.beta_checkbox.stateChanged.connect(self._beta_mode_changed)
        self.beta_checkbox.setToolTip(
            'Tell Calibre to communicate with the Beta version of QuietThyme')
        self.l.addWidget(self.beta_checkbox)

        self.config_url = QUrl(self.plugin_prefs.get('web_base') + '/storage')
        self.webview = QTWebView(bearer_token=self.plugin_prefs.get('token'))

        self.webview.load(self.config_url)
        self.global_settings = self.webview.page().settings(
        )  #QWebSettings.globalSettings()

        self.global_settings.setAttribute(
            QWebSettings.LocalStorageEnabled,
            True)  #required since this is where we store tokens.
        self.global_settings.setAttribute(QWebSettings.PrivateBrowsingEnabled,
                                          False)
        self.global_settings.setAttribute(QWebSettings.JavascriptEnabled, True)
        self.global_settings.setAttribute(
            QWebSettings.JavascriptCanOpenWindows, True)
        self.global_settings.setAttribute(
            QWebSettings.JavascriptCanCloseWindows, True)
        self.global_settings.setAttribute(QWebSettings.PluginsEnabled, True)
        self.global_settings.setAttribute(
            QWebSettings.LocalContentCanAccessRemoteUrls, True)
        self.global_settings.setAttribute(
            QWebSettings.LocalContentCanAccessFileUrls, True)
        self.global_settings.setAttribute(QWebSettings.XSSAuditingEnabled,
                                          False)
        self.global_settings.setAttribute(QWebSettings.DeveloperExtrasEnabled,
                                          True)

        # ensure that we get a random offline/localstorage/cache path for the brower (so that the localstorage data is not persistent across sessions)
        path = None
        while True:
            potential_path = QTemporaryDir()
            if potential_path.isValid():
                path = potential_path.path()
                break

        self.global_settings.setOfflineStoragePath(path)
        self.global_settings.setOfflineWebApplicationCachePath(path)
        self.global_settings.enablePersistentStorage(path)
        self.global_settings.setLocalStoragePath(path)

        self.webview.show()
        self.l.addWidget(self.webview)

        self.configure_webview_inspector_ui()

        self.webview.urlChanged.connect(self._url_changed)
        self.webview.loadFinished.connect(self._load_finished)

    ################################################################################################################
    # Configure UI methods
    #
    def configure_webview_inspector_ui(self):
        if self.plugin_prefs.get('inspector_enabled'):
            self.webview.setMinimumSize(QSize(600, 300))
            self.inspector = QWebInspector()
            self.inspector.setMinimumSize(QSize(600, 300))
            self.inspector.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Expanding)
            self.l.addWidget(self.inspector)
            self.inspector.setPage(self.webview.page())
        else:
            self.webview.setMinimumSize(QSize(600, 600))
            if self.inspector is not None:
                self.l.removeWidget(self.inspector)
                self.inspector.setParent(None)
                self.inspector = None

    def save_settings(self):
        self.plugin_prefs.set('inspector_enabled',
                              self.inspector_checkbox.isChecked())
        self.plugin_prefs.set('beta_mode', self.beta_checkbox.isChecked())

        # # If restart needed, inform user
        if self.restart_required:
            # do_restart = show_restart_warning('Restart calibre for the changes to be applied.',
            #                                   parent=self.l)
            # if do_restart:
            #     self.gui.quit(restart=True)

            # TODO: figure out if theres a way to call self.gui.quit()

            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)

            msg.setText("Restart Required")
            msg.setInformativeText(
                "A configuration change requires you to restart Calibre, You should do so now,"
            )
            msg.setWindowTitle("Restart Required")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()

    def validate(self):
        # TODO: validate the that the api_endpoint and web endpoint are valid urls.
        return True

    ################################################################################################################
    # Event Handlers
    #
    def _url_changed(self, url):
        logger.debug(sys._getframe().f_code.co_name, url)

    def _load_finished(self, ok):
        logger.debug(sys._getframe().f_code.co_name, ok)
        if self.webview.page().mainFrame().url() == self.config_url:
            logger.debug(
                "Loading finished and the url is the same as the desired destination url, ",
                self.config_url)
            self.webview.page().mainFrame().evaluateJavaScript("""
            console.log("GET LOCALSTORAGE TOKEN")
            """)
            token = self.webview.page().mainFrame().evaluateJavaScript("""
            localStorage.getItem('id_token');
            """)
            logger.debug("Got JWT Token", token)
            self.plugin_prefs.set('token', token)

    def _set_restart_required(self, state):
        '''
        Set restart_required flag to show show dialog when closing dialog
        '''

        logger.debug(sys._getframe().f_code.co_name, "restart required")
        self.restart_required = True

    def _beta_mode_changed(self, state):
        logger.debug(sys._getframe().f_code.co_name,
                     self.beta_checkbox.isChecked())
        self.plugin_prefs.set('beta_mode', self.beta_checkbox.isChecked())

        # if the beta mode has changed, we need to reset the api endpoints, and then wipe the token (not valid between envs)
        self.plugin_prefs.set('token', '')
        if self.plugin_prefs.get('beta_mode'):
            self.plugin_prefs.set('api_base', beta_api_base)
            self.plugin_prefs.set('web_base', beta_web_base)
        else:
            self.plugin_prefs.set('api_base', master_api_base)
            self.plugin_prefs.set('web_base', master_web_base)

        # after we reset the token, we need to generate a new QTWebView with the new config, and then reload the login page.
        self.config_url = QUrl(self.plugin_prefs.get('web_base') + '/storage')

        self.webview.set_bearer_token(self.plugin_prefs.get('token'))
        self.webview.load(self.config_url)

    def _inspector_enabled_changed(self, state):
        logger.debug(sys._getframe().f_code.co_name,
                     self.inspector_checkbox.isChecked())
        self.plugin_prefs.set('inspector_enabled',
                              self.inspector_checkbox.isChecked())
        self.configure_webview_inspector_ui()
Exemple #27
0
class MyWidget(QWidget):
    log = Logger('logs/main/main.log', level='info')
    METHOD_KERNEL = Kernel(log.logger)

    def __init__(self, Parant=None):
        super().__init__(Parant)
        self.__eraser_mode_set = False
        self.__init_data()
        self.__init_view()

    def __init_data(self):
        self.__canvas = PaintBoard(self)
        self.__colorList = QColor.colorNames()

    def __init_view(self):
        self.setFixedSize(720, 530)

        self.label_university = QLabel("学校:\t华南理工大学", self)
        self.label_university.setStyleSheet("font-size:12px")
        self.label_university.setGeometry(460, 10, 120, 35)

        self.label_school = QLabel("专业:\t控制科学与工程", self)
        self.label_school.setStyleSheet("font-size:12px")
        self.label_school.setGeometry(460, 40, 140, 35)

        self.label_name = QLabel("姓名:\t***", self)
        self.label_name.setStyleSheet("font-size:12px")
        self.label_name.setGeometry(460, 70, 100, 35)

        self.label_number = QLabel("学号:\t***", self)
        self.label_number.setStyleSheet("font-size:12px")
        self.label_number.setGeometry(460, 100, 120, 35)

        self.label_im = QLabel(self)
        self.label_im.setGeometry(600, 20, 105, 105)
        self.label_im.setPixmap(QPixmap("./im_scut.jpg").scaled(105, 105))

        self.label_log = QTextEdit(self)
        self.label_log.setReadOnly(True)
        # self.label_log.moveCursor(QTextCursor.Down)
        self.label_log.setStyleSheet(
            "background:transparent; font-size:15px; font-family:Roman times")
        # self.label_log.resize(220, 200)
        self.label_log.setGeometry(460, 140, 245, 220)
        self.label_log.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.label_log.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)

        # create a horizontal layout as the main layout of the GUI
        main_layout = QHBoxLayout(self)
        # set the distance between widgets to 10px
        main_layout.setSpacing(10)

        left_layout = QVBoxLayout()
        left_layout.setContentsMargins(5, 5, 5, 5)

        left_layout.addWidget(self.__canvas)

        path_layout = QHBoxLayout()
        path_layout.setContentsMargins(5, 5, 5, 5)

        self.__lab_path = QLabel(self)
        self.__lab_path.setText("Save Path")
        self.__lab_path.setFixedHeight(10)
        path_layout.addWidget(self.__lab_path)
        left_layout.addLayout(path_layout)

        self.__txt_path = QLineEdit("./data/1")
        path_layout.addWidget(self.__txt_path)

        self.__choose_path = QPushButton("index")
        self.__choose_path.setParent(self)
        # self.__choose_path.setShortcut("Ctrl+S")
        self.__choose_path.clicked.connect(self.btn_save_clicked)
        path_layout.addWidget(self.__choose_path)

        btn_layout = QHBoxLayout()
        btn_layout.setContentsMargins(5, 5, 5, 5)

        self.__btn_save = QPushButton("Save")
        self.__btn_save.setParent(self)
        self.__btn_save.setShortcut("Ctrl+A")
        self.__btn_save.clicked.connect(self.save_image)
        btn_layout.addWidget(self.__btn_save)

        self.__btn_recognize = QPushButton("Predict")
        self.__btn_recognize.setParent(self)
        self.__btn_recognize.setShortcut("Ctrl+R")
        self.__btn_recognize.clicked.connect(self.btn_recog_clicked)
        btn_layout.addWidget(self.__btn_recognize)

        self.__btn_clear = QPushButton("Clear")
        self.__btn_clear.setShortcut("Ctrl+X")
        self.__btn_clear.setParent(self)
        self.__btn_clear.clicked.connect(self.btn_clear_clicked)
        btn_layout.addWidget(self.__btn_clear)

        self.__btn_exit = QPushButton("EXIT")
        self.__btn_exit.setParent(self)
        # self.__btn_exit.setShortcut("Ctrl+Q")
        self.__btn_exit.clicked.connect(self.btn_exit_clicked)
        btn_layout.addWidget(self.__btn_exit)

        left_layout.addLayout(btn_layout)
        main_layout.addLayout(left_layout)

        # put canvas in the left GUI
        # main_layout.addWidget(self.__canvas)
        # main_layout.addWidget(left_layout)

        # set the right layout
        right_layout = QVBoxLayout()
        # set the space between right contents
        right_layout.setContentsMargins(5, 5, 5, 14)

        splitter = QSplitter(self)
        right_layout.addWidget(splitter)

        method_layout = QHBoxLayout()

        self.__lab_method = QLabel(self)
        self.__lab_method.setText("Recognition Method")
        self.__lab_method.setFixedHeight(30)
        method_layout.addWidget(self.__lab_method)

        self.kernel_list = [
            'NaiveBayesian', 'VoteFisher', 'MultiFisher', 'SklearnFisher',
            'CNN'
        ]

        self.__box_method = QComboBox(self)
        self.__box_method.addItems(self.kernel_list)
        self.__box_method.setCurrentIndex(0)
        method_layout.addWidget(self.__box_method)

        right_layout.addLayout(method_layout)

        show_layout = QHBoxLayout()
        canv_layout = QVBoxLayout()

        self.__cbtn_eraser = QCheckBox("Eraser")
        self.__cbtn_eraser.setParent(self)
        self.__cbtn_eraser.clicked.connect(self.btn_eraser_clicked)
        canv_layout.addWidget(self.__cbtn_eraser)

        pen_size_layout = QHBoxLayout()

        self.__lab_pen_size = QLabel(self)
        self.__lab_pen_size.setText("Pen Size")
        self.__lab_pen_size.setFixedHeight(20)
        # self.__lab_pen_size.setFixedSize(50, 20)
        pen_size_layout.addWidget(self.__lab_pen_size)

        self.__box_pen_size = QSpinBox(self)
        self.__box_pen_size.setMaximum(40)
        self.__box_pen_size.setMinimum(20)
        self.__box_pen_size.setValue(30)
        self.__box_pen_size.setSingleStep(2)
        self.__box_pen_size.setFixedSize(50, 20)
        self.__box_pen_size.valueChanged.connect(self.box_pen_size_change)
        pen_size_layout.addWidget(self.__box_pen_size)
        canv_layout.addLayout(pen_size_layout)

        pen_color_layout = QHBoxLayout()

        self.__label_pen_color = QLabel(self)
        self.__label_pen_color.setText("Pen Color")
        self.__label_pen_color.setFixedHeight(20)
        pen_color_layout.addWidget(self.__label_pen_color)

        self.__combo_pen_color = QComboBox(self)
        self.__combo_pen_color.setFixedSize(50, 20)
        self.__fillColorList(self.__combo_pen_color)
        self.__combo_pen_color.currentIndexChanged.connect(
            self.pen_color_changed)
        pen_color_layout.addWidget(self.__combo_pen_color)
        canv_layout.addLayout(pen_color_layout)
        show_layout.addLayout(canv_layout)

        self.feature_map = QLabel()
        self.feature_map.setFixedSize(100, 100)
        self.feature_map.setText("")
        self.feature_map.setObjectName('feature map')
        show_layout.addWidget(self.feature_map)
        right_layout.addLayout(show_layout)

        main_layout.addLayout(right_layout)

    def btn_recog_clicked(self):
        self.update()
        savePath = "./recog.jpg"
        image = self.__canvas.get_current_image()
        image.save(savePath)
        save_path = os.path.abspath(savePath)
        self.label_log.append("image saved in path:\n{}".format(save_path))
        method_text = self.__box_method.currentText()
        self.label_log.append('method: {}'.format(method_text))
        predict = self.METHOD_KERNEL.set_kernel(savePath, method_text)
        # pic = QTextImageFormat()
        # pic.setName('./feature_map.jpg')
        # pic.setHeight(100)
        # pic.setWidth(100)
        showImage = QImage('./feature_map.jpg').scaled(100, 100)
        self.feature_map.setPixmap(QPixmap.fromImage(showImage))
        # self.label_log.append('feature map:\n')
        # self.label_log.textCursor().insertImage('./feature_map.jpg')
        self.label_log.append("recognition result is: {}".format(predict))
        # self.label_log.moveCursor(QTextCursor.End)
        # self.label_log.textCursor().clearSelection()
        # del pic
        message = QMessageBox()
        message.setText("recognition result is: {}".format(predict))
        # message.addButton()
        message.exec_()

    def btn_clear_clicked(self):
        self.__canvas.clear()
        self.label_log.append("Canvas is clean now!")

    def btn_save_clicked(self):
        save_path = QFileDialog.getSaveFileName(self, 'save your paint', '.\\',
                                                '*.jpg')
        if save_path[0] == "":
            self.label_log.append("save cancel")
            return
        self.__txt_path.setText(save_path[0])
        save_image = self.__canvas.get_current_image()
        save_image.save(save_path[0])
        save_path_ = os.path.abspath(save_path[0])
        self.label_log.append("image saved in path:\n{}".format(save_path_))

    def save_image(self):
        self.__txt_path.setText(self.__txt_path.displayText())
        save_path = self.__txt_path.text()
        created = create_dir_path(save_path)
        if created:
            self.label_log.append("create an directory:\n{}".format(save_path))
        file_path = create_file_path(save_path)
        save_image = self.__canvas.get_current_image()
        save_image.save(file_path)
        file_path_ = os.path.abspath(file_path)
        self.label_log.append("image saved in path:\n{}".format(file_path_))

    def btn_exit_clicked(self):
        self.close()
        QApplication.quit()

    def btn_eraser_clicked(self):
        self.__eraser_mode_set = ~self.__eraser_mode_set
        if self.__eraser_mode_set:
            self.label_log.append("Attention! Eraser Mode!")
        else:
            self.label_log.append("Writing Mode!")
        if self.__cbtn_eraser.isChecked():
            self.__canvas.EraserMode = True
        else:
            self.__canvas.EraserMode = False

    def box_pen_size_change(self):
        pen_size = self.__box_pen_size.value()
        self.__canvas.pen_size(pen_size)

    def __fillColorList(self, comboBox):
        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    def pen_color_changed(self):
        color_index = self.__combo_pen_color.currentIndex()
        color_str = self.__colorList[color_index]
        self.__canvas.pen_color(color_str)
Exemple #28
0
class EKWindow(QDialog):
    """
        Class which is responisble for running this entire application
    """

    def __init__(self):
        """
            Constructor for this class
        """
        super(EKWindow, self).__init__()
        self.engine = Engine("tables/Tamil-bamini.txt.in")

        # Settings file initialization
        self.settingsFilePath = os.getenv("APPDATA") + "\\" + qApp.applicationName() + "\eksettings.ini"
        self.init_settings()    # Function to check whether the settings file is or not.
        self.iniSettings = QSettings(self.settingsFilePath, QSettings.IniFormat)

        # Variable Initialization
        self.registrySettings = QSettings("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", QSettings.NativeFormat)
        self.shortcutModifierKey = self.iniSettings.value("shortcut_modifier")
        self.shortcutKey = self.iniSettings.value("shortcut")
        self.selectedKeyboard = self.iniSettings.value("selected_keyboard")
        self.keyboardStatus = False
        self.fileName = ""

        # Ui variable Initialization
        self.iconGroupBox = QGroupBox("Keyboards")
        self.iconLabel = QLabel("Keyboard:")
        self.iconComboBox = QComboBox(self)
        self.shortcutGroupBox = QGroupBox("Shortcut Setting")
        self.shortcutComboBox1 = QComboBox(self)
        self.shortcutComboBox2 = QComboBox(self)
        self.otherSettingsGroupBox = QGroupBox("Other Settings")
        self.checkboxStartWithWindows = QCheckBox()
        self.minimizeAction = QAction("Minimize", self)
        self.maximizeAction = QAction("Maximize", self)
        self.settingsAction = QAction("Settings", self)
        self.aboutAction = QAction("About", self)
        self.quitAction = QAction("Quit", self)
        self.trayIconMenu = QMenu(self)
        self.trayIcon = QSystemTrayIcon(self)
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.iconGroupBox)
        self.mainLayout.addWidget(self.shortcutGroupBox)
        self.mainLayout.addWidget(self.otherSettingsGroupBox)
        self.setLayout(self.mainLayout)

        # UI constructor and connectors
        self.create_settings_group_boxes()
        self.create_actions()
        self.create_tray_icon()

        # Signal connectors
        self.iconComboBox.currentIndexChanged.connect(self.change_keyboard)
        self.shortcutComboBox1.currentIndexChanged.connect(self.set_shortcut_modifier)
        self.shortcutComboBox2.currentIndexChanged.connect(self.set_shortcut_key)
        self.trayIcon.activated.connect(self.icon_activated)
        self.checkboxStartWithWindows.stateChanged.connect(self.checkbox_start_with_windows_ticked)

        if self.keyboardStatus:
            self.iconComboBox.setCurrentIndex(self.selectedKeyBoard)
        else:
            self.change_keyboard(0)
            self.iconComboBox.setCurrentIndex(0)

        self.trayIcon.show()
        self.set_shortcut_key()
        self.setWindowTitle(qApp.applicationName() + " " + qApp.applicationVersion())

    def init_settings(self):
        """
            Function to check whether the settings file is there or not. If there is no file, then it will create with
            default settings.
        """
        if not os.path.exists(self.settingsFilePath):
            settings_dir = os.getenv("APPDATA") + "\\" + qApp.applicationName()
            if not os.path.exists(settings_dir):
                os.makedirs(settings_dir)
            setting_path = ""
            if getattr(sys, 'frozen', False):
                setting_path = os.path.dirname(sys.executable)
            elif __file__:
                setting_path = os.path.dirname(__file__)
            shutil.copyfile(os.path.join(setting_path, "resources\eksettings.ini"), self.settingsFilePath)
        return

    def create_settings_group_boxes(self):
        """
            UI generator function.
        """
        self.iconComboBox.addItem("No Keyboard")
        self.iconComboBox.addItem("Tamil99")
        self.iconComboBox.addItem("Phonetic")
        self.iconComboBox.addItem("Typewriter")
        self.iconComboBox.addItem("Bamini")
        self.iconComboBox.addItem("Inscript")
        icon_layout = QHBoxLayout(self)
        icon_layout.addWidget(self.iconLabel)
        icon_layout.addWidget(self.iconComboBox)
        icon_layout.addStretch()
        self.iconGroupBox.setLayout(icon_layout)

        shortcut_label_1 = QLabel("Modifier Key:")
        shortcut_label_2 = QLabel("Shortcut Key:")

        self.shortcutComboBox1.addItem("NONE")
        self.shortcutComboBox1.addItem("CTRL")
        self.shortcutComboBox1.addItem("ALT")

        modifier_index = self.shortcutComboBox1.findText(self.shortcutModifierKey)
        self.shortcutComboBox1.setCurrentIndex(modifier_index)

        self.shortcutComboBox2.setMinimumContentsLength(3)

        if modifier_index == 0:
            self.shortcutComboBox2.addItem("F1")
            self.shortcutComboBox2.addItem("ESC")
            self.shortcutComboBox2.addItem("F2")
            self.shortcutComboBox2.addItem("F3")
            self.shortcutComboBox2.addItem("F4")
            self.shortcutComboBox2.addItem("F5")
            self.shortcutComboBox2.addItem("F6")
            self.shortcutComboBox2.addItem("F7")
            self.shortcutComboBox2.addItem("F8")
            self.shortcutComboBox2.addItem("F9")
            self.shortcutComboBox2.addItem("F10")
        else:
            self.shortcutComboBox2.addItem("1")
            self.shortcutComboBox2.addItem("2")
            self.shortcutComboBox2.addItem("3")
            self.shortcutComboBox2.addItem("4")
            self.shortcutComboBox2.addItem("5")
            self.shortcutComboBox2.addItem("6")
            self.shortcutComboBox2.addItem("7")
            self.shortcutComboBox2.addItem("8")
            self.shortcutComboBox2.addItem("9")
            self.shortcutComboBox2.addItem("0")

        key_index = self.shortcutComboBox2.findText(self.shortcutKey)
        self.shortcutComboBox2.setCurrentIndex(key_index)

        shortcut_layout = QHBoxLayout(self)
        shortcut_layout.addWidget(shortcut_label_1)
        shortcut_layout.addWidget(self.shortcutComboBox1)
        shortcut_layout.addWidget(shortcut_label_2)
        shortcut_layout.addWidget(self.shortcutComboBox2)
        shortcut_layout.addStretch()
        self.shortcutGroupBox.setLayout(shortcut_layout)

        checkbox_start_with_windows_label = QLabel("Start eKalappai whenever windows starts")

        # if registry entry for auto start with windows for the current user exists, then check the checkbox
        if self.registrySettings.contains(qApp.applicationName()):
            self.checkboxStartWithWindows.setChecked(True)
        else:
            self.checkboxStartWithWindows.setChecked(False)

        other_settings_layout = QHBoxLayout(self)
        other_settings_layout.addWidget(checkbox_start_with_windows_label)
        other_settings_layout.addWidget(self.checkboxStartWithWindows)
        other_settings_layout.addStretch()
        self.otherSettingsGroupBox.setLayout(other_settings_layout)

    def set_shortcut_key(self):
        """
            Function to change the shortcut key when its changed.
        """
        self.shortcutKey = self.shortcutComboBox2.currentText()
        self.iniSettings.setValue("shortcut", self.shortcutKey)
        self.register_shortcut_listener()
        if self.shortcutKey == "ESC":
            self.shortcutKeyHex = 0x1B
        elif self.shortcutKey == "F1":
            self.shortcutKeyHex = 0x70
        elif self.shortcutKey == "F2":
            self.shortcutKeyHex = 0x71
        elif self.shortcutKey == "F3":
            self.shortcutKeyHex = 0x72
        elif self.shortcutKey == "F4":
            self.shortcutKeyHex = 0x73
        elif self.shortcutKey == "F5":
            self.shortcutKeyHex = 0x74
        elif self.shortcutKey == "F6":
            self.shortcutKeyHex = 0x75
        elif self.shortcutKey == "F7":
            self.shortcutKeyHex = 0x76
        elif self.shortcutKey == "F8":
            self.shortcutKeyHex = 0x77
        elif self.shortcutKey == "F9":
            self.shortcutKeyHex = 0x78
        elif self.shortcutKey == "F10":
            self.shortcutKeyHex = 0x79
        elif self.shortcutKey == "1":
            self.shortcutKeyHex = 0x31
        elif self.shortcutKey == "2":
            self.shortcutKeyHex = 0x32
        elif self.shortcutKey == "3":
            self.shortcutKeyHex = 0x33
        elif self.shortcutKey == "4":
            self.shortcutKeyHex = 0x34
        elif self.shortcutKey == "5":
            self.shortcutKeyHex = 0x35
        elif self.shortcutKey == "6":
            self.shortcutKeyHex = 0x36
        elif self.shortcutKey == "7":
            self.shortcutKeyHex = 0x37
        elif self.shortcutKey == "8":
            self.shortcutKeyHex = 0x38
        elif self.shortcutKey == "9":
            self.shortcutKeyHex = 0x39
        elif self.shortcutKey == "0":
            self.shortcutKeyHex = 0x30

    def create_actions(self):
        """
            Slot connectors for all right clicking and other actions.
        """
        self.minimizeAction.triggered.connect(self.hide)
        self.maximizeAction.triggered.connect(self.showMaximized)
        self.settingsAction.triggered.connect(self.showNormal)
        self.aboutAction.triggered.connect(self.show_about)
        self.quitAction.triggered.connect(self.quit)

    def quit(self):
        self.engine.un_hook()
        exit(0)

    def create_tray_icon(self):
        """
            Tray icon creator and corresponding connectors
        """
        self.trayIconMenu.addAction(self.settingsAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.aboutAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.quitAction)
        self.trayIcon.setContextMenu(self.trayIconMenu)

    def setVisible(self, visible):
        self.settingsAction.setEnabled(self.isMaximized() or not visible)
        super(EKWindow, self).setVisible(visible)

    def closeEvent(self, event):
        if self.trayIcon.isVisible():
            self.hide()
            event.ignore()

    def load_keyboard(self):
        """
            Mapping file loading function
        """
        if self.selectedKeyboard == 1:
            self.fileName = "tables/Tamil-tamil99.txt.in"
        elif self.selectedKeyboard == 2:
            self.fileName = "tables/Tamil-phonetic.txt.in"
        elif self.selectedKeyboard == 3:
            self.fileName = "tables/Tamil-typewriter.txt.in"
        elif self.selectedKeyboard == 4:
            self.fileName = "tables/Tamil-bamini.txt.in"
        elif self.selectedKeyboard == 5:
            self.fileName = "tables/Tamil-inscript.txt.in"
        else:
            pass

    def getPath(self, index):
            if index == 1:
                self.path = "tables/Tamil-tamil99.txt.in"
            elif index == 2:
                self.path = "tables/Tamil-phonetic.txt.in"
            elif index == 3:
                self.path = "tables/Tamil-typewriter.txt.in"
            elif index == 4:
                self.path = "tables/Tamil-bamini.txt.in"
            elif index == 5:
                self.path = "tables/Tamil-inscript.txt.in"
            else:
                pass

    def change_keyboard(self, index):
        """
            Function to change the keyboard based on the index which was sent as a param
        """
        if int(index) != 0:
            self.iniSettings.setValue("selected_keyboard", index)
            self.selectedKeyboard = index
        self.iconComboBox.setCurrentIndex(int(index))
        icon = self.iconComboBox.itemIcon(int(index))
        self.trayIcon.setIcon(icon)
        self.setWindowIcon(icon)
        self.trayIcon.setToolTip(self.iconComboBox.itemText(int(index)))
        self.show_tray_message(index)
        self.load_keyboard()
        if int(index) != 0:
            self.getPath(int(index))
            self.engine.file_name = self.path
            self.engine.initialize()
            self.engine.conv_state = True
        else:
            try:
                self.engine.conv_state = False
            except:
                pass

    def icon_activated(self, reason):
        """
            Function to toggle the state when the icon is clicked or shortcut key is pressed
        """
        if reason == QSystemTrayIcon.DoubleClick:
            pass
        elif reason == QSystemTrayIcon.Trigger:
            if self.keyboardStatus:
                self.keyboardStatus = False
            else:
                self.keyboardStatus = True
            if self.keyboardStatus:
                self.change_keyboard(self.selectedKeyboard)
            else:
                self.change_keyboard(0)
        elif reason == QSystemTrayIcon.MiddleClick:
            pass
        else:
            pass

    def show_tray_message(self, index):
        """
            Tray message generator when there is change in keyboard state
        """
        icon = QSystemTrayIcon.MessageIcon(0)
        message = self.iconComboBox.itemText(int(index)) + " set"
        self.trayIcon.showMessage(qApp.applicationName() + " " + qApp.applicationVersion(), message, icon, 100)

    def checkbox_start_with_windows_ticked(self):
        """
            Function to add or disable registry entry to auto start ekalappai with windows for the current users
        """
        if self.checkboxStartWithWindows.isChecked():
            self.registrySettings.setValue(qApp.applicationName(), qApp.applicationFilePath())
        else:
            self.registrySettings.remove(qApp.applicationName())

    def show_about(self):
        pass

    def set_shortcut_modifier(self, index):
        """
            Function to set the shortcut modifier when its changed.
        """
        self.iniSettings.setValue("shortcut_modifier", self.shortcutComboBox1.currentText())
        self.shortcutModifierKey = self.iniSettings.value("shortcut_modifier")
        # if none is selected, the allowed single key shortcuts should change
        if index == 0:
            self.shortcutComboBox2.clear()
            self.shortcutComboBox2.addItem("ESC")
            self.shortcutComboBox2.addItem("F1")
            self.shortcutComboBox2.addItem("F2")
            self.shortcutComboBox2.addItem("F3")
            self.shortcutComboBox2.addItem("F4")
            self.shortcutComboBox2.addItem("F5")
            self.shortcutComboBox2.addItem("F6")
            self.shortcutComboBox2.addItem("F7")
            self.shortcutComboBox2.addItem("F8")
            self.shortcutComboBox2.addItem("F9")
            self.shortcutComboBox2.addItem("F10")
        else:
            self.shortcutComboBox2.clear()
            self.shortcutComboBox2.addItem("1")
            self.shortcutComboBox2.addItem("2")
            self.shortcutComboBox2.addItem("3")
            self.shortcutComboBox2.addItem("4")
            self.shortcutComboBox2.addItem("5")
            self.shortcutComboBox2.addItem("6")
            self.shortcutComboBox2.addItem("7")
            self.shortcutComboBox2.addItem("8")
            self.shortcutComboBox2.addItem("9")
            self.shortcutComboBox2.addItem("0")
        self.register_shortcut_listener()

    def register_shortcut_listener(self):
        self.engine.event_queue.remove_all()
        if self.iniSettings.value("shortcut_modifier") == "NONE":
            self.engine.event_queue.register_event([[self.shortcutKey], self.icon_activated, QSystemTrayIcon.Trigger])
        elif self.iniSettings.value("shortcut_modifier") == "CTRL":
            self.engine.event_queue.register_event([['Lcontrol', self.shortcutKey], self.icon_activated, QSystemTrayIcon.Trigger])
            self.engine.event_queue.register_event([['Rcontrol', self.shortcutKey], self.icon_activated, QSystemTrayIcon.Trigger])
        elif self.iniSettings.value("shortcut_modifier") == "ALT":
            self.engine.event_queue.register_event([['LMenu', self.shortcutKey], self.icon_activated, QSystemTrayIcon.Trigger])
            self.engine.event_queue.register_event([['RMenu', self.shortcutKey], self.icon_activated, QSystemTrayIcon.Trigger])
        return True
Exemple #29
0
class ProceedQuestion(QDialog):

    ask_question = pyqtSignal(object, object, object)

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('dialog_question.png')))

        self.questions = []

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

        self.icon_label = ic = QLabel(self)
        ic.setPixmap(QPixmap(I('dialog_question.png')))
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        ic.setMaximumWidth(110)
        ic.setMaximumHeight(100)
        ic.setScaledContents(True)
        ic.setStyleSheet('QLabel { margin-right: 10px }')
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
                _('Show detailed information about this error'))
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes|self.bb.No|self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)

        self.checkbox = QCheckBox('', self)

        l.addWidget(ic, 0, 0, 1, 1)
        l.addWidget(msg, 0, 1, 1, 1)
        l.addWidget(self.checkbox, 1, 0, 1, 2)
        l.addWidget(self.det_msg, 2, 0, 1, 2)
        l.addWidget(self.bb, 3, 0, 1, 2)

        self.ask_question.connect(self.do_ask_question,
                type=Qt.QueuedConnection)

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
                'calibre, version %s\n%s: %s\n\n%s' %
                (__version__, unicode(self.windowTitle()),
                    unicode(self.msg_label.text()),
                    unicode(self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(self.show_det_msg if vis else
                self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        if self.geom_pref:
            geom = gprefs.get(self.geom_pref, None)
            if geom:
                self.restoreGeometry(geom)
                return
        sz = self.sizeHint() + QSize(100, 0)
        sz.setWidth(min(500, sz.width()))
        sz.setHeight(min(500, sz.height()))
        self.resize(sz)

    def show_question(self):
        if self.isVisible():
            return
        if self.questions:
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.setWindowTitle(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(
                    QIcon() if question.action_icon is None else question.action_icon)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.geom_pref = ('proceed question dialog:' + question.geom_pref) if question.geom_pref else None
            if question.show_det:
                self.toggle_det_msg()
            else:
                self.do_resize()
            self.show()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            button.setFocus(Qt.OtherFocusReason)

    def __call__(self, callback, payload, html_log, log_viewer_title, title,
            msg, det_msg='', show_copy_button=False, cancel_callback=None,
            log_is_file=False, checkbox_msg=None, checkbox_checked=False,
            action_callback=None, action_label=None, action_icon=None, focus_action=False,
            show_det=False, show_ok=False, geom_pref=None):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param geom_pref: String for preference name to preserve dialog box geometry

        '''
        question = Question(
            payload, callback, cancel_callback, title, msg, html_log,
            log_viewer_title, log_is_file, det_msg, show_copy_button,
            checkbox_msg, checkbox_checked, action_callback, action_label,
            action_icon, focus_action, show_det, show_ok, geom_pref)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title, log,
                        parent=self)
Exemple #30
0
class ConfigWidget(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        
        self.setWindowTitle('exlibris preferences')
        
        row = 0
        self.l = QGridLayout()
        self.setLayout(self.l)
        
        self.label_xhtml_filename = QLabel('Ex libris XHTML filename:')
        self.xhtml_filename = QLineEdit(self)
        self.xhtml_filename.setText(prefs['xhtml_filename'])
        self.button_xhtml_filename = QPushButton('Change', self)
        self.button_xhtml_filename.clicked.connect(self.button_xhtml_filename_handler)
        
        self.l.addWidget(self.label_xhtml_filename, row, 1)
        row += 1
        self.l.addWidget(self.xhtml_filename, row, 1)
        self.l.addWidget(self.button_xhtml_filename, row, 2)
        row += 1
        
        self.l.addWidget(QLabel(''), row, 1)
        row += 1

        self.label_include_dir = QLabel('Include additional files from directory:')
        self.checkbox_include_dir = QCheckBox('', self)
        self.checkbox_include_dir.setChecked(prefs['checkbox_include_dir'] == 'True')
        self.include_dir = QLineEdit(self)
        self.include_dir.setText(prefs['include_dir'])
        self.button_include_dir = QPushButton('Change', self)
        self.button_include_dir.clicked.connect(self.button_include_dir_handler)
        
        self.l.addWidget(self.checkbox_include_dir, row, 0)
        self.l.addWidget(self.label_include_dir, row, 1)
        row += 1
        self.l.addWidget(self.include_dir, row, 1)
        self.l.addWidget(self.button_include_dir, row, 2)
        row += 1
        
        self.l.addWidget(QLabel(''), row, 1)
        row += 1
        
        self.label_include_guide_text = QLabel('Include in guide with string:')
        self.checkbox_include_guide_text = QCheckBox('', self)
        self.checkbox_include_guide_text.setChecked(prefs['checkbox_include_guide_text'] == 'True')
        self.include_guide_text = QLineEdit(self)
        self.include_guide_text.setText(prefs['include_guide_text'])
        
        self.l.addWidget(self.checkbox_include_guide_text, row, 0)
        self.l.addWidget(self.label_include_guide_text, row, 1)
        row += 1
        self.l.addWidget(self.include_guide_text, row, 1)
        row += 1
        
        self.l.addWidget(QLabel(''), row, 1)
        row += 1
        
        self.label_include_toc_text = QLabel('Include in TOC with string:')
        self.checkbox_include_toc_text = QCheckBox('', self)
        self.checkbox_include_toc_text.setChecked(prefs['checkbox_include_toc_text'] == 'True')
        self.include_toc_text = QLineEdit(self)
        self.include_toc_text.setText(prefs['include_toc_text'])
        
        self.l.addWidget(self.checkbox_include_toc_text, row, 0)
        self.l.addWidget(self.label_include_toc_text, row, 1)
        row += 1
        self.l.addWidget(self.include_toc_text, row, 1)
        row += 1
        
        self.l.addWidget(QLabel(''), row, 1)
        row += 1
        
        self.label_ask_replace = QLabel('Ask before replacing book in library')
        self.checkbox_ask_replace = QCheckBox('', self)
        self.checkbox_ask_replace.setChecked(prefs['checkbox_ask_replace'] == 'True')
        self.l.addWidget(self.checkbox_ask_replace, row, 0)
        self.l.addWidget(self.label_ask_replace, row, 1)
        row += 1
        
        self.label_disable_first_last_only = QLabel('When multiple EPUB files are selected, allow insertion points other than "1", "first", and "last"')
        self.checkbox_disable_first_last_only = QCheckBox('', self)
        self.checkbox_disable_first_last_only.setChecked(prefs['checkbox_disable_first_last_only'] == 'True')
        self.l.addWidget(self.checkbox_disable_first_last_only, row, 0)
        self.l.addWidget(self.label_disable_first_last_only, row, 1)
        row += 1
        
        self.l.addWidget(QLabel(''), row, 1)
        row += 1
        
        self.label_replace_strings = QLabel('Replace strings:')
        self.replace_strings = QTextEdit(self)
        self.replace_strings.setText(prefs['replace_strings'])
        self.label_supportedMetadata = QLabel('Supported metadata:')
        self.supportedMetadata = QListWidget(self)
        #QtCore.QObject.connect(self.supportedMetadata, QtCore.SIGNAL("doubleClicked()"), self.add_replace_string)
        self.supportedMetadata.doubleClicked.connect(self.add_replace_string)
        
        producer = exlibris()
        tags = producer.getSupportedMetadataList()
        for tag in tags:
            self.supportedMetadata.addItem(tag.decode('utf-8'))
        
        self.l.addWidget(self.label_replace_strings, row, 1)
        self.l.addWidget(self.label_supportedMetadata, row, 2)
        row += 1
        self.l.addWidget(self.replace_strings, row, 1)
        self.l.addWidget(self.supportedMetadata, row, 2)
        row += 1
                
        self.resize(self.sizeHint())


    def add_replace_string(self):
        currentText = str(self.replace_strings.toPlainText()).strip()
        currentItem = self.supportedMetadata.currentItem().text()
        self.replace_strings.setText("%s\n%s=your_value_goes_here;" % (currentText, currentItem))


    def button_xhtml_filename_handler(self):
        initial_dir = os.path.dirname(str(self.xhtml_filename.text()))
        new_file = QFileDialog.getOpenFileName(self, "Select ex libris XHTML file", initial_dir, "XHTML Files (*.xhtml)")
        if new_file:
            new_file = new_file[0] if isinstance(new_file, tuple) else new_file
            if new_file and os.path.exists(new_file):
                self.xhtml_filename.setText(new_file)

    def button_include_dir_handler(self):
        initial_dir = os.path.dirname(str(self.include_dir.text()))
        dirDialog = QFileDialog()
        dirDialog.setFileMode(QFileDialog.Directory)
        new_dir = dirDialog.getExistingDirectory(self, "Select directory", initial_dir)
        if (len(new_dir) > 0):
            self.include_dir.setText(new_dir)

    def save_settings(self):
        prefs['xhtml_filename'] = unicode(self.xhtml_filename.text())
        prefs['include_dir'] = unicode(self.include_dir.text())
        prefs['include_guide_text'] = unicode(self.include_guide_text.text())
        prefs['include_toc_text'] = unicode(self.include_toc_text.text())
        prefs['replace_strings'] = unicode(self.replace_strings.toPlainText())
        prefs['checkbox_include_dir'] = unicode(self.checkbox_include_dir.isChecked())
        prefs['checkbox_include_guide_text'] = unicode(self.checkbox_include_guide_text.isChecked())
        prefs['checkbox_include_toc_text'] = unicode(self.checkbox_include_toc_text.isChecked())
        prefs['checkbox_ask_replace'] = unicode(self.checkbox_ask_replace.isChecked())
        prefs['checkbox_disable_first_last_only'] = unicode(self.checkbox_disable_first_last_only.isChecked())
        # TODO: save value from main.py (?)
        prefs['include_spine'] = u'1'
        prefs['include_toc'] = u'1'
Exemple #31
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)

    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.white)
        self.marked_brush = QBrush(Qt.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = CoverView(self, show_size=gprefs['bd_overlay_cover_size'])
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

        self.details = Details(parent.book_details.book_info, self)
        self.details.anchor_clicked.connect(self.on_link_clicked)
        self.link_delegate = link_delegate
        self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
        palette = self.details.palette()
        self.details.setAcceptDrops(False)
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.details.setPalette(palette)

        self.c = QWidget(self)
        self.c.l = l2 = QGridLayout(self.c)
        l2.setContentsMargins(0, 0, 0, 0)
        self.c.setLayout(l2)
        l2.addWidget(self.details, 0, 0, 1, -1)
        self.splitter.addWidget(self.c)

        self.fit_cover = QCheckBox(_('Fit &cover within view'), self)
        self.fit_cover.setChecked(
            gprefs.get('book_info_dialog_fit_cover', True))
        self.hl = hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        l2.addLayout(hl, l2.rowCount(), 0, 1, -1)
        hl.addWidget(self.fit_cover), hl.addStretch()
        self.clabel = QLabel(
            '<div style="text-align: right"><a href="calibre:conf" title="{}" style="text-decoration: none">{}</a>'
            .format(_('Configure this view'), _('Configure')))
        self.clabel.linkActivated.connect(self.configure)
        hl.addWidget(self.clabel)
        self.previous_button = QPushButton(QIcon(I('previous.png')),
                                           _('&Previous'), self)
        self.previous_button.clicked.connect(self.previous)
        l2.addWidget(self.previous_button, l2.rowCount(), 0)
        self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self)
        self.next_button.clicked.connect(self.next)
        l2.addWidget(self.next_button, l2.rowCount() - 1, 1)

        self.view = view
        self.current_row = None
        self.refresh(row)
        self.view.model().new_bookdisplay_data.connect(self.slave)
        self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
        self.ns = QShortcut(QKeySequence('Alt+Right'), self)
        self.ns.activated.connect(self.next)
        self.ps = QShortcut(QKeySequence('Alt+Left'), self)
        self.ps.activated.connect(self.previous)
        self.next_button.setToolTip(
            _('Next [%s]') %
            unicode_type(self.ns.key().toString(QKeySequence.NativeText)))
        self.previous_button.setToolTip(
            _('Previous [%s]') %
            unicode_type(self.ps.key().toString(QKeySequence.NativeText)))

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                self.restoreGeometry(saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass

    def configure(self):
        d = Configure(get_gui().current_db, self)
        if d.exec_() == d.Accepted:
            if self.current_row is not None:
                mi = self.view.model().get_book_display_info(self.current_row)
                if mi is not None:
                    self.refresh(self.current_row, mi=mi)

    def on_link_clicked(self, qurl):
        link = unicode_type(qurl.toString(NO_URL_FORMATTING))
        self.link_delegate(link)

    def done(self, r):
        saved_layout = (bytearray(self.saveGeometry()),
                        bytearray(self.splitter.saveState()))
        gprefs.set('book_info_dialog_layout', saved_layout)
        ret = QDialog.done(self, r)
        self.view.model().new_bookdisplay_data.disconnect(self.slave)
        self.view = self.link_delegate = self.gui = None
        self.closed.emit(self)
        return ret

    def cover_changed(self, data):
        if self.current_row is not None:
            id_ = self.view.model().id(self.current_row)
            self.view.model().db.set_cover(id_, data)
        self.gui.refresh_cover_browser()
        ci = self.view.currentIndex()
        if ci.isValid():
            self.view.model().current_changed(ci, ci)

    def details_size_hint(self):
        return QSize(350, 550)

    def toggle_cover_fit(self, state):
        gprefs.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
        self.resize_cover()

    def cover_view_resized(self, event):
        QTimer.singleShot(1, self.resize_cover)

    def slave(self, mi):
        self.refresh(mi.row_number, mi)

    def move(self, delta=1):
        idx = self.view.currentIndex()
        if idx.isValid():
            m = self.view.model()
            ni = m.index(idx.row() + delta, idx.column())
            if ni.isValid():
                if self.view.isVisible():
                    self.view.scrollTo(ni)
                self.view.setCurrentIndex(ni)

    def next(self):
        self.move()

    def previous(self):
        self.move(-1)

    def resize_cover(self):
        if self.cover_pixmap is None:
            return
        pixmap = self.cover_pixmap
        if self.fit_cover.isChecked():
            scaled, new_width, new_height = fit_image(
                pixmap.width(), pixmap.height(),
                self.cover.size().width() - 10,
                self.cover.size().height() - 10)
            if scaled:
                try:
                    dpr = self.devicePixelRatioF()
                except AttributeError:
                    dpr = self.devicePixelRatio()
                pixmap = pixmap.scaled(int(dpr * new_width),
                                       int(dpr * new_height),
                                       Qt.KeepAspectRatio,
                                       Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(dpr)
        self.cover.set_pixmap(pixmap)
        self.update_cover_tooltip()

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt = _('This book is marked') if self.marked in {
                True, 'true'
            } else _('This book is marked as: %s') % self.marked
            tt += '\n\n'
        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d pixels') % dict(
                width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)
        self.cover.pixmap_size = sz.width(), sz.height()

    def refresh(self, row, mi=None):
        if isinstance(row, QModelIndex):
            row = row.row()
        if row == self.current_row and mi is None:
            return
        mi = self.view.model().get_book_display_info(row) if mi is None else mi
        if mi is None:
            # Indicates books was deleted from library, or row numbers have
            # changed
            return

        self.previous_button.setEnabled(False if row == 0 else True)
        self.next_button.setEnabled(False if row ==
                                    self.view.model().rowCount(QModelIndex()) -
                                    1 else True)
        self.current_row = row
        self.setWindowTitle(mi.title)
        self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
        try:
            dpr = self.devicePixelRatioF()
        except AttributeError:
            dpr = self.devicePixelRatio()
        self.cover_pixmap.setDevicePixelRatio(dpr)
        self.resize_cover()
        html = render_html(mi,
                           True,
                           self,
                           pref_name='popup_book_display_fields')
        set_html(mi, html, self.details)
        self.marked = mi.marked
        self.cover.setBackgroundBrush(
            self.marked_brush if mi.marked else self.normal_brush)
        self.update_cover_tooltip()
Exemple #32
0
class Report(QDialog):  # {{{

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.gui = parent
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('polish.png')))
        self.reports = []

        self.l = l = QGridLayout()
        self.setLayout(l)
        self.view = v = QTextEdit(self)
        v.setReadOnly(True)
        l.addWidget(self.view, 0, 0, 1, 2)

        self.backup_msg = la = QLabel('')
        l.addWidget(la, 1, 0, 1, 2)
        la.setVisible(False)
        la.setWordWrap(True)

        self.ign = QCheckBox(_('Ignore remaining report'), self)
        l.addWidget(self.ign, 2, 0)

        bb = self.bb = QDialogButtonBox(QDialogButtonBox.Close)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        b = self.log_button = bb.addButton(_('View full &log'), bb.ActionRole)
        b.clicked.connect(self.view_log)
        bb.button(bb.Close).setDefault(True)
        l.addWidget(bb, 2, 1)

        self.finished.connect(self.show_next, type=Qt.QueuedConnection)

        self.resize(QSize(800, 600))

    def setup_ign(self):
        self.ign.setText(ngettext(
            'Ignore remaining report', 'Ignore remaining {} reports', len(self.reports)).format(len(self.reports)))
        self.ign.setVisible(bool(self.reports))
        self.ign.setChecked(False)

    def __call__(self, *args):
        self.reports.append(args)
        self.setup_ign()
        if not self.isVisible():
            self.show_next()

    def show_report(self, book_title, book_id, fmts, job, report):
        from calibre.ebooks.markdown import markdown
        self.current_log = job.details
        self.setWindowTitle(_('Polishing of %s')%book_title)
        self.view.setText(markdown('# %s\n\n'%book_title + report,
                                   output_format='html4'))
        self.bb.button(self.bb.Close).setFocus(Qt.OtherFocusReason)
        self.backup_msg.setVisible(bool(fmts))
        if fmts:
            m = ngettext('The original file has been saved as %s.',
                     'The original files have been saved as %s.', len(fmts))%(
                _(' and ').join('ORIGINAL_'+f for f in fmts)
                     )
            self.backup_msg.setText(m + ' ' + _(
                'If you polish again, the polishing will run on the originals.')%(
                ))

    def view_log(self):
        self.view.setPlainText(self.current_log)
        self.view.verticalScrollBar().setValue(0)

    def show_next(self, *args):
        if not self.reports:
            return
        if not self.isVisible():
            self.show()
        self.show_report(*self.reports.pop(0))
        self.setup_ign()

    def accept(self):
        if self.ign.isChecked():
            self.reports = []
        if self.reports:
            self.show_next()
            return
        super(Report, self).accept()

    def reject(self):
        if self.ign.isChecked():
            self.reports = []
        if self.reports:
            self.show_next()
            return
        super(Report, self).reject()
Exemple #33
0
class ConfigWidget(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        #add checkbox
        self.debug_checkbox = QCheckBox('Debug Mode')
        self.debug_checkbox.setChecked(prefs['debug_mode'])
        self.l.addWidget(self.debug_checkbox)

        self.config_url = QUrl('https://'+prefs['api_base']+'/link/start')
        self.webview = QTWebView(bearer_token=prefs['token'])

        self.webview.load(self.config_url)
        if prefs['debug_mode']:
            self.webview.setMinimumSize(QSize(600, 300))
        else:
            self.webview.setMinimumSize(QSize(600, 600))
        self.global_settings = self.webview.page().settings() #QWebSettings.globalSettings()
        self.global_settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.global_settings.setAttribute(QWebSettings.JavascriptEnabled, True)
        self.global_settings.setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
        self.global_settings.setAttribute(QWebSettings.JavascriptCanCloseWindows, True)
        self.global_settings.setAttribute(QWebSettings.PluginsEnabled, True)
        self.global_settings.setAttribute(QWebSettings.LocalContentCanAccessRemoteUrls, True)
        self.global_settings.setAttribute(QWebSettings.LocalContentCanAccessFileUrls, True)
        self.global_settings.setAttribute(QWebSettings.XSSAuditingEnabled, False)
        self.global_settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, True)
        self.webview.show()
        self.l.addWidget(self.webview)

        if prefs['debug_mode']:
            self.inspector = QWebInspector()
            self.inspector.setMinimumSize(QSize(600, 300))
            self.inspector.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding);

            self.l.addWidget(self.inspector)
            self.inspector.setPage(self.webview.page())

        # self.webview.urlChanged.connect(_url_changed)
        # self.webview.loadFinished.connect(_load_finished)

    ################################################################################################################
    # Event Handlers
    #
    # def _url_changed(url):
    #         print('url changed: ', url)
    #
    # def _load_finished(ok):
    #     print('load finished, ok: ', ok)
    #     if self.webview.page().mainFrame().url() == self.config_url:
    #         print('requested url = current url')
    #         # token = self.webview.page().mainFrame().evaluateJavaScript("""
    #         # getAuthToken();
    #         # """)
    #         # print(token)
    #         # prefs['token'] = token

    def save_settings(self):
        prefs['debug_mode'] = self.debug_checkbox.isChecked()

    def validate(self):
        return True #self.webview.page().mainFrame().url() == self.config_url
Exemple #34
0
    def request_octo_init_settings(self, wizard, method):
        vbox = QVBoxLayout()
        next_enabled = True
        label = QLabel(_("Enter a label to name your device:"))
        name = QLineEdit()
        hl = QHBoxLayout()
        hl.addWidget(label)
        hl.addWidget(name)
        hl.addStretch(1)
        vbox.addLayout(hl)

        def clean_text(widget):
            text = widget.toPlainText().strip()
            return ' '.join(text.split())

        if method in [TIM_NEW, TIM_RECOVER]:
            gb = QGroupBox()
            hbox1 = QHBoxLayout()
            gb.setLayout(hbox1)
            vbox.addWidget(gb)
            gb.setTitle(_("Select your seed length:"))
            bg_numwords = QButtonGroup()
            for i, count in enumerate([12, 18, 24]):
                rb = QRadioButton(gb)
                rb.setText(_("%d words") % count)
                bg_numwords.addButton(rb)
                bg_numwords.setId(rb, i)
                hbox1.addWidget(rb)
                rb.setChecked(True)
            cb_pin = QCheckBox(_('Enable PIN protection'))
            cb_pin.setChecked(True)
        else:
            text = QTextEdit()
            text.setMaximumHeight(60)
            if method == TIM_MNEMONIC:
                msg = _("Enter your BIP39 mnemonic:")
            else:
                msg = _("Enter the master private key beginning with xprv:")

                def set_enabled():
                    from electrum.keystore import is_xprv
                    wizard.next_button.setEnabled(is_xprv(clean_text(text)))

                text.textChanged.connect(set_enabled)
                next_enabled = False

            vbox.addWidget(QLabel(msg))
            vbox.addWidget(text)
            pin = QLineEdit()
            pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,9}')))
            pin.setMaximumWidth(100)
            hbox_pin = QHBoxLayout()
            hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):")))
            hbox_pin.addWidget(pin)
            hbox_pin.addStretch(1)

        if method in [TIM_NEW, TIM_RECOVER]:
            vbox.addWidget(WWLabel(RECOMMEND_PIN))
            vbox.addWidget(cb_pin)
        else:
            vbox.addLayout(hbox_pin)

        passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        cb_phrase = QCheckBox(_('Enable passphrases'))
        cb_phrase.setChecked(False)
        vbox.addWidget(passphrase_msg)
        vbox.addWidget(passphrase_warning)
        vbox.addWidget(cb_phrase)

        # ask for recovery type (random word order OR matrix)
        if method == TIM_RECOVER:
            gb_rectype = QGroupBox()
            hbox_rectype = QHBoxLayout()
            gb_rectype.setLayout(hbox_rectype)
            vbox.addWidget(gb_rectype)
            gb_rectype.setTitle(_("Select recovery type:"))
            bg_rectype = QButtonGroup()

            rb1 = QRadioButton(gb_rectype)
            rb1.setText(_('Scrambled words'))
            bg_rectype.addButton(rb1)
            bg_rectype.setId(rb1, RECOVERY_TYPE_SCRAMBLED_WORDS)
            hbox_rectype.addWidget(rb1)
            rb1.setChecked(True)

            rb2 = QRadioButton(gb_rectype)
            rb2.setText(_('Matrix'))
            bg_rectype.addButton(rb2)
            bg_rectype.setId(rb2, RECOVERY_TYPE_MATRIX)
            hbox_rectype.addWidget(rb2)
        else:
            bg_rectype = None

        wizard.exec_layout(vbox, next_enabled=next_enabled)

        if method in [TIM_NEW, TIM_RECOVER]:
            item = bg_numwords.checkedId()
            pin = cb_pin.isChecked()
            recovery_type = bg_rectype.checkedId() if bg_rectype else None
        else:
            item = ' '.join(str(clean_text(text)).split())
            pin = str(pin.text())
            recovery_type = None

        return (item, name.text(), pin, cb_phrase.isChecked(), recovery_type)
Exemple #35
0
class JobError(QDialog):  # {{{

    WIDTH = 600
    do_pop = pyqtSignal()

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.queue = []
        self.do_pop.connect(self.pop, type=Qt.QueuedConnection)

        self._layout = l = QGridLayout()
        self.setLayout(l)
        self.icon = QIcon(I('dialog_error.png'))
        self.setWindowIcon(self.icon)
        self.icon_label = QLabel()
        self.icon_label.setPixmap(self.icon.pixmap(68, 68))
        self.icon_label.setMaximumSize(QSize(68, 68))
        self.msg_label = QLabel('<p>&nbsp;')
        self.msg_label.setStyleSheet('QLabel { margin-top: 1ex; }')
        self.msg_label.setWordWrap(True)
        self.msg_label.setTextFormat(Qt.RichText)
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setVisible(False)

        self.bb = QDialogButtonBox(QDialogButtonBox.Close, parent=self)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                self.bb.ActionRole)
        self.ctc_button.clicked.connect(self.copy_to_clipboard)
        self.retry_button = self.bb.addButton(_('&Retry'), self.bb.ActionRole)
        self.retry_button.clicked.connect(self.retry)
        self.retry_func = None
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
                _('Show detailed information about this error'))
        self.suppress = QCheckBox(self)

        l.addWidget(self.icon_label, 0, 0, 1, 1)
        l.addWidget(self.msg_label,  0, 1, 1, 1)
        l.addWidget(self.det_msg,    1, 0, 1, 2)
        l.addWidget(self.suppress,   2, 0, 1, 2, Qt.AlignLeft|Qt.AlignBottom)
        l.addWidget(self.bb,         3, 0, 1, 2, Qt.AlignRight|Qt.AlignBottom)
        l.setColumnStretch(1, 100)

        self.setModal(False)
        self.suppress.setVisible(False)
        self.do_resize()

    def retry(self):
        if self.retry_func is not None:
            self.accept()
            self.retry_func()

    def update_suppress_state(self):
        self.suppress.setText(_(
            'Hide the remaining %d error messages'%len(self.queue)))
        self.suppress.setVisible(len(self.queue) > 3)
        self.do_resize()

    def copy_to_clipboard(self, *args):
        d = QTextDocument()
        d.setHtml(self.msg_label.text())
        QApplication.clipboard().setText(
                u'calibre, version %s (%s, embedded-python: %s)\n%s: %s\n\n%s' %
                (__version__, sys.platform, isfrozen,
                    unicode(self.windowTitle()), unicode(d.toPlainText()),
                    unicode(self.det_msg.toPlainText())))
        if hasattr(self, 'ctc_button'):
            self.ctc_button.setText(_('Copied'))

    def toggle_det_msg(self, *args):
        vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(self.show_det_msg if vis else
                self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        h = self.sizeHint().height()
        self.setMinimumHeight(0)  # Needed as this gets set if det_msg is shown
        # Needed otherwise re-showing the box after showing det_msg causes the box
        # to not reduce in height
        self.setMaximumHeight(h)
        self.resize(QSize(self.WIDTH, h))

    def showEvent(self, ev):
        ret = QDialog.showEvent(self, ev)
        self.bb.button(self.bb.Close).setFocus(Qt.OtherFocusReason)
        return ret

    def show_error(self, title, msg, det_msg=u'', retry_func=None):
        self.queue.append((title, msg, det_msg, retry_func))
        self.update_suppress_state()
        self.pop()

    def pop(self):
        if not self.queue or self.isVisible():
            return
        title, msg, det_msg, retry_func = self.queue.pop(0)
        self.setWindowTitle(title)
        self.msg_label.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.det_msg_toggle.setText(self.show_det_msg)
        self.det_msg_toggle.setVisible(True)
        self.suppress.setChecked(False)
        self.update_suppress_state()
        if not det_msg:
            self.det_msg_toggle.setVisible(False)
        self.retry_button.setVisible(retry_func is not None)
        self.retry_func = retry_func
        self.do_resize()
        self.show()

    def done(self, r):
        if self.suppress.isChecked():
            self.queue = []
        QDialog.done(self, r)
        self.do_pop.emit()
Exemple #36
0
class BulkSeries(BulkBase):

    def setup_ui(self, parent):
        self.make_widgets(parent, EditWithComplete)
        values = self.all_values = list(self.db.all_custom(num=self.col_id))
        values.sort(key=sort_key)
        self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon)
        self.main_widget.setMinimumContentsLength(25)
        self.widgets.append(QLabel('', parent))
        w = QWidget(parent)
        layout = QHBoxLayout(w)
        layout.setContentsMargins(0, 0, 0, 0)
        self.remove_series = QCheckBox(parent)
        self.remove_series.setText(_('Clear series'))
        layout.addWidget(self.remove_series)
        self.idx_widget = QCheckBox(parent)
        self.idx_widget.setText(_('Automatically number books'))
        self.idx_widget.setToolTip('<p>' + _(
            'If not checked, the series number for the books will be set to 1. '
            'If checked, selected books will be automatically numbered, '
            'in the order you selected them. So if you selected '
            'Book A and then Book B, Book A will have series number 1 '
            'and Book B series number 2.') + '</p>')
        layout.addWidget(self.idx_widget)
        self.force_number = QCheckBox(parent)
        self.force_number.setText(_('Force numbers to start with '))
        self.force_number.setToolTip('<p>' + _(
            'Series will normally be renumbered from the highest '
            'number in the database for that series. Checking this '
            'box will tell calibre to start numbering from the value '
            'in the box') + '</p>')
        layout.addWidget(self.force_number)
        self.series_start_number = QDoubleSpinBox(parent)
        self.series_start_number.setMinimum(0.0)
        self.series_start_number.setMaximum(9999999.0)
        self.series_start_number.setProperty("value", 1.0)
        layout.addWidget(self.series_start_number)
        self.series_increment = QDoubleSpinBox(parent)
        self.series_increment.setMinimum(0.00)
        self.series_increment.setMaximum(99999.0)
        self.series_increment.setProperty("value", 1.0)
        self.series_increment.setToolTip('<p>' + _(
            'The amount by which to increment the series number '
            'for successive books. Only applicable when using '
            'force series numbers.') + '</p>')
        self.series_increment.setPrefix('+')
        layout.addWidget(self.series_increment)
        layout.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.widgets.append(w)
        self.idx_widget.stateChanged.connect(self.a_c_checkbox_changed)
        self.force_number.stateChanged.connect(self.a_c_checkbox_changed)
        self.series_start_number.valueChanged.connect(self.a_c_checkbox_changed)
        self.series_increment.valueChanged.connect(self.a_c_checkbox_changed)
        self.remove_series.stateChanged.connect(self.a_c_checkbox_changed)
        self.main_widget
        self.ignore_change_signals = False

    def a_c_checkbox_changed(self):
        def disable_numbering_checkboxes(idx_widget_enable):
            if idx_widget_enable:
                self.idx_widget.setEnabled(True)
            else:
                self.idx_widget.setChecked(False)
                self.idx_widget.setEnabled(False)
            self.force_number.setChecked(False)
            self.force_number.setEnabled(False)
            self.series_start_number.setEnabled(False)
            self.series_increment.setEnabled(False)

        if self.ignore_change_signals:
            return
        self.ignore_change_signals = True
        apply_changes = False
        if self.remove_series.isChecked():
            self.main_widget.setText('')
            self.main_widget.setEnabled(False)
            disable_numbering_checkboxes(idx_widget_enable=False)
            apply_changes = True
        elif self.main_widget.text():
            self.remove_series.setEnabled(False)
            self.idx_widget.setEnabled(True)
            apply_changes = True
        else:  # no text, no clear. Basically reinitialize
            self.main_widget.setEnabled(True)
            self.remove_series.setEnabled(True)
            disable_numbering_checkboxes(idx_widget_enable=False)
            apply_changes = False

        self.force_number.setEnabled(self.idx_widget.isChecked())
        self.series_start_number.setEnabled(self.force_number.isChecked())
        self.series_increment.setEnabled(self.force_number.isChecked())

        self.ignore_change_signals = False
        self.a_c_checkbox.setChecked(apply_changes)

    def initialize(self, book_id):
        self.idx_widget.setChecked(False)
        self.main_widget.set_separator(None)
        self.main_widget.update_items_cache(self.all_values)
        self.main_widget.setEditText('')
        self.a_c_checkbox.setChecked(False)

    def getter(self):
        n = unicode(self.main_widget.currentText()).strip()
        autonumber = self.idx_widget.checkState()
        force = self.force_number.checkState()
        start = self.series_start_number.value()
        remove = self.remove_series.checkState()
        increment = self.series_increment.value()
        return n, autonumber, force, start, remove, increment

    def commit(self, book_ids, notify=False):
        if not self.a_c_checkbox.isChecked():
            return
        val, update_indices, force_start, at_value, clear, increment = self.gui_val
        val = None if clear else self.normalize_ui_val(val)
        if clear or val != '':
            extras = []
            for book_id in book_ids:
                if clear:
                    extras.append(None)
                    continue
                if update_indices:
                    if force_start:
                        s_index = at_value
                        at_value += increment
                    elif tweaks['series_index_auto_increment'] != 'const':
                        s_index = self.db.get_next_cc_series_num_for(val, num=self.col_id)
                    else:
                        s_index = 1.0
                else:
                    s_index = self.db.get_custom_extra(book_id, num=self.col_id,
                                                       index_is_id=True)
                extras.append(s_index)
            self.db.set_custom_bulk(book_ids, val, extras=extras,
                                   num=self.col_id, notify=notify)
Exemple #37
0
class ConfigWidget(QWidget):

    # GUI definition
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.ll = QHBoxLayout()
        self.l.addLayout(self.ll)

        self.label_exe = QLabel(_('&Prince executable:'))
        self.ll.addWidget(self.label_exe)

        self.exe = QLineEdit(self)
        self.exe.setText(prefs['prince_exe'])
        self.exe.setToolTip(_('<qt>Executable for the Prince program (command-line interface)</qt>'))
        self.ll.addWidget(self.exe)
        self.label_exe.setBuddy(self.exe)

        self.browse = QPushButton(_('&Browse') + '...', self)
        self.browse.setToolTip(_('<qt>Search the Prince executable in your computer</qt>'))
        self.browse.clicked.connect(self.select_exe)
        self.ll.addWidget(self.browse)

        self.lll = QHBoxLayout()
        self.l.addLayout(self.lll)

        self.label_fmts = QLabel(_('Preferred &formats:'))
        self.lll.addWidget(self.label_fmts)

        self.fmts = QLineEdit(self)
        self.fmts.setText(','.join(prefs['formats']))
        self.fmts.setToolTip(_('<qt>Comma-separated list of preferred formats to use as source, the first that matches will be used</qt>'))
        self.lll.addWidget(self.fmts)
        self.label_fmts.setBuddy(self.fmts)

        self.add_book = QCheckBox(_('&Add PDF to the book record'))
        self.add_book.setToolTip(_('<qt>Add the converted PDF to the selected book record</qt>'))
        self.add_book.setChecked(prefs['add_book'])
        self.l.addWidget(self.add_book)

        self.show_css = QCheckBox(_('&Show CSS in the Convert dialog'))
        self.show_css.setToolTip(_('<qt>Show by default the stylesheets in the Convert dialog</qt>'))
        self.show_css.setChecked(prefs['show_CSS'])
        self.l.addWidget(self.show_css)

        self.css_layout = QVBoxLayout()

        self.llll = QHBoxLayout()
        self.css_layout.addLayout(self.llll)

        self.css_list = QComboBox()
        self.css_list.setToolTip(_('<qt>List of custom stylesheets defined. Select one to edit</qt>'))
        self.css_list.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.CSS_list = prefs['custom_CSS_list'].copy()
        self.default_CSS = prefs['default_CSS']
        if 'custom_CSS' in prefs:
            self.CSS_list[_('old')] = prefs['custom_CSS']
            self.default_CSS = _('old')
        if self.default_CSS not in self.CSS_list:
            self.default_CSS = sorted(self.CSS_list, key=lambda x: x.lower())[0]
        for key in sorted(self.CSS_list, key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(self.default_CSS))
        self.css_list.currentIndexChanged.connect(self.set_css)
        self.llll.addWidget(self.css_list)

        self.css_rename = QPushButton(_('Re&name'))
        self.css_rename.setToolTip(_('<qt>Rename the current stylesheet to the name on the right</qt>'))
        self.css_rename.clicked.connect(self.rename_css)
        self.css_rename.setEnabled(False)
        self.llll.addWidget(self.css_rename)

        self.css_name = QLineEdit(self)
        self.css_name.setToolTip(_('<qt>Name for the new or renamed stylesheet</qt>'))
        self.css_name.setText(self.css_list.currentText())
        self.css_name.textChanged.connect(self.check_names)
        self.llll.addWidget(self.css_name)

        self.css_add = QPushButton(_('A&dd'))
        self.css_add.setToolTip(_('<qt>Add a new empty stylesheet with the name on the left</qt>'))
        self.css_add.clicked.connect(self.add_css)
        self.css_add.setEnabled(False)
        self.llll.addWidget(self.css_add)

        self.css_remove = QPushButton(_('Re&move'))
        self.css_remove.setToolTip(_('<qt>Remove the current stylesheet</qt>'))
        self.css_remove.clicked.connect(self.remove_css)
        self.llll.addWidget(self.css_remove)

        self.css = TextEditWithTooltip()
        self.css.setLineWrapMode(TextEditWithTooltip.NoWrap)
        self.css.load_text(self.CSS_list[unicode(self.css_list.currentText())],'css')
        self.css.setToolTip(_('<qt>Custom stylesheet that will be applied, if selected, to all Prince PDF conversions</qt>'))
        self.css_layout.addWidget(self.css)

        self.css_templates = QLabel(_('Book metadata can be used in the stylesheet. Anything between %(s1)s and %(s2)s will be processed as a calibre template. For instance, %(s3)s in the stylesheet will be replaced with the book title in the conversion.') % \
          {'s1':'<span style="font-family:monospace ; font-weight:bold">@{@</span>', \
           's2':'<span style="font-family:monospace ; font-weight:bold">@}@</span>', \
           's3':'<span style="font-family:monospace ; font-weight:bold">@{@{title}@}@</span>'})
        self.css_templates.setWordWrap(True)
        self.css_layout.addWidget(self.css_templates)

        self.css_box = QGroupBox(_('&Custom CSS:'))
        self.css_box.setLayout(self.css_layout)
        self.l.addWidget(self.css_box)

        self.lllll = QHBoxLayout()
        self.lllll.setAlignment(Qt.AlignLeft)
        self.l.addLayout(self.lllll)

        self.defaults = QPushButton(_('&Restore defaults'))
        self.defaults.setToolTip(_('<qt>Restore the default settings</qt>'))
        self.defaults.clicked.connect(self.restore_defaults)
        self.lllll.addWidget(self.defaults, alignment=Qt.AlignLeft)

        self.warning = QLabel(_('<b>Warning</b>: Deletes modified stylesheets'))
        self.lllll.addWidget(self.warning)

        self.adjustSize()

    def select_exe(self):
        '''
        Create a dialog to select the Prince executable
        '''
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        filename = dialog.getOpenFileName(self, _('Select Prince executable'), '', '')
        if filename:
            try:
                self.exe.setText(filename)
            except(TypeError):
                self.exe.setText(filename[0])

    def restore_defaults(self):
        '''
        Restore the default settings
        '''
        self.exe.setText(prefs.defaults['prince_exe'])
        self.fmts.setText(','.join(prefs.defaults['formats']).lower())
        self.show_css.setChecked(prefs.defaults['show_CSS'])
        self.add_book.setChecked(prefs.defaults['add_book'])
        self.css_list.currentIndexChanged.disconnect()
        self.css_list.clear()
        self.CSS_list = prefs.defaults['custom_CSS_list'].copy()
        self.default_CSS = prefs.defaults['default_CSS']
        for key in sorted(self.CSS_list, key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(self.default_CSS))
        self.css_name.setText(self.default_CSS)
        self.css.load_text(self.CSS_list[unicode(self.css_list.currentText())],'css')
        self.css_list.currentIndexChanged.connect(self.set_css)

    def save_settings(self):
        '''
        Save the current settings
        '''
        prefs['prince_exe'] = unicode(self.exe.text())
        prefs['formats'] = unicode(self.fmts.text().lower()).split(',')
        prefs['show_CSS'] = self.show_css.isChecked()
        prefs['add_book'] = self.add_book.isChecked()
        self.set_css()
        prefs['default_CSS'] = self.default_CSS
        prefs['custom_CSS_list'] = self.CSS_list.copy()
        if 'custom_CSS' in prefs:
            del prefs['custom_CSS']

    def set_css(self):
        '''
        Fill the CSS text box with the selected stylesheet
        '''
        self.CSS_list[self.default_CSS] = unicode(self.css.toPlainText())
        self.default_CSS = unicode(self.css_list.currentText())
        self.css.load_text(self.CSS_list[self.default_CSS],'css')
        self.css_name.setText(self.css_list.currentText())

    def add_css(self):
        '''
        Add a new stylesheet
        '''
        from calibre.gui2 import error_dialog

        name = unicode(self.css_name.text())
        if name in self.CSS_list:
            error_dialog(self, _('Cannot add stylesheet'), _('A stylesheet with the name "%s" is already defined, use a different name.') % name, show=True)
        else:
            self.CSS_list[name] = ''
            self.css_list.addItem(name, name)
            self.css_list.setCurrentIndex(self.css_list.findText(name))
            self.css_add.setEnabled(False)
            self.css_rename.setEnabled(False)

    def remove_css(self):
        '''
        Remove an existing stylesheet
        '''
        from calibre.gui2 import error_dialog

        if (self.css_list.count() > 1):
            self.css_list.currentIndexChanged.disconnect()
            self.css_list.removeItem(self.css_list.currentIndex())
            del self.CSS_list[self.default_CSS]
            self.default_CSS = unicode(self.css_list.currentText())
            self.css.load_text(self.CSS_list[self.default_CSS],'css')
            self.css_list.currentIndexChanged.connect(self.set_css)
            self.css_name.setText(self.css_list.currentText())
        else:
            error_dialog(self, _('Cannot delete the last stylesheet'), _('The last stylesheet cannot be removed. You can rename it and/or remove its contents.'), show=True)

    def rename_css(self):
        '''
        Rename a stylesheet
        '''
        from calibre.gui2 import error_dialog

        name = unicode(self.css_name.text())
        if name in self.CSS_list:
            error_dialog(self, _('Cannot rename stylesheet'), _('A stylesheet with the name "%s" is already defined, use a different name.') % name, show=True)
        else:
            self.CSS_list[name] = self.CSS_list.pop(self.default_CSS)
            self.css_list.setItemText(self.css_list.currentIndex(),name)
            self.default_CSS = name

    def check_names(self, text):
        name = unicode(text)
        if name in self.CSS_list:
            self.css_add.setEnabled(False)
            self.css_rename.setEnabled(False)
        else:
            self.css_add.setEnabled(True)
            self.css_rename.setEnabled(True)
Exemple #38
0
class HistoryWidget(QDialog):
    """
    class HistonWidget
    """

    _v_curve_colors = [Qt.white, Qt.gray, Qt.red, Qt.green, Qt.blue, Qt.cyan, Qt.magenta, Qt.darkYellow]
    _v_curve_checked = [True, True, True, True, True, True, True, True]

    def __init__(self, parent=None):
        super(HistoryWidget, self).__init__(parent)
        self.setObjectName("HistoryWidget")
        self.resize(800, 480)
        self.setWindowTitle("历史数据查看")

        # layout - top
        horiLayoutTop = QHBoxLayout()

        buttonQuit = QPushButton(self)
        buttonQuit.setObjectName("buttonQuit")
        horiLayoutTop.addSpacing(25)
        horiLayoutTop.addWidget(buttonQuit, 0, Qt.AlignLeft)
        horiLayoutTop.addStretch()

        # button-export
        buttonExport = QPushButton(self)
        buttonExport.setObjectName("buttonExport")
        horiLayoutTop.addWidget(buttonExport)
        horiLayoutTop.addStretch()

        # button-open
        buttonOpen = QPushButton(self)
        buttonOpen.setObjectName("buttonOpen")
        horiLayoutTop.addWidget(buttonOpen)
        horiLayoutTop.addStretch()

        formLayoutTime = QFormLayout()
        formLayoutTime.setFormAlignment(Qt.AlignVCenter)
        horiLayoutTop.addLayout(formLayoutTime)
        horiLayoutTop.addStretch()

        self.dateTimeEditStart = QDateTimeEdit(self)
        self.dateTimeEditStart.setObjectName("dateTimeEditStart")
        self.dateTimeEditStart.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        formLayoutTime.addRow("起始时间:", self.dateTimeEditStart)

        self.dateTimeEditEnd = QDateTimeEdit(self)
        self.dateTimeEditEnd.setObjectName("dateTimeEditEnd")
        self.dateTimeEditEnd.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        formLayoutTime.addRow("结束时间:", self.dateTimeEditEnd)

        # LBP
        formLayoutLBP = QFormLayout()
        formLayoutLBP.setFormAlignment(Qt.AlignVCenter)
        formLayoutLBP.setLabelAlignment(Qt.AlignRight)
        horiLayoutTop.addLayout(formLayoutLBP)
        horiLayoutTop.addStretch()
        self.checkBoxLBPMajor = QCheckBox("主", self)
        self.checkBoxLBPMajor.setProperty("curveColor", "#101010")
        self.checkBoxLBPMinor = QCheckBox("副", self)
        self.checkBoxLBPMinor.setProperty("curveColor", "#101010")
        formLayoutLBP.addRow("左刹车压力:", self.checkBoxLBPMajor)
        formLayoutLBP.addRow("", self.checkBoxLBPMinor)

        # RBP
        formLayoutRBP = QFormLayout()
        formLayoutRBP.setFormAlignment(Qt.AlignVCenter)
        formLayoutRBP.setLabelAlignment(Qt.AlignRight)
        horiLayoutTop.addLayout(formLayoutRBP)
        horiLayoutTop.addStretch()
        self.checkBoxRBPMajor = QCheckBox("主", self)
        self.checkBoxRBPMajor.setProperty("curveColor", "#101010")
        self.checkBoxRBPMinor = QCheckBox("副", self)
        self.checkBoxRBPMinor.setProperty("curveColor", "#101010")
        formLayoutRBP.addRow("右刹车压力:", self.checkBoxRBPMajor)
        formLayoutRBP.addRow("", self.checkBoxRBPMinor)

        # LRP
        formLayoutLRP = QFormLayout()
        formLayoutLRP.setFormAlignment(Qt.AlignVCenter)
        formLayoutLRP.setLabelAlignment(Qt.AlignRight)
        horiLayoutTop.addLayout(formLayoutLRP)
        horiLayoutTop.addStretch()
        self.checkBoxLRPTheory = QCheckBox("理论", self)
        self.checkBoxLRPTheory.setProperty("curveColor", "#101010")
        self.checkBoxLRPReal = QCheckBox("实际", self)
        self.checkBoxLRPReal.setProperty("curveColor", "#101010")
        formLayoutLRP.addRow("左转速:", self.checkBoxLRPTheory)
        formLayoutLRP.addRow("", self.checkBoxLRPReal)

        # RRP
        formLayoutRRP = QFormLayout()
        formLayoutRRP.setFormAlignment(Qt.AlignVCenter)
        formLayoutRRP.setLabelAlignment(Qt.AlignRight)
        horiLayoutTop.addLayout(formLayoutRRP)
        horiLayoutTop.addStretch()
        self.checkBoxRRPTheory = QCheckBox("理论", self)
        self.checkBoxRRPTheory.setProperty("curveColor", "#101010")
        self.checkBoxRRPReal = QCheckBox("实际", self)
        self.checkBoxRRPReal.setProperty("curveColor", "#101010")
        formLayoutRRP.addRow("右转速:", self.checkBoxRRPTheory)
        formLayoutRRP.addRow("", self.checkBoxRRPReal)

        # button-update
        buttonUpdate = QPushButton(self)
        buttonUpdate.setObjectName("buttonUpdate")
        horiLayoutTop.addWidget(buttonUpdate)
        horiLayoutTop.addStretch()

        # middle-curves
        self.curveHistory = CurveWidget("历史数据回放", True, self)
        self.curveHistory.setMaximumWidth(10e5)
        self.curveHistory.setScaleLabelFormat("yyyy/MM/dd\n  HH:mm:ss")
        self.curveHistory.clear()

        #
        vertLayoutMain = QVBoxLayout(self)
        vertLayoutMain.addLayout(horiLayoutTop)
        vertLayoutMain.addWidget(self.curveHistory)

        buttonQuit.clicked.connect(self.accept)
        buttonOpen.clicked.connect(self.buttonOpenClicked)
        buttonExport.clicked.connect(self.buttonExportClicked)
        self.dateTimeEditStart.dateTimeChanged.connect(self.dateTimeStartChanged)
        self.dateTimeEditEnd.dateTimeChanged.connect(self.dateTimeEndChanged)
        self.checkBoxLBPMajor.toggled.connect(self.checkBoxLBPMajorToggled)
        self.checkBoxLBPMinor.toggled.connect(self.checkBoxLBPMinorToggled)
        self.checkBoxRBPMajor.toggled.connect(self.checkBoxRBPMajorToggled)
        self.checkBoxRBPMinor.toggled.connect(self.checkBoxRBPMinorToggled)
        self.checkBoxLRPTheory.toggled.connect(self.checkBoxLRPTheoryToggled)
        self.checkBoxLRPReal.toggled.connect(self.checkBoxLRPRealToggled)
        self.checkBoxRRPTheory.toggled.connect(self.checkBoxRRPTheoryToggled)
        self.checkBoxRRPReal.toggled.connect(self.checkBoxRRPRealToggled)
        buttonUpdate.clicked.connect(self.buttonUpdateClicked)

        # finalLy initialize
        self.checkBoxLBPMajor.setChecked(self._v_curve_checked[0])
        self.checkBoxLBPMinor.setChecked(self._v_curve_checked[1])
        self.checkBoxRBPMajor.setChecked(self._v_curve_checked[2])
        self.checkBoxRBPMinor.setChecked(self._v_curve_checked[3])
        self.checkBoxLRPTheory.setChecked(self._v_curve_checked[4])
        self.checkBoxLRPReal.setChecked(self._v_curve_checked[5])
        self.checkBoxRRPTheory.setChecked(self._v_curve_checked[6])
        self.checkBoxRRPReal.setChecked(self._v_curve_checked[7])

    def buttonOpenClicked(self):
        fileDialog = QFileDialog(
            self, "打开历史数据文件", QApplication.applicationDirPath() + "/../data", "Database File (*.db *.mdb)"
        )
        if fileDialog.exec_() == QDialog.Rejected:
            return
        # clear curve
        self.curveHistory.clear()
        #
        filePaths = fileDialog.selectedFiles()
        if filePaths.isEmpty():
            return
        filePath = filePaths.first()
        if filePath.isEmpty():
            return
        # open database
        if not DatabaseMgr().open(filePath):
            return
        #
        startTime = QDateTime.fromMSecsSinceEpoch(DatabaseMgr().startTime())
        endTime = QDateTime.fromMSecsSinceEpoch(DatabaseMgr().endTime())
        self.dateTimeEditStart.setDateTimeRange(startTime, endTime)
        self.dateTimeEditEnd.setDateTimeRange(startTime, endTime)
        self.dateTimeEditEnd.setDateTime(endTime)
        self.dateTimeEditStart.setDateTime(startTime)

        # title of curve
        self.curveHistory.setTitle("历史数据回放" + "(" + QFileInfo(filePath).fileName() + ")")

    def buttonExportClicked(self):
        (filePaths, filter) = QFileDialog.getOpenFileNames(
            parent=self,
            caption="转换数据库文件为文本格式",
            directory=QApplication.applicationDirPath() + "/../data",
            filter="Database file (*.db * mdb)",
        )
        if not filePaths:
            return
        #
        if DatabaseMgr().convertToText(filePaths):
            QMessageBox.information(self, "格式转换", "转换成功!")
        else:
            QMessageBox.warning(self, "格式转换", "转换失败!")

    def dateTimeStartChanged(self, dateTime):
        dateTimeEnd = self.dateTimeEditEnd.dateTime()
        if dateTime > dateTimeEnd:
            self.dateTimeEditStart.setDateTime(dateTimeEnd)

    def dateTimeEndChanged(self, dateTime):
        dateTimeStart = self.dateTimeEditStart.dateTime()
        if dateTime < dateTimeStart:
            self.dateTimeEditEnd.setDateTime(dateTimeStart)

    def checkBoxLBPMajorToggled(self, checked):
        self._v_curve_checked[0] = checked

    def checkBoxLBPMinorToggled(self, checked):
        self._v_curve_checked[1] = checked

    def checkBoxRBPMajorToggled(self, checked):
        self._v_curve_checked[2] = checked

    def checkBoxRBPMinorToggled(self, checked):
        self._v_curve_checked[3] = checked

    def checkBoxLRPTheoryToggled(self, checked):
        self._v_curve_checked[4] = checked

    def checkBoxLRPRealToggled(self, checked):
        self._v_curve_checked[5] = checked

    def checkBoxRRPTheoryToggled(self, checked):
        self._v_curve_checked[6] = checked

    def checkBoxRRPRealToggled(self, checked):
        self._v_curve_checked[7] = checked

    def buttonUpdateClicked(self):
        # clear curve
        self.curveHistory.clear()

        points = []
        startTime = self.dateTimeEditStart.dateTime().toMSecsSinceEpoch()
        endTime = self.dateTimeEditEnd.dateTime().toMSecsSinceEpoch()

        # LBP-Major
        if self.checkBoxLBPMajor.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("lMBrakeP", points, startTime, endTime):
                self.curveHistory.addCurve("左刹压力-主", QPen(self.randomColor(0)), points)
        # LBP-Minor
        if self.checkBoxLBPMinor.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("lABrakeP", points, startTime, endTime):
                self.curveHistory.addCurve("左刹压力-副", QPen(self.randomColor(1)), points)
        # RBP-Major
        if self.checkBoxRBPMajor.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("rMBrakeP", points, startTime, endTime):
                self.curveHistory.addCurve("右刹压力-主", QPen(self.randomColor(2)), points)
        # RBP-Minor
        if self.checkBoxRBPMinor.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("rABrakeP", points, startTime, endTime):
                self.curveHistory.addCurve("右刹压力-副", QPen(self.randomColor(3)), points)

        # LRP-Theory
        if self.checkBoxLRPTheory.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("lTheorySpd", points, startTime, endTime):
                self.curveHistory.addCurve("左转速-理论", QPen(self.randomColor(4)), points)
        # LRP-Real
        if self.checkBoxLRPReal.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("lWheelSpd", points, startTime, endTime):
                self.curveHistory.addCurve("左转速-实际", QPen(self.randomColor(5)), points)
        # RRP-Theory
        if self.checkBoxRRPTheory.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("rTheorySpd", points, startTime, endTime):
                self.curveHistory.addCurve("右转速-理论", QPen(self.randomColor(6)), points)
        # RRP-Real
        if self.checkBoxRRPReal.isChecked():
            # read
            points.clear()
            if DatabaseMgr().read("rWheelSpd", points, startTime, endTime):
                self.curveHistory.addCurve("右转速-实际", QPen(self.randomColor(7)), points)

    @staticmethod
    def randomColor(index):
        return HistoryWidget._v_curve_colors[index]
Exemple #39
0
class OpdsDialog(QDialog):

    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db.new_api

        # The model for the book list
        self.model = OpdsBooksModel(None, self.dummy_books(), self.db)
        self.searchproxymodel = QSortFilterProxyModel(self)
        self.searchproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.searchproxymodel.setFilterKeyColumn(-1)
        self.searchproxymodel.setSourceModel(self.model)

        self.layout = QGridLayout()
        self.setLayout(self.layout)

        self.setWindowTitle('OPDS Client')
        self.setWindowIcon(icon)

        labelColumnWidths = []

        self.opdsUrlLabel = QLabel('OPDS URL: ')
        self.layout.addWidget(self.opdsUrlLabel, 0, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(0, 0).sizeHint().width())

        config.convertSingleStringOpdsUrlPreferenceToListOfStringsPreference()
        self.opdsUrlEditor = QComboBox(self)
        self.opdsUrlEditor.activated.connect(self.opdsUrlEditorActivated)
        self.opdsUrlEditor.addItems(prefs['opds_url'])
        self.opdsUrlEditor.setEditable(True)
        self.opdsUrlEditor.setInsertPolicy(QComboBox.InsertAtTop)
        self.layout.addWidget(self.opdsUrlEditor, 0, 1, 1, 3)
        self.opdsUrlLabel.setBuddy(self.opdsUrlEditor)

        buttonColumnNumber = 7
        buttonColumnWidths = []
        self.about_button = QPushButton('About', self)
        self.about_button.setAutoDefault(False)
        self.about_button.clicked.connect(self.about)
        self.layout.addWidget(self.about_button, 0, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(0, buttonColumnNumber).sizeHint().width()) 

        # Initially download the catalogs found in the root catalog of the URL
        # selected at startup.  Fail quietly on failing to open the URL
        catalogsTuple = self.model.downloadOpdsRootCatalog(self.gui, self.opdsUrlEditor.currentText(), False)
        print catalogsTuple
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1] # A dictionary of title->feedURL

        self.opdsCatalogSelectorLabel = QLabel('OPDS Catalog:')
        self.layout.addWidget(self.opdsCatalogSelectorLabel, 1, 0)
        labelColumnWidths.append(self.layout.itemAtPosition(1, 0).sizeHint().width())

        self.opdsCatalogSelector = QComboBox(self)
        self.opdsCatalogSelector.setEditable(False)
        self.opdsCatalogSelectorModel = QStringListModel(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setModel(self.opdsCatalogSelectorModel)
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)
        self.layout.addWidget(self.opdsCatalogSelector, 1, 1, 1, 3)

        self.download_opds_button = QPushButton('Download OPDS', self)
        self.download_opds_button.setAutoDefault(False)
        self.download_opds_button.clicked.connect(self.download_opds)
        self.layout.addWidget(self.download_opds_button, 1, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(1, buttonColumnNumber).sizeHint().width()) 

        # Search GUI
        self.searchEditor = QLineEdit(self)
        self.searchEditor.returnPressed.connect(self.searchBookList)
        self.layout.addWidget(self.searchEditor, 2, buttonColumnNumber - 2, 1, 2)

        self.searchButton = QPushButton('Search', self)
        self.searchButton.setAutoDefault(False)
        self.searchButton.clicked.connect(self.searchBookList)
        self.layout.addWidget(self.searchButton, 2, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(2, buttonColumnNumber).sizeHint().width())

        # The main book list
        self.library_view = QTableView(self)
        self.library_view.setAlternatingRowColors(True)
        self.library_view.setModel(self.searchproxymodel)
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.library_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.library_view.resizeColumnsToContents()
        self.layout.addWidget(self.library_view, 3, 0, 3, buttonColumnNumber + 1)

        self.hideNewsCheckbox = QCheckBox('Hide Newspapers', self)
        self.hideNewsCheckbox.clicked.connect(self.setHideNewspapers)
        self.hideNewsCheckbox.setChecked(prefs['hideNewspapers'])
        self.layout.addWidget(self.hideNewsCheckbox, 6, 0, 1, 3)

        self.hideBooksAlreadyInLibraryCheckbox = QCheckBox('Hide books already in library', self)
        self.hideBooksAlreadyInLibraryCheckbox.clicked.connect(self.setHideBooksAlreadyInLibrary)
        self.hideBooksAlreadyInLibraryCheckbox.setChecked(prefs['hideBooksAlreadyInLibrary'])
        self.layout.addWidget(self.hideBooksAlreadyInLibraryCheckbox, 7, 0, 1, 3)

        # Let the checkbox initial state control the filtering
        self.model.setFilterBooksThatAreNewspapers(self.hideNewsCheckbox.isChecked())
        self.model.setFilterBooksThatAreAlreadyInLibrary(self.hideBooksAlreadyInLibraryCheckbox.isChecked())

        self.downloadButton = QPushButton('Download selected books', self)
        self.downloadButton.setAutoDefault(False)
        self.downloadButton.clicked.connect(self.downloadSelectedBooks)
        self.layout.addWidget(self.downloadButton, 6, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(6, buttonColumnNumber).sizeHint().width()) 

        self.fixTimestampButton = QPushButton('Fix timestamps of selection', self)
        self.fixTimestampButton.setAutoDefault(False)
        self.fixTimestampButton.clicked.connect(self.fixBookTimestamps)
        self.layout.addWidget(self.fixTimestampButton, 7, buttonColumnNumber)
        buttonColumnWidths.append(self.layout.itemAtPosition(7, buttonColumnNumber).sizeHint().width()) 

        # Make all columns of the grid layout the same width as the button column
        buttonColumnWidth = max(buttonColumnWidths)
        for columnNumber in range(0, buttonColumnNumber):
            self.layout.setColumnMinimumWidth(columnNumber, buttonColumnWidth)

        # Make sure the first column isn't wider than the labels it holds
        labelColumnWidth = max(labelColumnWidths)
        self.layout.setColumnMinimumWidth(0, labelColumnWidth)

        self.resize(self.sizeHint())

    def opdsUrlEditorActivated(self, text):
        prefs['opds_url'] = config.saveOpdsUrlCombobox(self.opdsUrlEditor)
        catalogsTuple = self.model.downloadOpdsRootCatalog(self.gui, self.opdsUrlEditor.currentText(), True)
        firstCatalogTitle = catalogsTuple[0]
        self.currentOpdsCatalogs = catalogsTuple[1] # A dictionary of title->feedURL
        self.opdsCatalogSelectorModel.setStringList(self.currentOpdsCatalogs.keys())
        self.opdsCatalogSelector.setCurrentText(firstCatalogTitle)

    def setHideNewspapers(self, checked):
        prefs['hideNewspapers'] = checked
        self.model.setFilterBooksThatAreNewspapers(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def setHideBooksAlreadyInLibrary(self, checked):
        prefs['hideBooksAlreadyInLibrary'] = checked
        self.model.setFilterBooksThatAreAlreadyInLibrary(checked)
        self.resizeAllLibraryViewLinesToHeaderHeight()

    def searchBookList(self):
        searchString = self.searchEditor.text()
        print "starting book list search for: %s" % searchString
        self.searchproxymodel.setFilterFixedString(searchString)

    def about(self):
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About the OPDS Client plugin', text.decode('utf-8'))

    def download_opds(self):
        opdsCatalogUrl = self.currentOpdsCatalogs.get(self.opdsCatalogSelector.currentText(), None)
        if opdsCatalogUrl is None:
            # Just give up quietly
            return
        self.model.downloadOpdsCatalog(self.gui, opdsCatalogUrl)
        if self.model.isCalibreOpdsServer():
            self.model.downloadMetadataUsingCalibreRestApi(self.opdsUrlEditor.currentText())
        self.library_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.library_view.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.resizeAllLibraryViewLinesToHeaderHeight()
        self.resize(self.sizeHint())

    def config(self):
        self.do_user_config(parent=self)

    def downloadSelectedBooks(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.downloadBook(book)

    def downloadBook(self, book):
        if len(book.links) > 0:
            self.gui.download_ebook(book.links[0])

    def fixBookTimestamps(self):
        selectionmodel = self.library_view.selectionModel()
        if selectionmodel.hasSelection():
            rows = selectionmodel.selectedRows()
            for row in reversed(rows):
                book = row.data(Qt.UserRole)
                self.fixBookTimestamp(book)

    def fixBookTimestamp(self, book):
        bookTimestamp = book.timestamp
        identicalBookIds = self.findIdenticalBooksForBooksWithMultipleAuthors(book)
        bookIdToValMap = {}
        for identicalBookId in identicalBookIds:
            bookIdToValMap[identicalBookId] = bookTimestamp
        if len(bookIdToValMap) < 1:
            print "Failed to set timestamp of book: %s" % book
        self.db.set_field('timestamp', bookIdToValMap)

    def findIdenticalBooksForBooksWithMultipleAuthors(self, book):
        authorsList = book.authors
        if len(authorsList) < 2:
            return self.db.find_identical_books(book)
        # Try matching the authors one by one
        identicalBookIds = set()
        for author in authorsList:
            singleAuthorBook = Metadata(book.title, [author])
            singleAuthorIdenticalBookIds = self.db.find_identical_books(singleAuthorBook)
            identicalBookIds = identicalBookIds.union(singleAuthorIdenticalBookIds)
        return identicalBookIds

    def dummy_books(self):
        dummy_author = ' ' * 40
        dummy_title = ' ' * 60
        books_list = []
        for line in range (1, 10):
            book = DynamicBook()
            book.author = dummy_author
            book.title = dummy_title
            book.updated = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S+00:00')
            book.id = ''
            books_list.append(book)
        return books_list

    def resizeAllLibraryViewLinesToHeaderHeight(self):
        rowHeight = self.library_view.horizontalHeader().height()
        for rowNumber in range (0, self.library_view.model().rowCount()):
            self.library_view.setRowHeight(rowNumber, rowHeight)
class writeIn(QWidget):  # 手写板识别
    def __init__(self):
        super(writeIn, self).__init__()
        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()
        self.detect_model = DBNet()

    def __InitData(self):
        '''
                  初始化成员变量
        '''
        self.__paintBoard = PaintBoard(self)
        # 获取颜色列表(字符串类型)
        self.__colorList = QColor.colorNames()

    def __InitView(self):
        '''
                  初始化界面
        '''
        self.setWindowIcon(QtGui.QIcon('./icon.jpg'))
        # self.resize(640, 560)
        # self.setFixedSize(self.width(), self.height())
        self.setWindowTitle("手写板识别")

        self.label_name = QLabel('识别结果:', self)
        self.label_name.setGeometry(530, 10, 120, 30)

        self.edit = QTextEdit(self)
        self.edit.setGeometry(530, 50, 120, 90)

        # 新建一个水平布局作为本窗体的主布局
        main_layout = QHBoxLayout(self)
        # 设置主布局内边距以及控件间距为10px
        main_layout.setSpacing(10)
        img_layout = QVBoxLayout()
        img_layout.setContentsMargins(10, 10, 10, 10)

        # 在主界面左侧放置画板
        img_layout.addWidget(self.__paintBoard)
        #
        # self.__btn_Pic = QLabel("过程演示图")
        # self.__btn_Pic.setParent(self)
        # img_layout.addWidget(self.__btn_Pic)
        self.label_name6 = QLabel('过程演示图', self)
        self.label_name6.setGeometry(10, 300, 480, 280)
        self.label_name6.setStyleSheet("QLabel{background:white;}"
                                       "QLabel{color:rgb(0,0,0,120);font-size:15px;font-weight:bold;font-family:宋体;}"
                                       )
        self.label_name6.setAlignment(QtCore.Qt.AlignCenter)
        img_layout.addWidget(self.label_name6)

        main_layout.addLayout(img_layout)  # 将子布局加入主布局

        # 新建垂直子布局用于放置按键
        sub_layout = QVBoxLayout()
        # 设置此子布局和内部控件的间距为5px
        sub_layout.setContentsMargins(5, 5, 5, 5)

        splitter = QSplitter(self)  # 占位符
        sub_layout.addWidget(splitter)
        sub_layout.addWidget(self.label_name)
        sub_layout.addWidget(self.edit)

        self.__btn_Recognize = QPushButton("开始识别")
        self.__btn_Recognize.setParent(self)
        self.__btn_Recognize.clicked.connect(self.on_btn_Recognize_Clicked)
        sub_layout.addWidget(self.__btn_Recognize)

        self.__btn_Clear = QPushButton("清空画板")
        self.__btn_Clear.setParent(self)  # 设置父对象为本界面
        # 将按键按下信号与画板清空函数相关联
        self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_return = QPushButton("返回")
        self.__btn_return.setParent(self)
        self.__btn_return.clicked.connect(self.slot_btn_function)
        sub_layout.addWidget(self.__btn_return)

        self.__btn_Quit = QPushButton("退出")
        self.__btn_Quit.setParent(self)
        self.__btn_Quit.clicked.connect(self.Quit)
        sub_layout.addWidget(self.__btn_Quit)

        self.__btn_Save = QPushButton("保存作品")
        self.__btn_Save.setParent(self)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__cbtn_Eraser = QCheckBox("使用橡皮擦")
        self.__cbtn_Eraser.setParent(self)
        self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        sub_layout.addWidget(self.__cbtn_Eraser)

        self.__label_penThickness = QLabel(self)
        self.__label_penThickness.setText("画笔粗细")
        self.__label_penThickness.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penThickness)

        self.__spinBox_penThickness = QSpinBox(self)
        self.__spinBox_penThickness.setMaximum(20)
        self.__spinBox_penThickness.setMinimum(2)
        self.__spinBox_penThickness.setValue(10)  # 默认粗细为10
        self.__spinBox_penThickness.setSingleStep(2)  # 最小变化值为2
        self.__spinBox_penThickness.valueChanged.connect(
            self.on_PenThicknessChange)  # 关联spinBox值变化信号和函数on_PenThicknessChange
        sub_layout.addWidget(self.__spinBox_penThickness)

        main_layout.addLayout(sub_layout)  # 将子布局加入主布局

    def on_PenThicknessChange(self):
        penThickness = self.__spinBox_penThickness.value()
        self.__paintBoard.ChangePenThickness(penThickness)

    def on_btn_Save_Clicked(self):
        savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')
        print(savePath)
        if savePath[0] == "":
            print("Save cancel")
            return
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath[0])
        print(savePath[0])

    def Quit(self):
        self.close()

    def on_cbtn_Eraser_clicked(self):
        if self.__cbtn_Eraser.isChecked():
            self.__paintBoard.EraserMode = True  # 进入橡皮擦模式
        else:
            self.__paintBoard.EraserMode = False  # 退出橡皮擦模式

    def on_btn_Recognize_Clicked(self):  # 识别过程**
        savePath = "./text.png"
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath)
        print(savePath)

        resultPath, box_list = self.detect_model.predict(savePath)

        jpg = QtGui.QPixmap(resultPath).scaled(self.label_name6.width(), self.label_name6.height())
        self.label_name6.setPixmap(jpg)
        print(savePath)

        self.edit.setText('测试文本1')

    def slot_btn_function(self):
        self.hide()
        self.f = FirstUi()
        self.f.show()
class HotkeyWidget(QWidget):
    def __init__(self, prefs, configName, title):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)
        
        self.configName = configName
    
        self.hotkeyLayout = QHBoxLayout()
        self.l.addLayout(self.hotkeyLayout)
        
        enabledLabel = QLabel(title)
        self.hotkeyLayout.addWidget(enabledLabel)
        
        self.enabledBox = QCheckBox()
        self.hotkeyLayout.addWidget(self.enabledBox)
        self.enabledBox.setChecked(prefs[configName + '_hotkey_enabled'])
        
        hotkeyLayout2 = QHBoxLayout()
        self.l.addLayout(hotkeyLayout2)
        
        ctrlLabel = QLabel("Ctrl")
        self.ctrlBox = QCheckBox()
        self.ctrlBox.setChecked(prefs[configName + '_hotkey_ctrl'])
        
        ctrlLabel.setBuddy(self.ctrlBox)
        hotkeyLayout2.addWidget(ctrlLabel)
        hotkeyLayout2.addWidget(self.ctrlBox)
        
        altLabel = QLabel("Alt")
        self.altBox = QCheckBox()
        self.altBox.setChecked(prefs[configName + '_hotkey_alt'])
        
        altLabel.setBuddy(self.altBox)
        hotkeyLayout2.addWidget(altLabel)
        hotkeyLayout2.addWidget(self.altBox)
        
        shiftLabel = QLabel("Shift")
        self.shiftBox = QCheckBox()
        self.shiftBox.setChecked(prefs[configName + '_hotkey_shift'])
        
        shiftLabel.setBuddy(self.shiftBox)
        hotkeyLayout2.addWidget(shiftLabel)
        hotkeyLayout2.addWidget(self.shiftBox)
        
        self.keycodeBox = QComboBox()
        for key, value in keycodes.iteritems():
            self.keycodeBox.addItem(key, value)
            
        index = self.keycodeBox.findData(prefs[configName + '_hotkey_keycode'])
        if index != -1:
            self.keycodeBox.setCurrentIndex(index)
            
        hotkeyLayout2.addWidget(self.keycodeBox)
        
    def save_settings(self, prefs):
        prefs[self.configName + '_hotkey_enabled'] = self.enabledBox.isChecked()
        prefs[self.configName + '_hotkey_ctrl'] = self.ctrlBox.isChecked()
        prefs[self.configName + '_hotkey_alt'] = self.altBox.isChecked()
        prefs[self.configName + '_hotkey_shift'] = self.shiftBox.isChecked()
        prefs[self.configName + '_hotkey_keycode'] = keycodes[unicode(self.keycodeBox.currentText())]
        
Exemple #42
0
class write_num(QWidget):
    def __init__(self):
        super(write_num, self).__init__()
        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()

    def __InitData(self):
        '''
                  初始化成员变量
        '''
        self.__paintBoard = PaintBoard(self)
        # 获取颜色列表(字符串类型)
        self.__colorList = QColor.colorNames()

    def __InitView(self):
        '''
                  初始化界面
        '''
        self.setWindowIcon(QtGui.QIcon('./icon.jpg'))
        self.resize(640, 600)
        self.setFixedSize(self.width(), self.height())
        self.setWindowTitle("手写数字识别")

        self.label_name = QLabel('哔哩哔哩大学', self)
        self.label_name.setGeometry(500, 5, 120, 30)

        self.label_name = QLabel('知识学院', self)
        self.label_name.setGeometry(500, 35, 100, 30)

        self.label_name = QLabel('野生技术协会', self)
        self.label_name.setGeometry(500, 65, 100, 30)

        self.label_name = QLabel('王荣胜', self)
        self.label_name.setGeometry(500, 95, 100, 30)

        self.edit = QTextEdit(self)
        self.edit.setGeometry(510, 160, 110, 60)

        # 新建一个水平布局作为本窗体的主布局
        main_layout = QHBoxLayout(self)
        # 设置主布局内边距以及控件间距为10px
        main_layout.setSpacing(10)

        # 在主界面左侧放置画板
        main_layout.addWidget(self.__paintBoard)

        # 新建垂直子布局用于放置按键
        sub_layout = QVBoxLayout()

        # 设置此子布局和内部控件的间距为5px
        sub_layout.setContentsMargins(5, 5, 5, 5)

        splitter = QSplitter(self)  # 占位符
        sub_layout.addWidget(splitter)

        self.__btn_Recognize = QPushButton("开始识别")
        self.__btn_Recognize.setParent(self)
        self.__btn_Recognize.clicked.connect(self.on_btn_Recognize_Clicked)
        sub_layout.addWidget(self.__btn_Recognize)

        self.__btn_Clear = QPushButton("清空画板")
        self.__btn_Clear.setParent(self)  # 设置父对象为本界面
        # 将按键按下信号与画板清空函数相关联
        self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_return = QPushButton("返回")
        self.__btn_return.setParent(self)  # 设置父对象为本界面
        self.__btn_return.clicked.connect(self.slot_btn_function)
        sub_layout.addWidget(self.__btn_return)

        self.__btn_Quit = QPushButton("退出")
        self.__btn_Quit.setParent(self)  # 设置父对象为本界面
        self.__btn_Quit.clicked.connect(self.Quit)
        sub_layout.addWidget(self.__btn_Quit)

        self.__btn_Save = QPushButton("保存作品")
        self.__btn_Save.setParent(self)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__cbtn_Eraser = QCheckBox("使用橡皮擦")
        self.__cbtn_Eraser.setParent(self)
        self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        sub_layout.addWidget(self.__cbtn_Eraser)

        self.__label_penThickness = QLabel(self)
        self.__label_penThickness.setText("画笔粗细")
        self.__label_penThickness.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penThickness)

        self.__spinBox_penThickness = QSpinBox(self)
        self.__spinBox_penThickness.setMaximum(20)
        self.__spinBox_penThickness.setMinimum(2)
        self.__spinBox_penThickness.setValue(10)  # 默认粗细为10
        self.__spinBox_penThickness.setSingleStep(2)  # 最小变化值为2
        self.__spinBox_penThickness.valueChanged.connect(self.on_PenThicknessChange)  # 关联spinBox值变化信号和函数on_PenThicknessChange
        sub_layout.addWidget(self.__spinBox_penThickness)

        self.__label_penColor = QLabel(self)
        self.__label_penColor.setText("画笔颜色")
        self.__label_penColor.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penColor)

        self.__comboBox_penColor = QComboBox(self)
        self.__fillColorList(self.__comboBox_penColor)  # 用各种颜色填充下拉列表
        self.__comboBox_penColor.currentIndexChanged.connect(self.on_PenColorChange)  # 关联下拉列表的当前索引变更信号与函数on_PenColorChange
        sub_layout.addWidget(self.__comboBox_penColor)

        main_layout.addLayout(sub_layout)  # 将子布局加入主布局

    def __fillColorList(self, comboBox):

        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    def on_PenColorChange(self):
        color_index = self.__comboBox_penColor.currentIndex()
        color_str = self.__colorList[color_index]
        self.__paintBoard.ChangePenColor(color_str)

    def on_PenThicknessChange(self):
        penThickness = self.__spinBox_penThickness.value()
        self.__paintBoard.ChangePenThickness(penThickness)

    def on_btn_Save_Clicked(self):
        savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')
        print(savePath)
        if savePath[0] == "":
            print("Save cancel")
            return
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath[0])
        print(savePath[0])

    def Quit(self):
        self.close()

    def on_cbtn_Eraser_clicked(self):
        if self.__cbtn_Eraser.isChecked():
            self.__paintBoard.EraserMode = True  # 进入橡皮擦模式
        else:
            self.__paintBoard.EraserMode = False  # 退出橡皮擦模式

    def on_btn_Recognize_Clicked(self):
        config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
        config.gpu_options.per_process_gpu_memory_fraction = 0.3
        tf.compat.v1.keras.backend.set_session(tf.compat.v1.Session(config=config))
        savePath = "./text.png"
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath)
        print(savePath)
        # 加载图像
        img = keras.preprocessing.image.load_img(savePath, target_size=(28, 28))
        img = img.convert('L')
        x = keras.preprocessing.image.img_to_array(img)
        x = abs(255-x)
        #x = x.reshape(28,28)
        x = np.expand_dims(x, axis=0)
        x=x/255.0
        new_model = keras.models.load_model('./my_model.h5')
        prediction = new_model.predict(x)
        output = np.argmax(prediction, axis=1)
        #print("手写数字识别为:" + str(output[0]))
        self.edit.setText('识别的手写数字为:' + str(output[0]))

    def slot_btn_function(self):
        self.hide()  # 隐藏此窗口
        self.f = FirstUi()  # 将第一个窗口换个名字
        self.f.show()  # 将第一个窗口显示出来
Exemple #43
0
class XPathDialog(QDialog):  # {{{
    def __init__(self, parent, prefs):
        QDialog.__init__(self, parent)
        self.prefs = prefs
        self.setWindowTitle(_('Create ToC from XPath'))
        self.l = l = QVBoxLayout()
        self.setLayout(l)
        self.la = la = QLabel(
            _('Specify a series of XPath expressions for the different levels of'
              ' the Table of Contents. You can use the wizard buttons to help'
              ' you create XPath expressions.'))
        la.setWordWrap(True)
        l.addWidget(la)
        self.widgets = []
        for i in range(5):
            la = _('Level %s ToC:') % ('&%d' % (i + 1))
            xp = XPathEdit(self)
            xp.set_msg(la)
            self.widgets.append(xp)
            l.addWidget(xp)

        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok
                                        | QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.ssb = b = bb.addButton(_('&Save settings'), bb.ActionRole)
        b.clicked.connect(self.save_settings)
        self.load_button = b = bb.addButton(_('&Load settings'), bb.ActionRole)
        self.load_menu = QMenu(b)
        b.setMenu(self.load_menu)
        self.setup_load_button()
        self.remove_duplicates_cb = QCheckBox(
            _('Do not add duplicate entries at the same level'))
        self.remove_duplicates_cb.setChecked(
            self.prefs.get('xpath_toc_remove_duplicates', True))
        l.addWidget(self.remove_duplicates_cb)
        l.addStretch()
        l.addWidget(bb)
        self.resize(self.sizeHint() + QSize(50, 75))

    def save_settings(self):
        xpaths = self.xpaths
        if not xpaths:
            return error_dialog(self,
                                _('No XPaths'),
                                _('No XPaths have been entered'),
                                show=True)
        if not self.check():
            return
        name, ok = QInputDialog.getText(self, _('Choose name'),
                                        _('Choose a name for these settings'))
        if ok:
            name = unicode_type(name).strip()
            if name:
                saved = self.prefs.get('xpath_toc_settings', {})
                # in JSON all keys have to be strings
                saved[name] = {str(i): x for i, x in enumerate(xpaths)}
                self.prefs.set('xpath_toc_settings', saved)
                self.setup_load_button()

    def setup_load_button(self):
        saved = self.prefs.get('xpath_toc_settings', {})
        m = self.load_menu
        m.clear()
        self.__actions = []
        a = self.__actions.append
        for name in sorted(saved):
            a(m.addAction(name, partial(self.load_settings, name)))
        m.addSeparator()
        a(m.addAction(_('Remove saved settings'), self.clear_settings))
        self.load_button.setEnabled(bool(saved))

    def clear_settings(self):
        self.prefs.set('xpath_toc_settings', {})
        self.setup_load_button()

    def load_settings(self, name):
        saved = self.prefs.get('xpath_toc_settings', {}).get(name, {})
        for i, w in enumerate(self.widgets):
            txt = saved.get(str(i), '')
            w.edit.setText(txt)

    def check(self):
        for w in self.widgets:
            if not w.check():
                error_dialog(self,
                             _('Invalid XPath'),
                             _('The XPath expression %s is not valid.') %
                             w.xpath,
                             show=True)
                return False
        return True

    def accept(self):
        if self.check():
            self.prefs.set('xpath_toc_remove_duplicates',
                           self.remove_duplicates_cb.isChecked())
            super(XPathDialog, self).accept()

    @property
    def xpaths(self):
        return [w.xpath for w in self.widgets if w.xpath.strip()]
Exemple #44
0
class BasicTab(QWidget):

    def __init__(self, parent_dialog, plugin_action):
        self.parent_dialog = parent_dialog
        self.plugin_action = plugin_action
        QWidget.__init__(self)

        self.l = QVBoxLayout()
        self.setLayout(self.l)

        label = QLabel(_('These settings control the basic features of the plugin.'))
        label.setWordWrap(True)
        self.l.addWidget(label)
        self.l.addSpacing(5)

        no_toc_warning = _('''If both 'Insert Table of Contents entry' and 'Copy Table of Contents entries'
are unchecked, there will be no Table of Contents in merged books.''')
        self.titlenavpoints = QCheckBox(_('Insert Table of Contents entry for each title?'),self)
        self.titlenavpoints.setToolTip(_('''If set, a new TOC entry will be made for each title and
it's existing TOC nested underneath it.''')+'\n'+no_toc_warning)
        self.titlenavpoints.setChecked(prefs['titlenavpoints'])
        self.l.addWidget(self.titlenavpoints)

        self.originalnavpoints = QCheckBox(_('Copy Table of Contents entries from each title?'),self)
        self.originalnavpoints.setToolTip(_('''If set, the original TOC entries will be included the new epub.''')+'\n'+no_toc_warning)
        self.originalnavpoints.setChecked(prefs['originalnavpoints'])
        self.l.addWidget(self.originalnavpoints)

        def f():
            if not self.originalnavpoints.isChecked() and not self.titlenavpoints.isChecked():
                confirm("<br>"+no_toc_warning, # force HTML to get auto wrap.
                        'epubmerge_no_toc_warning_again',
                        parent=self,
                        show_cancel_button=False)
        self.originalnavpoints.stateChanged.connect(f)
        self.titlenavpoints.stateChanged.connect(f)

        self.flattentoc = QCheckBox(_('Flatten Table of Contents?'),self)
        self.flattentoc.setToolTip(_('Remove nesting and make TOC all on one level.'))
        self.flattentoc.setChecked(prefs['flattentoc'])
        self.l.addWidget(self.flattentoc)

        self.includecomments = QCheckBox(_("Include Books' Comments?"),self)
        self.includecomments.setToolTip(_('''Include all the merged books' comments in the new book's comments.
Default is a list of included titles only.'''))
        self.includecomments.setChecked(prefs['includecomments'])
        self.l.addWidget(self.includecomments)

        self.keepmeta = QCheckBox(_('Keep UnMerge Metadata?'),self)
        self.keepmeta.setToolTip(_('''If set, a copy of the original metadata for each merged book will
be included, allowing for UnMerge.  This includes your calibre custom
columns.  Leave off if you plan to distribute the epub to others.'''))
        self.keepmeta.setChecked(prefs['keepmeta'])
        self.l.addWidget(self.keepmeta)

#         self.showunmerge = QCheckBox(_('Show UnMerge Option?'),self)
#         self.showunmerge.setToolTip(_('''If set, the UnMerge Epub option will be shown on the EpubMerge menu.
# Only Epubs merged with 'Keep UnMerge Metadata' can be UnMerged.'''))
#         self.showunmerge.setChecked(prefs['showunmerge'])
#         self.l.addWidget(self.showunmerge)

        horz = QHBoxLayout()
        horz.addWidget(QLabel(_("Add tags to merged books:")))

        self.mergetags = QLineEdit(self)
        self.mergetags.setText(prefs['mergetags'])
        self.mergetags.setToolTip(_('Tags you enter here will be added to all new merged books'))
        horz.addWidget(self.mergetags)
        self.l.addLayout(horz)

        horz = QHBoxLayout()
        horz.addWidget(QLabel(_("Merged Book Word:")))

        self.mergeword = QLineEdit(self)
        self.mergeword.setText(prefs['mergeword'])
        self.mergeword.setToolTip(_('''Word use to describe merged books in default title and summary.
For people who don't like the word Anthology.'''))
## Defaults back to Anthology if cleared.

        horz.addWidget(self.mergeword)
        self.l.addLayout(horz)

        self.l.addSpacing(15)

        label = QLabel(_("These controls aren't plugin settings as such, but convenience buttons for setting Keyboard shortcuts and getting all the EpubMerge confirmation dialogs back again."))
        label.setWordWrap(True)
        self.l.addWidget(label)
        self.l.addSpacing(5)

        keyboard_shortcuts_button = QPushButton(_('Keyboard shortcuts...'), self)
        keyboard_shortcuts_button.setToolTip(_('Edit the keyboard shortcuts associated with this plugin'))
        keyboard_shortcuts_button.clicked.connect(parent_dialog.edit_shortcuts)
        self.l.addWidget(keyboard_shortcuts_button)

        reset_confirmation_button = QPushButton(_('Reset disabled &confirmation dialogs'), self)
        reset_confirmation_button.setToolTip(_('Reset all show me again dialogs for the EpubMerge plugin'))
        reset_confirmation_button.clicked.connect(self.reset_dialogs)
        self.l.addWidget(reset_confirmation_button)

        view_prefs_button = QPushButton(_('View library preferences...'), self)
        view_prefs_button.setToolTip(_('View data stored in the library database for this plugin'))
        view_prefs_button.clicked.connect(self.view_prefs)
        self.l.addWidget(view_prefs_button)

        self.l.insertStretch(-1)

    def view_prefs(self):
        d = PrefsViewerDialog(self.plugin_action.gui, PREFS_NAMESPACE)
        d.exec_()

    def reset_dialogs(self):
        for key in dynamic.keys():
            if key.startswith('epubmerge_') and key.endswith('_again') \
                                                  and dynamic[key] is False:
                dynamic[key] = True
        info_dialog(self, _('Done'),
                    _('Confirmation dialogs have all been reset'),
                    show=True,
                    show_copy_button=False)
Exemple #45
0
class ProceedQuestion(QWidget):

    ask_question = pyqtSignal(object, object, object)

    @pyqtProperty(float)
    def show_fraction(self):
        return self._show_fraction

    @show_fraction.setter
    def show_fraction(self, val):
        self._show_fraction = max(0, min(1, float(val)))
        self.update()

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.setVisible(False)
        parent.installEventFilter(self)

        self._show_fraction = 0.0
        self.show_animation = a = QPropertyAnimation(self, b"show_fraction", self)
        a.setDuration(1000), a.setEasingCurve(QEasingCurve.OutQuad)
        a.setStartValue(0.0), a.setEndValue(1.0)
        a.finished.connect(self.stop_show_animation)
        self.rendered_pixmap = None

        self.questions = []

        self.icon = ic = Icon(self)
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
                _('Show detailed information about this error'))
        self.det_msg = PlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes|self.bb.No|self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)
        self.title_label = title = QLabel('A dummy title')
        f = title.font()
        f.setBold(True)
        title.setFont(f)

        self.checkbox = QCheckBox('', self)

        self._l = l = QVBoxLayout(self)
        self._h = h = QHBoxLayout()
        self._v = v = QVBoxLayout()
        v.addWidget(title), v.addWidget(msg)
        h.addWidget(ic), h.addSpacing(10), h.addLayout(v), l.addLayout(h)
        l.addSpacing(5)
        l.addWidget(self.checkbox)
        l.addWidget(self.det_msg)
        l.addWidget(self.bb)

        self.ask_question.connect(self.do_ask_question,
                type=Qt.QueuedConnection)
        self.setFocusPolicy(Qt.NoFocus)
        for child in self.findChildren(QWidget):
            child.setFocusPolicy(Qt.NoFocus)
        self.setFocusProxy(self.parent())
        self.resize_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(100), t.timeout.connect(self.parent_resized)

    def eventFilter(self, obj, ev):
        if ev.type() == ev.Resize and self.isVisible():
            self.resize_timer.start()
        return False

    def parent_resized(self):
        if self.isVisible():
            self.do_resize()

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
                'calibre, version %s\n%s: %s\n\n%s' %
                (__version__, unicode_type(self.windowTitle()),
                    unicode_type(self.msg_label.text()),
                    unicode_type(self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode_type(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(self.show_det_msg if vis else
                self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        sz = self.sizeHint()
        sz.setWidth(min(self.parent().width(), sz.width()))
        sb = self.parent().statusBar().height() + 10
        sz.setHeight(min(self.parent().height() - sb, sz.height()))
        self.resize(sz)
        self.position_widget()

    def show_question(self):
        if not self.questions:
            return
        if not self.isVisible():
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.icon.set_icon(question.icon)
            self.title_label.setText(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(
                    QIcon() if question.action_icon is None else question.action_icon)
            # Force the button box to relayout its buttons, as button text
            # might have changed
            self.bb.setOrientation(Qt.Vertical), self.bb.setOrientation(Qt.Horizontal)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            self.toggle_det_msg() if question.show_det else self.do_resize()
            self.show_widget()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            self.raise_()
            self.start_show_animation()

    def start_show_animation(self):
        if self.rendered_pixmap is not None:
            return

        dpr = getattr(self, 'devicePixelRatioF', self.devicePixelRatio)()
        p = QImage(dpr * self.size(), QImage.Format_ARGB32_Premultiplied)
        p.setDevicePixelRatio(dpr)
        self.render(p)
        self.rendered_pixmap = QPixmap.fromImage(p)
        self.original_visibility = v = []
        for child in self.findChildren(QWidget):
            if child.isVisible():
                child.setVisible(False)
                v.append(child)
        self.show_animation.start()

    def stop_show_animation(self):
        self.rendered_pixmap = None
        [c.setVisible(True) for c in getattr(self, 'original_visibility', ())]
        self.update()
        for child in self.findChildren(QWidget):
            child.update()
            if hasattr(child, 'viewport'):
                child.viewport().update()

    def position_widget(self):
        geom = self.parent().geometry()
        x = geom.width() - self.width() - 5
        sb = self.parent().statusBar()
        if sb is None:
            y = geom.height() - self.height()
        else:
            y = sb.geometry().top() - self.height()
        self.move(x, y)

    def show_widget(self):
        self.show()
        self.position_widget()

    def dummy_question(self, action_label=None):
        self(lambda *args:args, (), 'dummy log', 'Log Viewer', 'A Dummy Popup',
             'This is a dummy popup to easily test things, with a long line of text that should wrap. '
             'This is a dummy popup to easily test things, with a long line of text that should wrap',
             checkbox_msg='A dummy checkbox',
             action_callback=lambda *args: args, action_label=action_label or 'An action')

    def __call__(self, callback, payload, html_log, log_viewer_title, title,
            msg, det_msg='', show_copy_button=False, cancel_callback=None,
            log_is_file=False, checkbox_msg=None, checkbox_checked=False,
            action_callback=None, action_label=None, action_icon=None, focus_action=False,
            show_det=False, show_ok=False, icon=None, log_viewer_unique_name=None, **kw):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param icon: The icon to be used for this popop (defaults to question mark). Can be either a QIcon or a string to be used with I()
        :log_viewer_unique_name: If set, ViewLog will remember/reuse its size for this name in calibre.gui2.gprefs
        '''
        question = Question(
            payload, callback, cancel_callback, title, msg, html_log,
            log_viewer_title, log_is_file, det_msg, show_copy_button,
            checkbox_msg, checkbox_checked, action_callback, action_label,
            action_icon, focus_action, show_det, show_ok, icon, log_viewer_unique_name)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title, log,
                        parent=self, unique_name=q.log_viewer_unique_name)

    def paintEvent(self, ev):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
        try:
            if self.rendered_pixmap is None:
                self.paint_background(painter)
            else:
                self.animated_paint(painter)
        finally:
            painter.end()

    def animated_paint(self, painter):
        top = (1 - self._show_fraction) * self.height()
        painter.drawPixmap(0, top, self.rendered_pixmap)

    def paint_background(self, painter):
        br = 12  # border_radius
        bw = 1  # border_width
        pal = self.palette()
        c = pal.color(pal.Window)
        c.setAlphaF(0.9)
        p = QPainterPath()
        p.addRoundedRect(QRectF(self.rect()), br, br)
        painter.fillPath(p, c)
        p.addRoundedRect(QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br)
        painter.fillPath(p, pal.color(pal.WindowText))
Exemple #46
0
class Report(QDialog):  # {{{

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.gui = parent
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('polish.png')))
        self.reports = []

        self.l = l = QGridLayout()
        self.setLayout(l)
        self.view = v = QTextEdit(self)
        v.setReadOnly(True)
        l.addWidget(self.view, 0, 0, 1, 2)

        self.backup_msg = la = QLabel('')
        l.addWidget(la, 1, 0, 1, 2)
        la.setVisible(False)
        la.setWordWrap(True)

        self.ign = QCheckBox(_('Ignore remaining report'), self)
        l.addWidget(self.ign, 2, 0)

        bb = self.bb = QDialogButtonBox(QDialogButtonBox.Close)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        b = self.log_button = bb.addButton(_('View full &log'), bb.ActionRole)
        b.clicked.connect(self.view_log)
        bb.button(bb.Close).setDefault(True)
        l.addWidget(bb, 2, 1)

        self.finished.connect(self.show_next, type=Qt.QueuedConnection)

        self.resize(QSize(800, 600))

    def setup_ign(self):
        self.ign.setText(ngettext(
            'Ignore remaining report', 'Ignore remaining {} reports', len(self.reports)).format(len(self.reports)))
        self.ign.setVisible(bool(self.reports))
        self.ign.setChecked(False)

    def __call__(self, *args):
        self.reports.append(args)
        self.setup_ign()
        if not self.isVisible():
            self.show_next()

    def show_report(self, book_title, book_id, fmts, job, report):
        from calibre.ebooks.markdown import markdown
        self.current_log = job.details
        self.setWindowTitle(_('Polishing of %s')%book_title)
        self.view.setText(markdown('# %s\n\n'%book_title + report,
                                   output_format='html4'))
        self.bb.button(self.bb.Close).setFocus(Qt.OtherFocusReason)
        self.backup_msg.setVisible(bool(fmts))
        if fmts:
            m = ngettext('The original file has been saved as %s.',
                     'The original files have been saved as %s.', len(fmts))%(
                _(' and ').join('ORIGINAL_'+f for f in fmts)
                     )
            self.backup_msg.setText(m + ' ' + _(
                'If you polish again, the polishing will run on the originals.')%(
                ))

    def view_log(self):
        self.view.setPlainText(self.current_log)
        self.view.verticalScrollBar().setValue(0)

    def show_next(self, *args):
        if not self.reports:
            return
        if not self.isVisible():
            self.show()
        self.show_report(*self.reports.pop(0))
        self.setup_ign()

    def accept(self):
        if self.ign.isChecked():
            self.reports = []
        if self.reports:
            self.show_next()
            return
        super(Report, self).accept()

    def reject(self):
        if self.ign.isChecked():
            self.reports = []
        if self.reports:
            self.show_next()
            return
        super(Report, self).reject()
Exemple #47
0
class SyncWidget(QWidget):
    def __init__(self, gui, do_user_config, selected_book_ids,
                 is_sync_selected):
        QWidget.__init__(self, gui)

        api.build_request('/limits')

        self.logger = Logger(
            path.join(gui.current_db.library_path, 'bookfusion_sync.log'))
        self.logger.info(
            'Open sync dialog: selected_book_ids={}; is_sync_selected={}'.
            format(selected_book_ids, is_sync_selected))

        if len(selected_book_ids) == 0:
            is_sync_selected = False

        self.worker_thread = None

        self.do_user_config = do_user_config
        self.db = gui.current_db.new_api

        self.selected_book_ids = selected_book_ids

        self.l = QVBoxLayout()
        self.l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.l)

        self.radio_layout = QVBoxLayout()
        self.l.addLayout(self.radio_layout)

        self.sync_all_radio = QRadioButton('Sync all books')
        self.sync_all_radio.setChecked(not is_sync_selected)
        self.radio_layout.addWidget(self.sync_all_radio)

        sync_selected_radio_label = 'Sync selected books'
        if len(selected_book_ids) > 0:
            sync_selected_radio_label = 'Sync {} selected {}'.format(
                len(selected_book_ids),
                'book' if len(selected_book_ids) == 1 else 'books')
        self.sync_selected_radio = QRadioButton(sync_selected_radio_label)
        self.sync_selected_radio.toggled.connect(self.toggle_sync_selected)
        self.sync_selected_radio.setChecked(is_sync_selected)
        self.sync_selected_radio.setEnabled(len(selected_book_ids) > 0)
        self.radio_layout.addWidget(self.sync_selected_radio)

        self.reupload_possible = len(selected_book_ids) > 0 and len(
            selected_book_ids) <= 100
        if self.reupload_possible:
            for book_id in selected_book_ids:
                identifiers = self.db.get_proxy_metadata(book_id).identifiers
                if not identifiers.get('bookfusion'):
                    self.reupload_possible = False

        self.reupload_checkbox = QCheckBox('Re-upload book files', self)
        self.reupload_checkbox.setVisible(is_sync_selected
                                          and self.reupload_possible)
        self.radio_layout.addWidget(self.reupload_checkbox)

        self.btn_layout = QHBoxLayout()
        self.l.addLayout(self.btn_layout)

        self.config_btn = QPushButton('Configure')
        self.config_btn.clicked.connect(self.config)
        self.btn_layout.addWidget(self.config_btn)

        self.btn_layout.addStretch()

        self.start_btn = QPushButton('Start')
        self.start_btn.clicked.connect(self.start)
        self.btn_layout.addWidget(self.start_btn)

        self.cancel_btn = QPushButton('Cancel')
        self.cancel_btn.clicked.connect(self.cancel)
        self.cancel_btn.hide()
        self.btn_layout.addWidget(self.cancel_btn)

        self.info = QHBoxLayout()
        self.info.setContentsMargins(0, 0, 0, 0)
        self.l.addLayout(self.info)
        self.msg = QLabel()
        self.info.addWidget(self.msg)
        self.info.addStretch()
        self.log_btn = QLabel('<a href="#">Log</a>')
        self.log_btn.linkActivated.connect(self.toggle_log)
        self.log_btn.hide()
        self.info.addWidget(self.log_btn)

        self.log = QTableWidget(0, 2)
        self.log.setHorizontalHeaderLabels(['Book', 'Message'])
        self.log.horizontalHeader().setStretchLastSection(True)
        self.log.hide()
        self.l.addWidget(self.log)

        self.apply_config()

    def __del__(self):
        if self.worker_thread:
            self.worker_thread.quit()
            self.worker_thread.terminate()

    def config(self):
        self.do_user_config(parent=self)
        self.apply_config()

    def apply_config(self):
        configured = bool(prefs['api_key'])
        self.start_btn.setEnabled(configured)

    def toggle_sync_selected(self, is_sync_selected):
        if hasattr(self, 'reupload_checkbox'):
            self.reupload_checkbox.setVisible(is_sync_selected
                                              and self.reupload_possible)

    def start(self):
        if self.sync_selected_radio.isChecked(
        ) and self.reupload_checkbox.isChecked():
            reply = QMessageBox.question(
                self, 'BookFusion Sync',
                'Re-uploading book files can potentially result in previous highlights or bookmarks no longer working.\n\nPreviously uploaded files will be overwritten. Are you sure you want to re-upload?',
                QMessageBox.No | QMessageBox.Yes, QMessageBox.Yes)
            if reply != QMessageBox.Yes:
                return

        self.worker = None
        self.valid_book_ids = None
        self.book_log_map = {}
        self.book_progress_map = {}

        if self.sync_selected_radio.isChecked():
            book_ids = list(self.selected_book_ids)
        else:
            book_ids = list(self.db.all_book_ids())

        self.logger.info('Start sync: sync_selected={}; book_ids={}'.format(
            self.sync_selected_radio.isChecked(), book_ids))

        self.in_progress = True
        self.total = len(book_ids)
        self.update_progress(None)
        self.start_btn.hide()
        self.cancel_btn.show()
        self.config_btn.setEnabled(False)
        self.sync_all_radio.setEnabled(False)
        self.sync_selected_radio.setEnabled(False)

        self.worker_thread = QThread(self)

        self.worker = CheckWorker(self.db, self.logger, book_ids)
        self.worker.finished.connect(self.finish_check)
        self.worker.finished.connect(self.worker_thread.quit)
        self.worker.progress.connect(self.update_progress)
        self.worker.limitsAvailable.connect(self.apply_limits)
        self.worker.resultsAvailable.connect(self.apply_results)
        self.worker.aborted.connect(self.abort)
        self.worker.moveToThread(self.worker_thread)

        self.worker_thread.started.connect(self.worker.start)
        self.worker_thread.start()

    def apply_limits(self, limits):
        self.logger.info('Limits: {}'.format(limits))
        self.limits = limits

    def apply_results(self, books_count, valid_ids):
        self.logger.info('Check results: books_count={}; valid_ids={}'.format(
            books_count, valid_ids))
        self.valid_book_ids = valid_ids
        self.books_count = books_count

    def finish_check(self):
        if self.valid_book_ids:
            is_filesize_exceeded = len(self.valid_book_ids) < self.books_count
            is_total_books_exceeded = self.limits[
                'total_books'] and self.books_count > self.limits['total_books']

            if is_filesize_exceeded or is_total_books_exceeded:
                if self.limits['message']:
                    msg_box = QMessageBox(self)
                    msg_box.setWindowTitle('BookFusion Sync')
                    msg_box.addButton(QMessageBox.No)
                    msg_box.addButton(QMessageBox.Yes)
                    msg_box.setText(self.limits['message'])
                    msg_box.setDefaultButton(QMessageBox.Yes)
                    reply = msg_box.exec_()
                    if reply == QMessageBox.Yes:
                        self.start_sync()
                    else:
                        self.in_progress = False
                        self.msg.setText('Canceled.')
                        self.finish_sync()
                else:
                    self.start_sync()
            else:
                self.start_sync()
        else:
            if self.in_progress:
                self.in_progress = False
                self.msg.setText('No supported books selected.')
            self.finish_sync()

    def start_sync(self):
        self.log_btn.show()
        self.log.setRowCount(0)
        self.log.show()

        self.worker_thread = QThread(self)

        book_ids = self.valid_book_ids
        if self.limits['total_books']:
            book_ids = book_ids[:self.limits['total_books']]

        self.total = len(book_ids)

        self.worker = UploadManager(
            self.db, self.logger, book_ids,
            self.sync_selected_radio.isChecked()
            and self.reupload_checkbox.isChecked())
        self.worker.finished.connect(self.finish_sync)
        self.worker.finished.connect(self.worker_thread.quit)
        self.worker.progress.connect(self.update_progress)
        self.worker.uploadProgress.connect(self.update_upload_progress)
        self.worker.started.connect(self.log_start)
        self.worker.skipped.connect(self.log_skip)
        self.worker.failed.connect(self.log_fail)
        self.worker.uploaded.connect(self.log_upload)
        self.worker.updated.connect(self.log_update)
        self.worker.aborted.connect(self.abort)
        self.worker.moveToThread(self.worker_thread)

        self.worker_thread.started.connect(self.worker.start)
        self.worker_thread.start()

    def finish_sync(self):
        if self.in_progress:
            self.msg.setText('Done.')
        self.cancel_btn.hide()
        self.cancel_btn.setEnabled(True)
        self.start_btn.show()
        self.config_btn.setEnabled(True)
        self.sync_all_radio.setEnabled(True)
        self.sync_selected_radio.setEnabled(len(self.selected_book_ids) > 0)

    def abort(self, error):
        self.in_progress = False
        self.msg.setText(error)

    def cancel(self):
        self.in_progress = False
        self.msg.setText('Canceled.')
        self.cancel_btn.setEnabled(False)
        self.worker.cancel()

    def update_progress(self, progress):
        if self.in_progress:
            if isinstance(self.worker, UploadManager):
                msg = 'Synchronizing...'
            else:
                msg = 'Preparing...'
            if progress:
                msg += ' {} of {}'.format(progress + 1, self.total)
            self.msg.setText(msg)

    def update_upload_progress(self, book_id, sent, total):
        if not book_id in self.book_progress_map:
            return

        progress = self.book_progress_map[book_id]

        if sent < total:
            progress.setValue(sent)
            progress.setMaximum(total)
        else:
            progress.setMaximum(0)

    def log_start(self, book_id):
        self.update_log(book_id, None)

    def log_fail(self, book_id, msg):
        self.update_log(book_id, msg)

    def log_skip(self, book_id):
        self.update_log(book_id, 'skipped')

    def log_upload(self, book_id):
        self.update_log(book_id, 'uploaded')

    def log_update(self, book_id):
        self.update_log(book_id, 'updated')

    def toggle_log(self, _):
        self.log.setVisible(not self.log.isVisible())

    def update_log(self, book_id, msg):
        if book_id in self.book_log_map:
            index = self.book_log_map[book_id]
        else:
            index = self.log.rowCount()
            self.book_log_map[book_id] = index

            self.log.insertRow(index)

            title = self.db.get_proxy_metadata(book_id).title
            title_item = QTableWidgetItem(title)
            title_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                | Qt.ItemNeverHasChildren)
            self.log.setItem(index, 0, title_item)

            progress = QProgressBar()
            progress.setMaximum(0)
            self.log.setCellWidget(index, 1, progress)
            self.book_progress_map[book_id] = progress

        if not msg is None:
            del (self.book_progress_map[book_id])
            self.log.setCellWidget(index, 1, None)

            msg_item = QTableWidgetItem(msg)
            msg_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                              | Qt.ItemNeverHasChildren)
            self.log.setItem(index, 1, msg_item)

    def maybe_cancel(self):
        if self.worker_thread and self.worker_thread.isRunning():
            reply = QMessageBox.question(
                self, 'BookFusion Sync',
                'Are you sure you want to cancel the currently running process?',
                QMessageBox.No | QMessageBox.Yes, QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.cancel()
            else:
                return False
        return True
Exemple #48
0
class ProceedQuestion(QWidget):

    ask_question = pyqtSignal(object, object, object)

    @pyqtProperty(float)
    def show_fraction(self):
        return self._show_fraction

    @show_fraction.setter
    def show_fraction(self, val):
        self._show_fraction = max(0, min(1, float(val)))
        self.update()

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.setVisible(False)
        parent.installEventFilter(self)

        self._show_fraction = 0.0
        self.show_animation = a = QPropertyAnimation(self, b"show_fraction",
                                                     self)
        a.setDuration(1000), a.setEasingCurve(QEasingCurve.OutQuad)
        a.setStartValue(0.0), a.setEndValue(1.0)
        a.finished.connect(self.stop_show_animation)
        self.rendered_pixmap = None

        self.questions = []

        self.icon = ic = Icon(self)
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                                             self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg,
                                                self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
            _('Show detailed information about this error'))
        self.det_msg = PlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes | self.bb.No | self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)
        self.title_label = title = QLabel('A dummy title')
        f = title.font()
        f.setBold(True)
        title.setFont(f)

        self.checkbox = QCheckBox('', self)

        self._l = l = QVBoxLayout(self)
        self._h = h = QHBoxLayout()
        self._v = v = QVBoxLayout()
        v.addWidget(title), v.addWidget(msg)
        h.addWidget(ic), h.addSpacing(10), h.addLayout(v), l.addLayout(h)
        l.addSpacing(5)
        l.addWidget(self.checkbox)
        l.addWidget(self.det_msg)
        l.addWidget(self.bb)

        self.ask_question.connect(self.do_ask_question,
                                  type=Qt.QueuedConnection)
        self.setFocusPolicy(Qt.NoFocus)
        for child in self.findChildren(QWidget):
            child.setFocusPolicy(Qt.NoFocus)
        self.setFocusProxy(self.parent())
        self.resize_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(100), t.timeout.connect(
            self.parent_resized)

    def eventFilter(self, obj, ev):
        if ev.type() == ev.Resize and self.isVisible():
            self.resize_timer.start()
        return False

    def parent_resized(self):
        if self.isVisible():
            self.do_resize()

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
            'calibre, version %s\n%s: %s\n\n%s' %
            (__version__, unicode_type(
                self.windowTitle()), unicode_type(self.msg_label.text()),
             unicode_type(self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode_type(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(
            self.show_det_msg if vis else self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        sz = self.sizeHint()
        sz.setWidth(min(self.parent().width(), sz.width()))
        sb = self.parent().statusBar().height() + 10
        sz.setHeight(min(self.parent().height() - sb, sz.height()))
        self.resize(sz)
        self.position_widget()

    def show_question(self):
        if not self.questions:
            return
        if not self.isVisible():
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.icon.set_icon(question.icon)
            self.title_label.setText(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(QIcon(
                ) if question.action_icon is None else question.action_icon)
            # Force the button box to relayout its buttons, as button text
            # might have changed
            self.bb.setOrientation(Qt.Vertical), self.bb.setOrientation(
                Qt.Horizontal)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            self.toggle_det_msg() if question.show_det else self.do_resize()
            self.show_widget()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            self.raise_()
            self.start_show_animation()

    def start_show_animation(self):
        if self.rendered_pixmap is not None:
            return

        dpr = getattr(self, 'devicePixelRatioF', self.devicePixelRatio)()
        p = QImage(dpr * self.size(), QImage.Format_ARGB32_Premultiplied)
        p.setDevicePixelRatio(dpr)
        # For some reason, Qt scrolls the book view when rendering this widget,
        # for the very first time, so manually preserve its position
        pr = getattr(self.parent(), 'library_view', None)
        if not hasattr(pr, 'preserve_state'):
            self.render(p)
        else:
            with pr.preserve_state():
                self.render(p)
        self.rendered_pixmap = QPixmap.fromImage(p)
        self.original_visibility = v = []
        for child in self.findChildren(QWidget):
            if child.isVisible():
                child.setVisible(False)
                v.append(child)
        self.show_animation.start()

    def stop_show_animation(self):
        self.rendered_pixmap = None
        [c.setVisible(True) for c in getattr(self, 'original_visibility', ())]
        self.update()
        for child in self.findChildren(QWidget):
            child.update()
            if hasattr(child, 'viewport'):
                child.viewport().update()

    def position_widget(self):
        geom = self.parent().geometry()
        x = geom.width() - self.width() - 5
        sb = self.parent().statusBar()
        if sb is None:
            y = geom.height() - self.height()
        else:
            y = sb.geometry().top() - self.height()
        self.move(x, y)

    def show_widget(self):
        self.show()
        self.position_widget()

    def dummy_question(self, action_label=None):
        self(
            lambda *args: args, (),
            'dummy log',
            'Log Viewer',
            'A Dummy Popup',
            'This is a dummy popup to easily test things, with a long line of text that should wrap. '
            'This is a dummy popup to easily test things, with a long line of text that should wrap',
            checkbox_msg='A dummy checkbox',
            action_callback=lambda *args: args,
            action_label=action_label or 'An action')

    def __call__(self,
                 callback,
                 payload,
                 html_log,
                 log_viewer_title,
                 title,
                 msg,
                 det_msg='',
                 show_copy_button=False,
                 cancel_callback=None,
                 log_is_file=False,
                 checkbox_msg=None,
                 checkbox_checked=False,
                 action_callback=None,
                 action_label=None,
                 action_icon=None,
                 focus_action=False,
                 show_det=False,
                 show_ok=False,
                 icon=None,
                 log_viewer_unique_name=None,
                 **kw):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param icon: The icon to be used for this popop (defaults to question mark). Can be either a QIcon or a string to be used with I()
        :log_viewer_unique_name: If set, ViewLog will remember/reuse its size for this name in calibre.gui2.gprefs
        '''
        question = Question(payload, callback, cancel_callback, title, msg,
                            html_log, log_viewer_title, log_is_file, det_msg,
                            show_copy_button, checkbox_msg, checkbox_checked,
                            action_callback, action_label, action_icon,
                            focus_action, show_det, show_ok, icon,
                            log_viewer_unique_name)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title,
                                      log,
                                      parent=self,
                                      unique_name=q.log_viewer_unique_name)

    def paintEvent(self, ev):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
        try:
            if self.rendered_pixmap is None:
                self.paint_background(painter)
            else:
                self.animated_paint(painter)
        finally:
            painter.end()

    def animated_paint(self, painter):
        top = (1 - self._show_fraction) * self.height()
        painter.drawPixmap(0, top, self.rendered_pixmap)

    def paint_background(self, painter):
        br = 12  # border_radius
        bw = 1  # border_width
        pal = self.palette()
        c = pal.color(pal.Window)
        c.setAlphaF(0.9)
        p = QPainterPath()
        p.addRoundedRect(QRectF(self.rect()), br, br)
        painter.fillPath(p, c)
        p.addRoundedRect(
            QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br)
        painter.fillPath(p, pal.color(pal.WindowText))
Exemple #49
0
class MainWidget(QWidget):
    def __init__(self, Parent=None):
        '''
        Constructor
        '''
        super().__init__(Parent)

        self.__InitData()  #先初始化数据,再初始化界面
        self.__InitView()
        self.svmModel = model.loadModel()

    def __InitData(self):
        '''
                  初始化成员变量
        '''
        self.__paintBoard = PaintBoard(self)
        #获取颜色列表(字符串类型)
        self.__colorList = QColor.colorNames()

    def __InitView(self):
        '''
                  初始化界面
        '''
        self.setFixedSize(640, 480)
        self.setWindowTitle("PaintBoard Example PyQt5")

        #新建一个水平布局作为本窗体的主布局
        main_layout = QHBoxLayout(self)
        #设置主布局内边距以及控件间距为10px
        main_layout.setSpacing(10)

        #在主界面左侧放置画板
        main_layout.addWidget(self.__paintBoard)

        #新建垂直子布局用于放置按键
        sub_layout = QVBoxLayout()

        #设置此子布局和内部控件的间距为10px
        sub_layout.setContentsMargins(10, 10, 10, 10)

        self.__btn_Clear = QPushButton("清空画板")
        self.__btn_Clear.setParent(self)  #设置父对象为本界面
        self.__btn_Clear.clicked.connect(self.on_clear)  #将按键按下信号与画板清空函数相关联
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_Save = QPushButton("识别")
        self.__btn_Save.setParent(self)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__text_predict = QLineEdit(self)
        sub_layout.addWidget(self.__text_predict)

        self.__cbtn_Eraser = QCheckBox("  使用橡皮擦")
        self.__cbtn_Eraser.setParent(self)
        self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        sub_layout.addWidget(self.__cbtn_Eraser)

        splitter = QSplitter(self)  #占位符
        sub_layout.addWidget(splitter)

        self.__btn_Quit = QPushButton("退出")
        self.__btn_Quit.setParent(self)  #设置父对象为本界面
        self.__btn_Quit.clicked.connect(self.Quit)
        sub_layout.addWidget(self.__btn_Quit)

        self.__label_penThickness = QLabel(self)
        self.__label_penThickness.setText("画笔粗细")
        self.__label_penThickness.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penThickness)

        self.__spinBox_penThickness = QSpinBox(self)
        self.__spinBox_penThickness.setMaximum(20)
        self.__spinBox_penThickness.setMinimum(2)
        self.__spinBox_penThickness.setValue(10)  #默认粗细为10
        self.__spinBox_penThickness.setSingleStep(2)  #最小变化值为2
        self.__spinBox_penThickness.valueChanged.connect(
            self.on_PenThicknessChange
        )  #关联spinBox值变化信号和函数on_PenThicknessChange
        sub_layout.addWidget(self.__spinBox_penThickness)

        self.__label_penColor = QLabel(self)
        self.__label_penColor.setText("画笔颜色")
        self.__label_penColor.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penColor)

        self.__comboBox_penColor = QComboBox(self)
        self.__fillColorList(self.__comboBox_penColor)  #用各种颜色填充下拉列表
        self.__comboBox_penColor.currentIndexChanged.connect(
            self.on_PenColorChange)  #关联下拉列表的当前索引变更信号与函数on_PenColorChange
        sub_layout.addWidget(self.__comboBox_penColor)

        main_layout.addLayout(sub_layout)  #将子布局加入主布局

    def __fillColorList(self, comboBox):

        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    def on_PenColorChange(self):
        color_index = self.__comboBox_penColor.currentIndex()
        color_str = self.__colorList[color_index]
        self.__paintBoard.ChangePenColor(color_str)

    def on_PenThicknessChange(self):
        penThickness = self.__spinBox_penThickness.value()
        self.__paintBoard.ChangePenThickness(penThickness)

    def on_clear(self):
        self.__paintBoard.Clear()
        self.__text_predict.setText("")

    def on_btn_Save_Clicked(self):
        image = self.__paintBoard.GetContentAsQImage()
        image.save("tmpimageforsvm.png")
        img = cv2.imread("tmpimageforsvm.png")
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img = cv2.resize(img, (28, 28))
        Array = np.empty((1, 28 * 28))
        Array[0] = img.reshape((1, 28 * 28))
        ret = self.svmModel.predict(model.reNormalize(Array))
        print(ret)
        self.__text_predict.setText("预测值{}".format(int(ret)))

    def on_cbtn_Eraser_clicked(self):
        if self.__cbtn_Eraser.isChecked():
            self.__paintBoard.EraserMode = True  #进入橡皮擦模式
        else:
            self.__paintBoard.EraserMode = False  #退出橡皮擦模式

    def Quit(self):
        self.close()
Exemple #50
0
class XPathDialog(QDialog):  # {{{

    def __init__(self, parent, prefs):
        QDialog.__init__(self, parent)
        self.prefs = prefs
        self.setWindowTitle(_('Create ToC from XPath'))
        self.l = l = QVBoxLayout()
        self.setLayout(l)
        self.la = la = QLabel(_(
            'Specify a series of XPath expressions for the different levels of'
            ' the Table of Contents. You can use the wizard buttons to help'
            ' you create XPath expressions.'))
        la.setWordWrap(True)
        l.addWidget(la)
        self.widgets = []
        for i in range(5):
            la = _('Level %s ToC:')%('&%d'%(i+1))
            xp = XPathEdit(self)
            xp.set_msg(la)
            self.widgets.append(xp)
            l.addWidget(xp)

        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.ssb = b = bb.addButton(_('&Save settings'), bb.ActionRole)
        b.clicked.connect(self.save_settings)
        self.load_button = b = bb.addButton(_('&Load settings'), bb.ActionRole)
        self.load_menu = QMenu(b)
        b.setMenu(self.load_menu)
        self.setup_load_button()
        self.remove_duplicates_cb = QCheckBox(_('Do not add duplicate entries at the same level'))
        self.remove_duplicates_cb.setChecked(self.prefs.get('xpath_toc_remove_duplicates', True))
        l.addWidget(self.remove_duplicates_cb)
        l.addStretch()
        l.addWidget(bb)
        self.resize(self.sizeHint() + QSize(50, 75))

    def save_settings(self):
        xpaths = self.xpaths
        if not xpaths:
            return error_dialog(self, _('No XPaths'),
                                _('No XPaths have been entered'), show=True)
        if not self.check():
            return
        name, ok = QInputDialog.getText(self, _('Choose name'),
                _('Choose a name for these settings'))
        if ok:
            name = unicode_type(name).strip()
            if name:
                saved = self.prefs.get('xpath_toc_settings', {})
                # in JSON all keys have to be strings
                saved[name] = {str(i):x for i, x in enumerate(xpaths)}
                self.prefs.set('xpath_toc_settings', saved)
                self.setup_load_button()

    def setup_load_button(self):
        saved = self.prefs.get('xpath_toc_settings', {})
        m = self.load_menu
        m.clear()
        self.__actions = []
        a = self.__actions.append
        for name in sorted(saved):
            a(m.addAction(name, partial(self.load_settings, name)))
        m.addSeparator()
        a(m.addAction(_('Remove saved settings'), self.clear_settings))
        self.load_button.setEnabled(bool(saved))

    def clear_settings(self):
        self.prefs.set('xpath_toc_settings', {})
        self.setup_load_button()

    def load_settings(self, name):
        saved = self.prefs.get('xpath_toc_settings', {}).get(name, {})
        for i, w in enumerate(self.widgets):
            txt = saved.get(str(i), '')
            w.edit.setText(txt)

    def check(self):
        for w in self.widgets:
            if not w.check():
                error_dialog(self, _('Invalid XPath'),
                    _('The XPath expression %s is not valid.')%w.xpath,
                             show=True)
                return False
        return True

    def accept(self):
        if self.check():
            self.prefs.set('xpath_toc_remove_duplicates', self.remove_duplicates_cb.isChecked())
            super(XPathDialog, self).accept()

    @property
    def xpaths(self):
        return [w.xpath for w in self.widgets if w.xpath.strip()]
class ConfigWidget(QWidget):
    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        self.gui = plugin_action.gui
        self.library = get_library_config(self.gui.current_db)
        self.views = self.library[KEY_VIEWS]
        self.all_columns = self.get_current_columns()
        self.view_name = None

        self.has_pin_view = hasattr(self.gui.library_view, 'pin_view')

        toplayout = QVBoxLayout(self)
        self.setLayout(toplayout)
        ## wrap config in a scrollable area for smaller displays.
        scrollable = QScrollArea()
        scrollcontent = QWidget()
        scrollable.setWidget(scrollcontent)
        scrollable.setWidgetResizable(True)
        toplayout.addWidget(scrollable)

        layout = QVBoxLayout()
        scrollcontent.setLayout(layout)

        select_view_layout = QHBoxLayout()
        layout.addLayout(select_view_layout)
        select_view_label = QLabel('Select view to customize:', self)
        select_view_layout.addWidget(select_view_label)
        self.select_view_combo = ViewComboBox(self, self.views)
        self.select_view_combo.setMinimumSize(150, 20)
        select_view_layout.addWidget(self.select_view_combo)
        self.add_view_button = QtGui.QToolButton(self)
        self.add_view_button.setToolTip('Add view')
        self.add_view_button.setIcon(QIcon(I('plus.png')))
        self.add_view_button.clicked.connect(self.add_view)
        select_view_layout.addWidget(self.add_view_button)
        self.delete_view_button = QtGui.QToolButton(self)
        self.delete_view_button.setToolTip('Delete view')
        self.delete_view_button.setIcon(QIcon(I('minus.png')))
        self.delete_view_button.clicked.connect(self.delete_view)
        select_view_layout.addWidget(self.delete_view_button)
        self.rename_view_button = QtGui.QToolButton(self)
        self.rename_view_button.setToolTip('Rename view')
        self.rename_view_button.setIcon(QIcon(I('edit-undo.png')))
        self.rename_view_button.clicked.connect(self.rename_view)
        select_view_layout.addWidget(self.rename_view_button)
        select_view_layout.insertStretch(-1)

        view_group_box = QGroupBox('Column Options', self)
        layout.addWidget(view_group_box)
        view_group_box_layout = QVBoxLayout()
        view_group_box.setLayout(view_group_box_layout)

        customise_layout = QGridLayout()
        view_group_box_layout.addLayout(customise_layout, 1)

        if self.has_pin_view:
            columns_label = 'Columns in Default (Left) pane'
        else:
            columns_label = 'Columns in view'
        self.columns_label = QLabel(columns_label, self)
        self.columns_list = ColumnListWidget(self, self.gui)
        self.move_column_up_button = QtGui.QToolButton(self)
        self.move_column_up_button.setToolTip('Move column up')
        self.move_column_up_button.setIcon(QIcon(I('arrow-up.png')))
        self.move_column_down_button = QtGui.QToolButton(self)
        self.move_column_down_button.setToolTip('Move column down')
        self.move_column_down_button.setIcon(QIcon(I('arrow-down.png')))
        self.move_column_up_button.clicked.connect(
            self.columns_list.move_column_up)
        self.move_column_down_button.clicked.connect(
            self.columns_list.move_column_down)

        if self.has_pin_view:

            self.apply_pin_columns_checkbox = QCheckBox(
                'Columns in Split (Right) Pane', self)
            self.apply_pin_columns_checkbox.setToolTip(
                'Split Book List will <i>only</i> be shown if this is checked.  This will be checked if you save a Split View.'
            )
            self.pin_columns_list = ColumnListWidget(self, self.gui)
            self.move_pin_column_up_button = QtGui.QToolButton(self)
            self.move_pin_column_up_button.setToolTip('Move column up')
            self.move_pin_column_up_button.setIcon(QIcon(I('arrow-up.png')))
            self.move_pin_column_down_button = QtGui.QToolButton(self)
            self.move_pin_column_down_button.setToolTip('Move column down')
            self.move_pin_column_down_button.setIcon(QIcon(
                I('arrow-down.png')))
            self.move_pin_column_up_button.clicked.connect(
                self.pin_columns_list.move_column_up)
            self.move_pin_column_down_button.clicked.connect(
                self.pin_columns_list.move_column_down)

            def group_abled(elems, cb):
                for el in elems:
                    el.setEnabled(cb.isChecked())

            pin_abled = partial(group_abled, [
                self.pin_columns_list, self.move_pin_column_up_button,
                self.move_pin_column_down_button
            ], self.apply_pin_columns_checkbox)
            pin_abled()
            self.apply_pin_columns_checkbox.stateChanged.connect(pin_abled)

        self.sort_label = QLabel('Sort order', self)
        self.sort_list = SortColumnListWidget(self, self.gui)
        self.move_sort_up_button = QtGui.QToolButton(self)
        self.move_sort_up_button.setToolTip('Move sort column up')
        self.move_sort_up_button.setIcon(QIcon(I('arrow-up.png')))
        self.move_sort_down_button = QtGui.QToolButton(self)
        self.move_sort_down_button.setToolTip('Move sort down')
        self.move_sort_down_button.setIcon(QIcon(I('arrow-down.png')))
        self.move_sort_up_button.clicked.connect(self.sort_list.move_column_up)
        self.move_sort_down_button.clicked.connect(
            self.sort_list.move_column_down)

        layout_col = 0  # calculate layout because pin column only shown if available.
        customise_layout.addWidget(self.columns_label, 0, layout_col, 1, 1)
        customise_layout.addWidget(self.columns_list, 1, layout_col, 3, 1)
        layout_col = layout_col + 1
        customise_layout.addWidget(self.move_column_up_button, 1, layout_col,
                                   1, 1)
        customise_layout.addWidget(self.move_column_down_button, 3, layout_col,
                                   1, 1)
        layout_col = layout_col + 1

        if self.has_pin_view:
            customise_layout.addWidget(self.apply_pin_columns_checkbox, 0,
                                       layout_col, 1, 1)
            customise_layout.addWidget(self.pin_columns_list, 1, layout_col, 3,
                                       1)
            layout_col = layout_col + 1
            customise_layout.addWidget(self.move_pin_column_up_button, 1,
                                       layout_col, 1, 1)
            customise_layout.addWidget(self.move_pin_column_down_button, 3,
                                       layout_col, 1, 1)
            layout_col = layout_col + 1

        customise_layout.addWidget(self.sort_label, 0, layout_col, 1, 1)
        customise_layout.addWidget(self.sort_list, 1, layout_col, 3, 1)
        layout_col = layout_col + 1

        customise_layout.addWidget(self.move_sort_up_button, 1, layout_col, 1,
                                   1)
        customise_layout.addWidget(self.move_sort_down_button, 3, layout_col,
                                   1, 1)
        layout_col = layout_col + 1

        search_group_box = QGroupBox("Search and Virtual Library Options",
                                     self)
        layout.addWidget(search_group_box)
        search_group_box_layout = QVBoxLayout()
        search_group_box.setLayout(search_group_box_layout)

        other_layout = QGridLayout()
        search_group_box_layout.addLayout(other_layout)

        self.apply_search_checkbox = QCheckBox('Apply saved &search', self)
        self.apply_search_checkbox.setToolTip(
            "Apply the selected saved search when the View is activated.")
        self.saved_search_combo = SearchComboBox(
            self, entries=saved_searches().names(), empty="(Clear Search)")
        self.saved_search_combo.setToolTip("Saved search to apply.")
        # enable/disable combo based on check.
        self.saved_search_combo.setEnabled(
            self.apply_search_checkbox.isChecked())
        self.apply_search_checkbox.stateChanged.connect(
            lambda x: self.saved_search_combo.setEnabled(
                self.apply_search_checkbox.isChecked()))

        self.apply_virtlib_checkbox = QCheckBox('Switch to &Virtual library',
                                                self)
        self.apply_virtlib_checkbox.setToolTip(
            "Switch to the selected Virtual library when the View is activated."
        )
        self.virtlib_combo = SearchComboBox(
            self,
            entries=self.gui.library_view.model().db.prefs.get(
                'virtual_libraries', {}),
            empty="(No Virtual library)")
        self.virtlib_combo.setToolTip("Virtual library to switch to.")
        # enable/disable combo based on check.
        self.virtlib_combo.setEnabled(self.apply_virtlib_checkbox.isChecked())
        self.apply_virtlib_checkbox.stateChanged.connect(
            lambda x: self.virtlib_combo.setEnabled(self.apply_virtlib_checkbox
                                                    .isChecked()))

        self.apply_restriction_checkbox = QCheckBox(
            'Apply VL additional search &restriction', self)
        self.apply_restriction_checkbox.setToolTip(
            "Apply the selected saved search as a Virtual library additional restriction when the View is activated."
        )
        self.search_restriction_combo = SearchComboBox(
            self,
            entries=saved_searches().names(),
            empty="(Clear VL restriction search)")
        self.search_restriction_combo.setToolTip(
            "Saved search to apply as VL additional search restriction.")
        # enable/disable combo based on check.
        self.search_restriction_combo.setEnabled(
            self.apply_restriction_checkbox.isChecked())
        self.apply_restriction_checkbox.stateChanged.connect(
            lambda x: self.search_restriction_combo.setEnabled(
                self.apply_restriction_checkbox.isChecked()))

        other_layout.addWidget(self.apply_search_checkbox, 0, 0, 1, 1)
        other_layout.addWidget(self.saved_search_combo, 0, 1, 1, 1)
        other_layout.addWidget(self.apply_virtlib_checkbox, 1, 0, 1, 1)
        other_layout.addWidget(self.virtlib_combo, 1, 1, 1, 1)
        other_layout.addWidget(self.apply_restriction_checkbox, 2, 0, 1, 1)
        other_layout.addWidget(self.search_restriction_combo, 2, 1, 1, 1)
        # other_layout.setRowStretch(4, 1)

        #layout.addSpacing(10)
        other_group_box = QGroupBox('General Options', self)
        layout.addWidget(other_group_box)
        other_group_box_layout = QGridLayout()
        other_group_box.setLayout(other_group_box_layout)

        self.jump_to_top_checkbox = QCheckBox(
            'Jump to the top when applying this View', self)
        jump_to_top = self.library.get(KEY_JUMP_TO_TOP, False)
        self.jump_to_top_checkbox.setCheckState(
            Qt.Checked if jump_to_top else Qt.Unchecked)

        restart_label = QLabel(
            'When restarting Calibre or switching to this library...')
        self.auto_apply_checkbox = QCheckBox('&Automatically apply view:',
                                             self)
        auto_apply = self.library.get(KEY_AUTO_APPLY_VIEW, False)
        self.auto_apply_checkbox.setCheckState(
            Qt.Checked if auto_apply else Qt.Unchecked)
        self.auto_view_combo = ViewComboBox(self,
                                            self.views,
                                            special=LAST_VIEW_ITEM)
        self.auto_view_combo.select_view(
            self.library.get(KEY_VIEW_TO_APPLY, LAST_VIEW_ITEM))
        self.auto_view_combo.setMinimumSize(150, 20)
        info_apply_label = QLabel(
            'Enabling this option may override any startup search restriction or '
            'title sort set in Preferences -> Behaviour/Tweaks.')
        info_apply_label.setWordWrap(True)
        other_group_box_layout.addWidget(self.jump_to_top_checkbox, 0, 0, 1, 2)
        other_group_box_layout.addWidget(restart_label, 1, 0, 1, 2)
        other_group_box_layout.addWidget(self.auto_apply_checkbox, 2, 0, 1, 1)
        other_group_box_layout.addWidget(self.auto_view_combo, 2, 1, 1, 1)
        other_group_box_layout.addWidget(info_apply_label, 3, 0, 1, 2)
        #other_group_box.setMaximumHeight(other_group_box.sizeHint().height())

        keyboard_layout = QHBoxLayout()
        layout.addLayout(keyboard_layout)
        keyboard_shortcuts_button = QPushButton('Keyboard shortcuts...', self)
        keyboard_shortcuts_button.setToolTip(
            _('Edit the keyboard shortcuts associated with this plugin'))
        keyboard_shortcuts_button.clicked.connect(self.edit_shortcuts)
        view_prefs_button = QPushButton('&View library preferences...', self)
        view_prefs_button.setToolTip(
            _('View data stored in the library database for this plugin'))
        view_prefs_button.clicked.connect(self.view_prefs)
        keyboard_layout.addWidget(keyboard_shortcuts_button)
        keyboard_layout.addWidget(view_prefs_button)
        keyboard_layout.addStretch(1)

        # Force an initial display of view information
        if KEY_LAST_VIEW in list(self.library.keys()):
            last_view = self.library[KEY_LAST_VIEW]
            if last_view in self.views:
                self.select_view_combo.select_view(self.library[KEY_LAST_VIEW])
        self.select_view_combo_index_changed(save_previous=False)
        self.select_view_combo.currentIndexChanged.connect(
            partial(self.select_view_combo_index_changed, save_previous=True))

    def save_settings(self):
        # We only need to update the store for the current view, as switching views
        # will have updated the other stores
        self.persist_view_config()

        library_config = get_library_config(self.gui.current_db)
        library_config[KEY_VIEWS] = self.views
        library_config[
            KEY_AUTO_APPLY_VIEW] = self.auto_apply_checkbox.checkState(
            ) == Qt.Checked
        library_config[KEY_VIEW_TO_APPLY] = unicode(
            self.auto_view_combo.currentText())
        set_library_config(self.gui.current_db, library_config)

    def persist_view_config(self):
        if not self.view_name:
            return
        # Update all of the current user information in the store
        view_info = self.views[self.view_name]
        view_info[KEY_COLUMNS] = self.columns_list.get_data()
        view_info[KEY_SORT] = self.sort_list.get_data()
        if self.has_pin_view:
            view_info[
                KEY_APPLY_PIN_COLUMNS] = self.apply_pin_columns_checkbox.checkState(
                ) == Qt.Checked
            view_info[KEY_PIN_COLUMNS] = self.pin_columns_list.get_data()
        view_info[
            KEY_APPLY_RESTRICTION] = self.apply_restriction_checkbox.checkState(
            ) == Qt.Checked
        if view_info[KEY_APPLY_RESTRICTION]:
            view_info[KEY_RESTRICTION] = unicode(
                self.search_restriction_combo.currentText()).strip()
        else:
            view_info[KEY_RESTRICTION] = ''
        view_info[KEY_APPLY_SEARCH] = self.apply_search_checkbox.checkState(
        ) == Qt.Checked
        if view_info[KEY_APPLY_SEARCH]:
            view_info[KEY_SEARCH] = unicode(
                self.saved_search_combo.currentText()).strip()
        else:
            view_info[KEY_SEARCH] = ''
        view_info[KEY_APPLY_VIRTLIB] = self.apply_virtlib_checkbox.checkState(
        ) == Qt.Checked
        if view_info[KEY_APPLY_VIRTLIB]:
            view_info[KEY_VIRTLIB] = unicode(
                self.virtlib_combo.currentText()).strip()
        else:
            view_info[KEY_VIRTLIB] = ''
        view_info[KEY_JUMP_TO_TOP] = self.jump_to_top_checkbox.checkState(
        ) == Qt.Checked

        self.views[self.view_name] = view_info

    def select_view_combo_index_changed(self, save_previous=True):
        # Update the dialog contents with data for the selected view
        if save_previous:
            # Switching views, persist changes made to the other view
            self.persist_view_config()
        if self.select_view_combo.count() == 0:
            self.view_name = None
        else:
            self.view_name = unicode(
                self.select_view_combo.currentText()).strip()
        columns = []
        sort_columns = []
        all_columns = []
        pin_columns = []
        apply_columns = True
        apply_pin_columns = False
        apply_sort = True
        apply_restriction = False
        restriction_to_apply = ''
        apply_search = False
        search_to_apply = ''
        apply_virtlib = False
        virtlib_to_apply = ''
        jump_to_top = False
        if self.view_name != None:
            view_info = self.views[self.view_name]
            columns = copy.deepcopy(view_info[KEY_COLUMNS])
            pin_columns = copy.deepcopy(view_info.get(KEY_PIN_COLUMNS, {}))
            sort_columns = copy.deepcopy(view_info[KEY_SORT])
            all_columns = self.all_columns
            apply_pin_columns = view_info.get(KEY_APPLY_PIN_COLUMNS, False)
            apply_restriction = view_info[KEY_APPLY_RESTRICTION]
            restriction_to_apply = view_info[KEY_RESTRICTION]
            apply_search = view_info[KEY_APPLY_SEARCH]
            search_to_apply = view_info[KEY_SEARCH]
            apply_virtlib = view_info.get(KEY_APPLY_VIRTLIB, False)
            virtlib_to_apply = view_info.get(KEY_VIRTLIB, '')
            jump_to_top = view_info.get(KEY_JUMP_TO_TOP, False)

        self.columns_list.populate(columns, all_columns)
        self.sort_list.populate(sort_columns, all_columns)
        if self.has_pin_view:
            self.pin_columns_list.populate(pin_columns, all_columns)
            self.apply_pin_columns_checkbox.setCheckState(
                Qt.Checked if apply_pin_columns else Qt.Unchecked)
        self.apply_restriction_checkbox.setCheckState(
            Qt.Checked if apply_restriction else Qt.Unchecked)
        self.search_restriction_combo.select_value(restriction_to_apply)
        self.apply_search_checkbox.setCheckState(
            Qt.Checked if apply_search else Qt.Unchecked)
        self.saved_search_combo.select_value(search_to_apply)
        self.apply_virtlib_checkbox.setCheckState(
            Qt.Checked if apply_virtlib else Qt.Unchecked)
        self.virtlib_combo.select_value(virtlib_to_apply)
        self.jump_to_top_checkbox.setCheckState(
            Qt.Checked if jump_to_top else Qt.Unchecked)

    def add_view(self):
        # Display a prompt allowing user to specify a new view
        new_view_name, ok = QInputDialog.getText(
            self,
            'Add new view',
            'Enter a unique display name for this view:',
            text='Default')
        if not ok:
            # Operation cancelled
            return
        new_view_name = unicode(new_view_name).strip()
        # Verify it does not clash with any other views in the list
        for view_name in self.views.keys():
            if view_name.lower() == new_view_name.lower():
                return error_dialog(self,
                                    'Add Failed',
                                    'A view with the same name already exists',
                                    show=True)

        self.persist_view_config()
        view_info = get_empty_view()

        if self.view_name != None:
            # We will copy values from the currently selected view
            old_view_info = self.views[self.view_name]
            view_info[KEY_COLUMNS] = copy.deepcopy(old_view_info[KEY_COLUMNS])
            view_info[KEY_APPLY_PIN_COLUMNS] = copy.deepcopy(
                old_view_info.get(KEY_APPLY_PIN_COLUMNS, False))
            view_info[KEY_PIN_COLUMNS] = copy.deepcopy(
                old_view_info.get(KEY_PIN_COLUMNS, {}))
            view_info[KEY_SORT] = copy.deepcopy(old_view_info[KEY_SORT])
            view_info[KEY_APPLY_RESTRICTION] = copy.deepcopy(
                old_view_info[KEY_APPLY_RESTRICTION])
            view_info[KEY_RESTRICTION] = copy.deepcopy(
                old_view_info[KEY_RESTRICTION])
            view_info[KEY_APPLY_SEARCH] = copy.deepcopy(
                old_view_info[KEY_APPLY_SEARCH])
            view_info[KEY_SEARCH] = copy.deepcopy(old_view_info[KEY_SEARCH])
            view_info[KEY_APPLY_VIRTLIB] = copy.deepcopy(
                old_view_info.get(KEY_APPLY_VIRTLIB, False))
            view_info[KEY_VIRTLIB] = copy.deepcopy(
                old_view_info.get(KEY_VIRTLIB, ''))
            view_info[KEY_JUMP_TO_TOP] = copy.deepcopy(
                old_view_info[KEY_JUMP_TO_TOP])
        else:
            # We will copy values from the current library view
            view_info[KEY_COLUMNS] = self.get_current_columns(
                visible_only=True)

        self.view_name = new_view_name
        self.views[new_view_name] = view_info
        # Now update the views combobox
        self.select_view_combo.populate_combo(self.views, new_view_name)
        self.select_view_combo_index_changed(save_previous=False)
        self.auto_view_combo.populate_combo(
            self.views, unicode(self.auto_view_combo.currentText()))

    def rename_view(self):
        if not self.view_name != None:
            return
        # Display a prompt allowing user to specify a rename view
        old_view_name = self.view_name
        new_view_name, ok = QInputDialog.getText(
            self,
            'Rename view',
            'Enter a new display name for this view:',
            text=old_view_name)
        if not ok:
            # Operation cancelled
            return
        new_view_name = unicode(new_view_name).strip()
        if new_view_name == old_view_name:
            return
        # Verify it does not clash with any other views in the list
        for view_name in self.views.keys():
            if view_name == old_view_name:
                continue
            if view_name.lower() == new_view_name.lower():
                return error_dialog(self,
                                    'Add Failed',
                                    'A view with the same name already exists',
                                    show=True)

        # Ensure any changes are persisted
        self.persist_view_config()
        view_info = self.views[old_view_name]
        del self.views[old_view_name]
        self.view_name = new_view_name
        self.views[new_view_name] = view_info
        # Now update the views combobox
        self.select_view_combo.populate_combo(self.views, new_view_name)
        self.select_view_combo_index_changed(save_previous=False)
        if unicode(self.auto_view_combo.currentText()) == old_view_name:
            self.auto_view_combo.populate_combo(self.views, new_view_name)
        else:
            self.auto_view_combo.populate_combo(self.views)

    def delete_view(self):
        if self.view_name == None:
            return
        if not question_dialog(
                self,
                _('Are you sure?'),
                '<p>' +
                'Do you want to delete the view named \'%s\'' % self.view_name,
                show_copy_button=False):
            return
        del self.views[self.view_name]
        # Now update the views combobox
        self.select_view_combo.populate_combo(self.views)
        self.select_view_combo_index_changed(save_previous=False)
        self.auto_view_combo.populate_combo(self.views)

    def get_current_columns(self, defaults=False, visible_only=False):
        model = self.gui.library_view.model()
        colmap = list(model.column_map)
        state = self.columns_state(defaults)
        positions = state['column_positions']
        colmap.sort(key=lambda x: positions[x])
        hidden_cols = state['hidden_columns']
        if visible_only:
            colmap = [
                col for col in colmap
                if col not in hidden_cols or col == 'ondevice'
            ]
        # Convert our list of column names into a list of tuples with column widths
        colsizemap = []
        for col in colmap:
            if col in hidden_cols:
                colsizemap.append((col, -1))
            else:
                colsizemap.append((col, state['column_sizes'].get(col, -1)))
        return colsizemap

    def columns_state(self, defaults=False):
        if defaults:
            return self.gui.library_view.get_default_state()
        return self.gui.library_view.get_state()

    def edit_shortcuts(self):
        self.save_settings()
        # Force the menus to be rebuilt immediately, so we have all our actions registered
        self.plugin_action.rebuild_menus()
        d = KeyboardConfigDialog(self.plugin_action.gui,
                                 self.plugin_action.action_spec[0])
        if d.exec_() == d.Accepted:
            self.plugin_action.gui.keyboard.finalize()

    def view_prefs(self):
        d = PrefsViewerDialog(self.plugin_action.gui, PREFS_NAMESPACE)
        d.exec_()
Exemple #52
0
class ConfigWidget(QWidget):

    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        # --- Directory Options ---
        directory_group_box = QGroupBox(_('Default Unpack Directory:'), self)
        layout.addWidget(directory_group_box)
        directory_group_box_layout = QVBoxLayout()
        directory_group_box.setLayout(directory_group_box_layout)

        # Directory path Textbox
        # Load the textbox with the current preference setting
        self.directory_txtBox = QLineEdit(plugin_prefs['Unpack_Folder'], self)
        self.directory_txtBox.setToolTip(_('<p>Default directory to extract files to'))
        directory_group_box_layout.addWidget(self.directory_txtBox)
        self.directory_txtBox.setReadOnly(True)

        # Folder select button
        directory_button = QPushButton(_('Select/Change Unpack Directory'), self)
        directory_button.setToolTip(_('<p>Select/Change directory to extract files to.'))
        # Connect button to the getDirectory function
        directory_button.clicked.connect(self.getDirectory)
        directory_group_box_layout.addWidget(directory_button)
        self.default_folder_check = QCheckBox(_('Always use the Default Unpack Directory'), self)
        self.default_folder_check.setToolTip(_('<p>When unchecked... you will be prompted to select a destination '+
                                                                                'directory for the extracted content each time you use Mobiunpack.'))
        directory_group_box_layout.addWidget(self.default_folder_check)
        # Load the checkbox with the current preference setting
        self.default_folder_check.setChecked(plugin_prefs['Always_Use_Unpack_Folder'])

        misc_group_box = QGroupBox(_('Default settings:'), self)
        layout.addWidget(misc_group_box)
        misc_group_box_layout = QVBoxLayout()
        misc_group_box.setLayout(misc_group_box_layout)

        self.use_hd_images = QCheckBox(_('Always use HD images if present'), self)
        self.use_hd_images.setToolTip(_('<p>When checked... any HD images present in the kindlebook '+
                                                                                'will be used for creating the ePub.'))
        misc_group_box_layout.addWidget(self.use_hd_images)
        # Load the checkbox with the current preference setting
        self.use_hd_images.setChecked(plugin_prefs['Use_HD_Images'])

        combo_label = QLabel('Select epub version output:', self)
        misc_group_box_layout.addWidget(combo_label)
        self.epub_version_combobox = QComboBox()
        self.epub_version_combobox.setToolTip(_('<p>Select the type of OPF file to create.'))
        misc_group_box_layout.addWidget(self.epub_version_combobox)
        self.epub_version_combobox.addItems(['Auto-detect', 'ePub2', 'ePub3'])
        if plugin_prefs['Epub_Version'] == 'A':
            self.epub_version_combobox.setCurrentIndex(0)
        else:
            self.epub_version_combobox.setCurrentIndex(int(plugin_prefs['Epub_Version'])-1)

    def save_settings(self):
        # Save current dialog sttings back to JSON config file
            plugin_prefs['Unpack_Folder'] = unicode(self.directory_txtBox.displayText())
            plugin_prefs['Always_Use_Unpack_Folder'] = self.default_folder_check.isChecked()
            plugin_prefs['Use_HD_Images'] = self.use_hd_images.isChecked()
            if unicode(self.epub_version_combobox.currentText()) == 'Auto-detect':
                plugin_prefs['Epub_Version'] = 'A'
            else:
                plugin_prefs['Epub_Version'] = unicode(self.epub_version_combobox.currentText())[4:]

    def getDirectory(self):
        c = choose_dir(self, _(PLUGIN_NAME + 'dir_chooser'),
                _('Select Default Directory To Unpack Kindle Book/Mobi To'))
        if c:
            self.directory_txtBox.setReadOnly(False)
            self.directory_txtBox.setText(c)
            self.directory_txtBox.setReadOnly(True)

    def validate(self):
        # This is just to catch the situation where somone might
        # manually enter a non-existent path in the Default path textbox.
        # Shouldn't be possible at this point.
        if not os.path.exists(self.directory_txtBox.text()):
            errmsg = '<p>The path specified for the Default Unpack folder does not exist.</p>' \
                        '<p>Your latest preference changes will <b>NOT</b> be saved!</p>' + \
                        '<p>You should configure again and make sure your settings are correct.'
            error_dialog(None, _(PLUGIN_NAME + ' v' + PLUGIN_VERSION),
                                    _(errmsg), show=True)
            return False
        return True