Пример #1
0
    def setup_store_checks(self):
        first_run = self.config.get('first_run', True)

        # Add check boxes for each store so the user
        # can disable searching specific stores on a
        # per search basis.
        existing = {}
        for n in self.store_checks:
            existing[n] = self.store_checks[n].isChecked()

        self.store_checks = {}

        stores_check_widget = QWidget()
        store_list_layout = QGridLayout()
        stores_check_widget.setLayout(store_list_layout)

        icon = QIcon(I('donate.png'))
        for i, x in enumerate(sorted(self.gui.istores.keys(), key=lambda x: x.lower())):
            cbox = QCheckBox(x)
            cbox.setChecked(existing.get(x, first_run))
            store_list_layout.addWidget(cbox, i, 0, 1, 1)
            if self.gui.istores[x].base_plugin.affiliate:
                iw = QLabel(self)
                iw.setToolTip('<p>' + _('Buying from this store supports the calibre developer: %s</p>') % self.gui.istores[x].base_plugin.author + '</p>')
                iw.setPixmap(icon.pixmap(16, 16))
                store_list_layout.addWidget(iw, i, 1, 1, 1)
            self.store_checks[x] = cbox
        store_list_layout.setRowStretch(store_list_layout.rowCount(), 10)
        self.store_list.setWidget(stores_check_widget)

        self.config['first_run'] = False
Пример #2
0
    def slotEditUser(self, item=None):
        if not item:
            item = self.ui.userList.currentItem()
        self.ui.userList.setCurrentItem(item)
        user = item.getUser()
        if user.uid > -1:
            self.ui.userIDCheck.setChecked(True)
            self.ui.userID.setValue(user.uid)
        self.ui.username.setText(user.username)
        self.ui.realname.setText(user.realname)
        self.ui.pass1.setText(user.passwd)
        self.ui.pass2.setText(user.passwd)

        if "wheel" in user.groups:
            self.ui.admin.setChecked(True)
        else:
            self.ui.admin.setChecked(False)

        self.ui.noPass.setChecked(user.no_password)

        self.edititemindex = self.ui.userList.currentRow()
        self.ui.createButton.setText(_("Update"))
        icon = QIcon()
        icon.addPixmap(QPixmap(":/gui/pics/tick.png"), QIcon.Normal, QIcon.Off)
        self.ui.createButton.setIcon(icon)
        self.ui.cancelButton.setVisible(self.ui.createButton.isVisible())
Пример #3
0
class CompletionCandidate:

    def __init__(self, place_id, url, title, substrings):
        self.value = url
        self.place_id = place_id

        def get_positions(text):
            ans = set()
            text = text.lower()
            for ss in substrings:
                idx = text.find(ss.lower())
                if idx > -1:
                    ans |= set(range(idx, idx + len(ss)))
            return sorted(ans)

        self.left = make_highlighted_text(url, get_positions(url))
        self.right = make_highlighted_text(title, get_positions(title))
        self._icon = None

    def adjust_size_hint(self, option, ans):
        ans.setHeight(max(option.decorationSize.height() + 6, ans.height()))

    @property
    def icon(self):
        if self._icon is None:
            self._icon = QIcon()
            url = places.favicon_url(self.place_id)
            if url is not None:
                f = QApplication.instance().disk_cache.data(QUrl(url))
                if f is not None:
                    with closing(f):
                        raw = f.readAll()
                    p = QPixmap()
                    p.loadFromData(raw)
                    if not p.isNull():
                        self._icon.addPixmap(p)
        return self._icon

    def __repr__(self):
        return self.value

    def draw_item(self, painter, style, option):
        option.features |= option.HasDecoration
        option.icon = self.icon
        text_rect = style.subElementRect(style.SE_ItemViewItemText, option, None)
        x, y = text_rect.x(), text_rect.y()
        y += (text_rect.height() - self.left.size().height()) // 2
        if not option.icon.isNull():
            icon_rect = style.subElementRect(style.SE_ItemViewItemDecoration, option, None)
            icon_rect.setTop(y), icon_rect.setBottom(text_rect.bottom())
            option.icon.paint(painter, icon_rect)
        option.icon = QIcon()
        width = (text_rect.width() // 2) - 10
        painter.setClipRect(x, text_rect.y(), width, text_rect.height())
        painter.drawStaticText(QPoint(x, y), self.left)
        painter.setClipRect(text_rect)
        x += width + 20
        painter.drawStaticText(QPoint(x, y), self.right)
Пример #4
0
 def load_menu(self):
     self.store_list_menu.clear()
     icon = QIcon()
     icon.addFile(I('donate.png'), QSize(16, 16))
     for n, p in sorted(self.gui.istores.items(), key=lambda x: x[0].lower()):
         if p.base_plugin.affiliate:
             self.store_list_menu.addAction(icon, n,
                                            partial(self.open_store, n))
         else:
             self.store_list_menu.addAction(n, partial(self.open_store, n))
Пример #5
0
 def finalize_entry(entry):
     icon_path = entry.get('Icon')
     if icon_path:
         ic = QIcon(icon_path)
         if not ic.isNull():
             pmap = ic.pixmap(48, 48)
             if not pmap.isNull():
                 entry['icon_data'] = pixmap_to_data(pmap)
     entry['MimeType'] = tuple(entry['MimeType'])
     return entry
Пример #6
0
    def slotAdvanced(self):
        icon_path = None
        if self.ui.scrollArea.isVisible():
            icon_path = ":/gui/pics/expand.png"
            self.time_line.start()
        else:
            self.ui.scrollArea.show()
            icon_path = ":/gui/pics/collapse.png"
            self.time_line.start()

        icon = QIcon()
        icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off)
        self.ui.addMoreUsers.setIcon(icon)
        self.checkUsers()
Пример #7
0
 def cached_emblem(self, cache, name, raw_icon=None):
     ans = cache.get(name, False)
     if ans is not False:
         return ans
     sz = self.emblem_size
     ans = None
     if raw_icon is not None:
         ans = raw_icon.pixmap(sz, sz)
     elif name == ':ondevice':
         ans = QIcon(I('ok.png')).pixmap(sz, sz)
     elif name:
         pmap = QIcon(os.path.join(config_dir, 'cc_icons', name)).pixmap(sz, sz)
         if not pmap.isNull():
             ans = pmap
     cache[name] = ans
     return ans
Пример #8
0
    def slotDeleteUser(self):
        if self.ui.userList.currentRow() == self.edititemindex:
            self.resetWidgets()
            self.ui.autoLogin.setCurrentIndex(0)
        _cur = self.ui.userList.currentRow()
        item = self.ui.userList.item(_cur).getUser()
        if item.uid in self.used_ids:
            self.used_ids.remove(item.uid)
        self.ui.userList.takeItem(_cur)
        self.ui.autoLogin.removeItem(_cur + 1)
        self.ui.createButton.setText(_("Add"))

        icon = QIcon()
        icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off)
        self.ui.createButton.setIcon(icon)

        self.ui.cancelButton.hide()
        self.checkUsers()
Пример #9
0
 def resetWidgets(self):
     # clear all
     self.edititemindex = None
     self.ui.username.clear()
     self.ui.realname.clear()
     self.ui.pass1.clear()
     self.ui.pass2.clear()
     self.ui.admin.setChecked(False)
     self.ui.noPass.setChecked(False)
     self.ui.userIDCheck.setChecked(False)
     self.ui.createButton.setEnabled(False)
     if self.ui.cancelButton.isVisible():
         self.ui.cancelButton.setHidden(self.sender() == self.ui.cancelButton)
         self.checkUsers()
     self.ui.createButton.setText(_("Add"))
     icon = QIcon()
     icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off)
     self.ui.createButton.setIcon(icon)
Пример #10
0
 def change_icon(self):
     ci = self.plist.currentItem()
     if ci is None:
         return error_dialog(self, _('No selection'), _(
             'No application selected'), show=True)
     paths = choose_images(self, 'choose-new-icon-for-open-with-program', _(
         'Choose new icon'))
     if paths:
         ic = QIcon(paths[0])
         if ic.isNull():
             return error_dialog(self, _('Invalid icon'), _(
                 'Could not load image from %s') % paths[0], show=True)
         pmap = ic.pixmap(48, 48)
         if not pmap.isNull():
             entry = ci.data(ENTRY_ROLE)
             entry['icon_data'] = pixmap_to_data(pmap)
             ci.setData(ENTRY_ROLE, entry)
             self.update_stored_config()
             ci.setIcon(ic)
Пример #11
0
    def __init__(self, title, msg=u'\u00a0', min=0, max=99, parent=None, cancelable=True, icon=None):
        QDialog.__init__(self, parent)
        if icon is None:
            self.l = l = QVBoxLayout(self)
        else:
            self.h = h = QHBoxLayout(self)
            self.icon = i = QLabel(self)
            if not isinstance(icon, QIcon):
                icon = QIcon(I(icon))
            i.setPixmap(icon.pixmap(64))
            h.addWidget(i, alignment=Qt.AlignTop | Qt.AlignHCenter)
            self.l = l = QVBoxLayout()
            h.addLayout(l)
            self.setWindowIcon(icon)

        self.title_label = t = QLabel(title)
        self.setWindowTitle(title)
        t.setStyleSheet('QLabel { font-weight: bold }'), t.setAlignment(Qt.AlignCenter), t.setTextFormat(Qt.PlainText)
        l.addWidget(t)

        self.bar = b = QProgressBar(self)
        b.setMinimum(min), b.setMaximum(max), b.setValue(min)
        l.addWidget(b)

        self.message = m = QLabel(self)
        fm = QFontMetrics(self.font())
        m.setAlignment(Qt.AlignCenter), m.setMinimumWidth(fm.averageCharWidth() * 80), m.setTextFormat(Qt.PlainText)
        l.addWidget(m)
        self.msg = msg

        self.button_box = bb = QDialogButtonBox(QDialogButtonBox.Abort, self)
        bb.rejected.connect(self._canceled)
        l.addWidget(bb)

        self.setWindowModality(Qt.ApplicationModal)
        self.canceled = False

        if not cancelable:
            bb.setVisible(False)
        self.cancelable = cancelable
        self.resize(self.sizeHint())
Пример #12
0
 def icon(self):
     if self._icon is None:
         self._icon = QIcon()
         url = places.favicon_url(self.place_id)
         if url is not None:
             f = QApplication.instance().disk_cache.data(QUrl(url))
             if f is not None:
                 with closing(f):
                     raw = f.readAll()
                 p = QPixmap()
                 p.loadFromData(raw)
                 if not p.isNull():
                     self._icon.addPixmap(p)
     return self._icon
Пример #13
0
    def __init__(self, plugins):
        QAbstractItemModel.__init__(self)

        self.NO_DRM_ICON = QIcon(I('ok.png'))
        self.DONATE_ICON = QIcon()
        self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16))

        self.all_matches = plugins
        self.matches = plugins
        self.filter = ''
        self.search_filter = SearchFilter(self.all_matches)

        self.sort_col = 1
        self.sort_order = Qt.AscendingOrder
Пример #14
0
def icon_data_for_filename(fname, size=64):
    ''' Return the file type icon (as bytes) for the given filename '''
    raw = b''
    if fname:
        if not hasattr(icon_data_for_filename, 'md'):
            icon_data_for_filename.md = QMimeDatabase()
        for mt in icon_data_for_filename.md.mimeTypesForFileName(fname):
            icname = mt.iconName()
            if icname:
                ic = QIcon.fromTheme(icname)
                if not ic.isNull():
                    raw = icon_to_data(ic)
                    if raw:
                        break
    return raw
Пример #15
0
    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()
Пример #16
0
 def slotCheckCD(self):
     if self.check_media_stop:
         self.check_media_stop = False
         self.ui.progressBar.show()
         icon = QIcon()
         icon.addPixmap(QPixmap(":/gui/pics/dialog-error.png"), QIcon.Normal, QIcon.Off)
         self.ui.checkButton.setIcon(icon)
         self.ui.checkButton.setText("")
         self.checkMedia()
     else:
         self.check_media_stop = True
         self.ui.progressBar.show()
         icon = QIcon()
         icon.addPixmap(QPixmap(":/gui/pics/task-accepted.png"), QIcon.Normal, QIcon.Off)
         self.ui.checkButton.setIcon(icon)
         self.ui.checkButton.setText(_("Validate"))
Пример #17
0
 def contextMenuEvent(self, event):
     if self.item != None:
         menu = QMenu(self.parent())
         self.actionUpdate = QtWidgets.QAction(self.parent())
         icon = QIcon()
         icon.addPixmap(QPixmap(":/icons/16x16/update"), QIcon.Normal, QIcon.Off)
         self.actionUpdate.setIcon(icon)
         self.actionUpdate.setObjectName(self.item.name)
         self.actionUpdate.setText("Update")
         self.actionUpdate.triggered.connect(self.onUpdate)
         menu.addAction(self.actionUpdate)
         self.actionDelete = QtWidgets.QAction(self.parent())
         icon = QIcon()
         icon.addPixmap(QPixmap(":/icons/16x16/delete"), QIcon.Normal, QIcon.Off)
         self.actionDelete.setIcon(icon)
         self.actionDelete.setObjectName(self.item.name)
         self.actionDelete.setText("Supprimer")
         self.actionDelete.triggered.connect(self.onDelete)
         menu.addAction(self.actionDelete)
         menu.exec_(self.mapToGlobal(event.pos()))
Пример #18
0
    def setup_ui(self):
        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.la1 = la = QLabel(_('&Existing images in the book'))
        la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        l.addWidget(la, 0, 0, 1, 2)
        if self.for_browsing:
            la.setVisible(False)

        self.view = v = QListView(self)
        v.setViewMode(v.IconMode)
        v.setFlow(v.LeftToRight)
        v.setSpacing(4)
        v.setResizeMode(v.Adjust)
        v.setUniformItemSizes(True)
        pi = plugins['progress_indicator'][0]
        if hasattr(pi, 'set_no_activate_on_click'):
            pi.set_no_activate_on_click(v)
        v.activated.connect(self.activated)
        v.doubleClicked.connect(self.activated)
        self.d = ImageDelegate(v)
        v.setItemDelegate(self.d)
        self.model = Images(self.view)
        self.fm = fm = QSortFilterProxyModel(self.view)
        self.fm.setDynamicSortFilter(self.for_browsing)
        fm.setSourceModel(self.model)
        fm.setFilterCaseSensitivity(False)
        v.setModel(fm)
        l.addWidget(v, 1, 0, 1, 2)
        v.pressed.connect(self.pressed)
        la.setBuddy(v)

        self.filter = f = QLineEdit(self)
        f.setPlaceholderText(_('Search for image by file name'))
        l.addWidget(f, 2, 0)
        self.cb = b = QToolButton(self)
        b.setIcon(QIcon(I('clear_left.png')))
        b.clicked.connect(f.clear)
        l.addWidget(b, 2, 1)
        f.textChanged.connect(self.filter_changed)

        if self.for_browsing:
            self.bb.clear()
            self.bb.addButton(self.bb.Close)
            b = self.refresh_button = self.bb.addButton(
                _('&Refresh'), self.bb.ActionRole)
            b.clicked.connect(self.refresh)
            b.setIcon(QIcon(I('view-refresh.png')))
            b.setToolTip(_('Refresh the displayed images'))
            self.setAttribute(Qt.WA_DeleteOnClose, False)
        else:
            b = self.import_button = self.bb.addButton(_('&Import image'),
                                                       self.bb.ActionRole)
            b.clicked.connect(self.import_image)
            b.setIcon(QIcon(I('view-image.png')))
            b.setToolTip(_('Import an image from elsewhere in your computer'))
            b = self.paste_button = self.bb.addButton(_('&Paste image'),
                                                      self.bb.ActionRole)
            b.clicked.connect(self.paste_image)
            b.setIcon(QIcon(I('edit-paste.png')))
            b.setToolTip(_('Paste an image from the clipboard'))
            self.fullpage = f = QCheckBox(_('Full page image'), self)
            f.setToolTip(
                _('Insert the image so that it takes up an entire page when viewed in a reader'
                  ))
            f.setChecked(tprefs['insert_full_screen_image'])
            self.preserve_aspect_ratio = a = QCheckBox(
                _('Preserve aspect ratio'))
            a.setToolTip(
                _('Preserve the aspect ratio of the inserted image when rendering it full paged'
                  ))
            a.setChecked(tprefs['preserve_aspect_ratio_when_inserting_image'])
            f.toggled.connect(
                lambda: (tprefs.set('insert_full_screen_image', f.isChecked()),
                         a.setVisible(f.isChecked())))
            a.toggled.connect(lambda: tprefs.set(
                'preserve_aspect_ratio_when_inserting_image', a.isChecked()))
            a.setVisible(f.isChecked())
            h = QHBoxLayout()
            l.addLayout(h, 3, 0, 1, -1)
            h.addWidget(f), h.addStretch(10), h.addWidget(a)
        l.addWidget(self.bb, 4, 0, 1, 2)
Пример #19
0
class MessageBox(QDialog):  # {{{

    ERROR = 0
    WARNING = 1
    INFO = 2
    QUESTION = 3

    resize_needed = pyqtSignal()

    def setup_ui(self):
        self.setObjectName("Dialog")
        self.resize(497, 235)
        self.gridLayout = l = QGridLayout(self)
        l.setObjectName("gridLayout")
        self.icon_label = la = QLabel('')
        la.setMaximumSize(QSize(68, 68))
        la.setScaledContents(True)
        la.setObjectName("icon_label")
        l.addWidget(la)
        self.msg = la = QLabel(self)
        la.setWordWrap(True), la.setMinimumWidth(400)
        la.setOpenExternalLinks(True)
        la.setObjectName("msg")
        l.addWidget(la, 0, 1, 1, 1)
        self.det_msg = dm = QPlainTextEdit(self)
        dm.setReadOnly(True)
        dm.setObjectName("det_msg")
        l.addWidget(dm, 1, 0, 1, 2)
        self.bb = bb = QDialogButtonBox(self)
        bb.setStandardButtons(QDialogButtonBox.Ok)
        bb.setObjectName("bb")
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        l.addWidget(bb, 3, 0, 1, 2)
        self.toggle_checkbox = tc = QCheckBox(self)
        tc.setObjectName("toggle_checkbox")
        l.addWidget(tc, 2, 0, 1, 2)

    def __init__(self, type_, title, msg,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None, default_yes=True,
                 yes_text=None, no_text=None, yes_icon=None, no_icon=None):
        QDialog.__init__(self, parent)
        if q_icon is None:
            icon = {
                    self.ERROR : 'error',
                    self.WARNING: 'warning',
                    self.INFO:    'information',
                    self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png'%icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(I(q_icon))
        self.setup_ui()

        self.setWindowTitle(title)
        self.setWindowIcon(self.icon)
        self.icon_label.setPixmap(self.icon.pixmap(128, 128))
        self.msg.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                    self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes|self.bb.No)
            self.bb.button(self.bb.Yes if default_yes else self.bb.No
                    ).setDefault(True)
            self.default_yes = default_yes
            if yes_text is not None:
                self.bb.button(self.bb.Yes).setText(yes_text)
            if no_text is not None:
                self.bb.button(self.bb.No).setText(no_text)
            if yes_icon is not None:
                self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(yes_icon, QIcon) else QIcon(I(yes_icon)))
            if no_icon is not None:
                self.bb.button(self.bb.No).setIcon(no_icon if isinstance(no_icon, QIcon) else QIcon(I(no_icon)))
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection)
        self.do_resize()

    def sizeHint(self):
        ans = QDialog.sizeHint(self)
        ans.setWidth(max(min(ans.width(), 500), self.bb.sizeHint().width() + 100))
        ans.setHeight(min(ans.height(), 500))
        return ans

    def toggle_det_msg(self, *args):
        vis = self.det_msg.isVisible()
        self.det_msg.setVisible(not vis)
        self.det_msg_toggle.setText(self.show_det_msg if vis else self.hide_det_msg)
        self.resize_needed.emit()

    def do_resize(self):
        self.resize(self.sizeHint())

    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.text()),
                    unicode(self.det_msg.toPlainText())))
        if hasattr(self, 'ctc_button'):
            self.ctc_button.setText(_('Copied'))

    def showEvent(self, ev):
        ret = QDialog.showEvent(self, ev)
        if self.is_question:
            try:
                self.bb.button(self.bb.Yes if self.default_yes else self.bb.No
                        ).setFocus(Qt.OtherFocusReason)
            except:
                pass  # Buttons were changed
        else:
            self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason)
        return ret

    def set_details(self, msg):
        if not msg:
            msg = ''
        self.det_msg.setPlainText(msg)
        self.det_msg_toggle.setText(self.show_det_msg)
        self.det_msg_toggle.setVisible(bool(msg))
        self.det_msg.setVisible(False)
        self.resize_needed.emit()
Пример #20
0
class Matches(QAbstractItemModel):

    HEADERS = [_('Enabled'), _('Name'), _('No DRM'), _('Headquarters'), _('Affiliate'), _('Formats')]
    HTML_COLS = [1]

    def __init__(self, plugins):
        QAbstractItemModel.__init__(self)

        self.NO_DRM_ICON = QIcon(I('ok.png'))
        self.DONATE_ICON = QIcon()
        self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16))

        self.all_matches = plugins
        self.matches = plugins
        self.filter = ''
        self.search_filter = SearchFilter(self.all_matches)

        self.sort_col = 1
        self.sort_order = Qt.AscendingOrder

    def get_plugin(self, index):
        row = index.row()
        if row < len(self.matches):
            return self.matches[row]
        else:
            return None

    def search(self, filter):
        self.filter = filter.strip()
        if not self.filter:
            self.matches = self.all_matches
        else:
            try:
                self.matches = list(self.search_filter.parse(self.filter))
            except:
                self.matches = self.all_matches
        self.layoutChanged.emit()
        self.sort(self.sort_col, self.sort_order)

    def enable_all(self):
        for i in xrange(len(self.matches)):
            index = self.createIndex(i, 0)
            data = (True)
            self.setData(index, data, Qt.CheckStateRole)

    def enable_none(self):
        for i in xrange(len(self.matches)):
            index = self.createIndex(i, 0)
            data = (False)
            self.setData(index, data, Qt.CheckStateRole)

    def enable_invert(self):
        for i in xrange(len(self.matches)):
            self.toggle_plugin(self.createIndex(i, 0))

    def toggle_plugin(self, index):
        new_index = self.createIndex(index.row(), 0)
        data = (is_disabled(self.get_plugin(index)))
        self.setData(new_index, data, Qt.CheckStateRole)

    def index(self, row, column, parent=QModelIndex()):
        return self.createIndex(row, column)

    def parent(self, index):
        if not index.isValid() or index.internalId() == 0:
            return QModelIndex()
        return self.createIndex(0, 0)

    def rowCount(self, *args):
        return len(self.matches)

    def columnCount(self, *args):
        return len(self.HEADERS)

    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole:
            return None
        text = ''
        if orientation == Qt.Horizontal:
            if section < len(self.HEADERS):
                text = self.HEADERS[section]
            return (text)
        else:
            return (section+1)

    def data(self, index, role):
        row, col = index.row(), index.column()
        result = self.matches[row]
        if role in (Qt.DisplayRole, Qt.EditRole):
            if col == 1:
                return ('<b>%s</b><br><i>%s</i>' % (result.name, result.description))
            elif col == 3:
                return (result.headquarters)
            elif col == 5:
                return (', '.join(result.formats).upper())
        elif role == Qt.DecorationRole:
            if col == 2:
                if result.drm_free_only:
                    return (self.NO_DRM_ICON)
            if col == 4:
                if result.affiliate:
                    return (self.DONATE_ICON)
        elif role == Qt.CheckStateRole:
            if col == 0:
                if is_disabled(result):
                    return Qt.Unchecked
                return Qt.Checked
        elif role == Qt.ToolTipRole:
            if col == 0:
                if is_disabled(result):
                    return ('<p>' + _('This store is currently disabled and cannot be used in other parts of calibre.') + '</p>')
                else:
                    return ('<p>' + _('This store is currently enabled and can be used in other parts of calibre.') + '</p>')
            elif col == 1:
                return ('<p>%s</p>' % result.description)
            elif col == 2:
                if result.drm_free_only:
                    return ('<p>' + _('This store only distributes e-books without DRM.') + '</p>')
                else:
                    return ('<p>' + _('This store distributes e-books with DRM. It may have some titles without DRM, but you will need to check on a per title basis.') + '</p>')  # noqa
            elif col == 3:
                return ('<p>' + _('This store is headquartered in %s. This is a good indication of what market the store caters to. However, this does not necessarily mean that the store is limited to that market only.') % result.headquarters + '</p>')  # noqa
            elif col == 4:
                if result.affiliate:
                    return ('<p>' + _('Buying from this store supports the calibre developer: %s.') % result.author + '</p>')
            elif col == 5:
                return ('<p>' + _('This store distributes e-books in the following formats: %s') % ', '.join(result.formats) + '</p>')
        return None

    def setData(self, index, data, role):
        if not index.isValid():
            return False
        col = index.column()
        if col == 0:
            if bool(data):
                enable_plugin(self.get_plugin(index))
            else:
                disable_plugin(self.get_plugin(index))
        self.dataChanged.emit(self.index(index.row(), 0), self.index(index.row(), self.columnCount() - 1))
        return True

    def flags(self, index):
        if index.column() == 0:
            return QAbstractItemModel.flags(self, index) | Qt.ItemIsUserCheckable
        return QAbstractItemModel.flags(self, index)

    def data_as_text(self, match, col):
        text = ''
        if col == 0:
            text = 'b' if is_disabled(match) else 'a'
        elif col == 1:
            text = match.name
        elif col == 2:
            text = 'a' if getattr(match, 'drm_free_only', True) else 'b'
        elif col == 3:
            text = getattr(match, 'headquarters', '')
        elif col == 4:
            text = 'a' if getattr(match, 'affiliate', False) else 'b'
        return text

    def sort(self, col, order, reset=True):
        self.sort_col = col
        self.sort_order = order
        if not self.matches:
            return
        descending = order == Qt.DescendingOrder
        self.matches.sort(None,
            lambda x: sort_key(unicode(self.data_as_text(x, col))),
            descending)
        if reset:
            self.beginResetModel(), self.endResetModel()
Пример #21
0
    def __init__(self, gui, initial_plugin=None, close_after_initial=False):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.must_restart = False
        self.do_restart = False
        self.committed = False
        self.close_after_initial = close_after_initial

        self.resize(930, 720)
        nh, nw = min_available_height() - 25, available_width() - 10
        if nh < 0:
            nh = 800
        if nw < 0:
            nw = 600
        nh = min(self.height(), nh)
        nw = min(self.width(), nw)
        self.resize(nw, nh)

        geom = gprefs.get('preferences dialog geometry', None)
        if geom is not None:
            self.restoreGeometry(geom)

        # Center
        if islinux:
            self.move(gui.rect().center() - self.rect().center())

        self.setWindowModality(Qt.ApplicationModal)
        self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
        self.setWindowIcon(QIcon(I('config.png')))
        self.l = l = QVBoxLayout(self)

        self.stack = QStackedWidget(self)
        self.bb = QDialogButtonBox(QDialogButtonBox.Close
                                   | QDialogButtonBox.Apply
                                   | QDialogButtonBox.Discard
                                   | QDialogButtonBox.RestoreDefaults)
        self.bb.button(self.bb.Apply).clicked.connect(self.accept)
        self.bb.button(self.bb.Discard).clicked.connect(self.reject)
        self.bb.button(self.bb.RestoreDefaults).setIcon(
            QIcon(I('clear_left.png')))
        self.bb.button(self.bb.RestoreDefaults).clicked.connect(
            self.restore_defaults)
        self.wizard_button = self.bb.addButton(_('Run Welcome &wizard'),
                                               self.bb.ActionRole)
        self.wizard_button.setIcon(QIcon(I('wizard.png')))
        self.wizard_button.clicked.connect(self.run_wizard,
                                           type=Qt.QueuedConnection)
        self.wizard_button.setAutoDefault(False)
        self.bb.rejected.connect(self.reject)
        self.browser = Browser(self)
        self.browser.show_plugin.connect(self.show_plugin)
        self.stack.addWidget(self.browser)
        self.scroll_area = QScrollArea(self)
        self.stack.addWidget(self.scroll_area)
        self.scroll_area.setWidgetResizable(True)

        self.setContextMenuPolicy(Qt.NoContextMenu)
        self.title_bar = TitleBar(self)
        for ac, tt in [(self.bb.Apply, _('Save changes')),
                       (self.bb.Discard, _('Cancel and return to overview'))]:
            self.bb.button(ac).setToolTip(tt)

        l.addWidget(self.title_bar), l.addWidget(self.stack), l.addWidget(
            self.bb)

        if initial_plugin is not None:
            category, name = initial_plugin[:2]
            plugin = get_plugin(category, name)
            if plugin is not None:
                self.show_plugin(plugin)
                if len(initial_plugin) > 2:
                    w = self.findChild(QWidget, initial_plugin[2])
                    if w is not None:
                        for c in self.showing_widget.children():
                            if isinstance(c, QTabWidget):
                                idx = c.indexOf(w)
                                if idx > -1:
                                    c.setCurrentIndex(idx)
                                    break
        else:
            self.hide_plugin()
Пример #22
0
    def __init__(self, type_, title, msg, opts,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None, default_yes=True):
        QDialog.__init__(self, parent)

        if q_icon is None:
            icon = {
                    self.ERROR: 'error',
                    self.WARNING: 'warning',
                    self.INFO:    'information',
                    self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png' % icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon
        self.setupUi(self)

        self.setWindowTitle(title)
        self.setWindowIcon(opts.icon)
        #self.icon_label.setPixmap(self.icon.pixmap(self.COVER_SIZE, self.COVER_SIZE))
        self.icon_label.setPixmap(self.icon.pixmap(COVER_ICON_SIZE))
        self.msg.setText(msg)
        self.msg.setOpenExternalLinks(True)

        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                    self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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'))

        self.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes | self.bb.No)
            self.bb.button(self.bb.Yes if default_yes else self.bb.No
                    ).setDefault(True)
            self.default_yes = default_yes
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.do_resize()
Пример #23
0
    def __init__(self, parent=None):
        QTextEdit.__init__(self, parent)
        self.setTabChangesFocus(True)
        self.document().setDefaultStyleSheet(css())
        font = self.font()
        f = QFontInfo(font)
        delta = tweaks['change_book_details_font_size_by'] + 1
        if delta:
            font.setPixelSize(f.pixelSize() + delta)
            self.setFont(font)
        f = QFontMetrics(self.font())
        self.em_size = f.horizontalAdvance('m')
        self.base_url = None
        self._parent = weakref.ref(parent)
        self.comments_pat = re.compile(r'<!--.*?-->', re.DOTALL)

        extra_shortcuts = {
            'bold': 'Bold',
            'italic': 'Italic',
            'underline': 'Underline',
        }

        for rec in (
            ('bold', 'format-text-bold', _('Bold'), True),
            ('italic', 'format-text-italic', _('Italic'), True),
            ('underline', 'format-text-underline', _('Underline'), True),
            ('strikethrough', 'format-text-strikethrough', _('Strikethrough'),
             True),
            ('superscript', 'format-text-superscript', _('Superscript'), True),
            ('subscript', 'format-text-subscript', _('Subscript'), True),
            ('ordered_list', 'format-list-ordered', _('Ordered list'), True),
            ('unordered_list', 'format-list-unordered', _('Unordered list'),
             True),
            ('align_left', 'format-justify-left', _('Align left'), True),
            ('align_center', 'format-justify-center', _('Align center'), True),
            ('align_right', 'format-justify-right', _('Align right'), True),
            ('align_justified', 'format-justify-fill', _('Align justified'),
             True),
            (
                'undo',
                'edit-undo',
                _('Undo'),
            ),
            (
                'redo',
                'edit-redo',
                _('Redo'),
            ),
            (
                'remove_format',
                'edit-clear',
                _('Remove formatting'),
            ),
            (
                'copy',
                'edit-copy',
                _('Copy'),
            ),
            (
                'paste',
                'edit-paste',
                _('Paste'),
            ),
            (
                'paste_and_match_style',
                'edit-paste',
                _('Paste and match style'),
            ),
            (
                'cut',
                'edit-cut',
                _('Cut'),
            ),
            (
                'indent',
                'format-indent-more',
                _('Increase indentation'),
            ),
            (
                'outdent',
                'format-indent-less',
                _('Decrease indentation'),
            ),
            (
                'select_all',
                'edit-select-all',
                _('Select all'),
            ),
            ('color', 'format-text-color', _('Foreground color')),
            ('background', 'format-fill-color', _('Background color')),
            (
                'insert_link',
                'insert-link',
                _('Insert link or image'),
            ),
            (
                'insert_hr',
                'format-text-hr',
                _('Insert separator'),
            ),
            ('clear', 'trash', _('Clear')),
        ):
            name, icon, text = rec[:3]
            checkable = len(rec) == 4
            ac = QAction(QIcon(I(icon + '.png')), text, self)
            if checkable:
                ac.setCheckable(checkable)
            setattr(self, 'action_' + name, ac)
            ss = extra_shortcuts.get(name)
            if ss is not None:
                ac.setShortcut(QKeySequence(getattr(QKeySequence, ss)))
            ac.triggered.connect(getattr(self, 'do_' + name))

        self.action_block_style = QAction(QIcon(I('format-text-heading.png')),
                                          _('Style text block'), self)
        self.action_block_style.setToolTip(_('Style the selected text block'))
        self.block_style_menu = QMenu(self)
        self.action_block_style.setMenu(self.block_style_menu)
        self.block_style_actions = []
        h = _('Heading {0}')
        for text, name in (
            (_('Normal'), 'p'),
            (h.format(1), 'h1'),
            (h.format(2), 'h2'),
            (h.format(3), 'h3'),
            (h.format(4), 'h4'),
            (h.format(5), 'h5'),
            (h.format(6), 'h6'),
            (_('Blockquote'), 'blockquote'),
        ):
            ac = QAction(text, self)
            self.block_style_menu.addAction(ac)
            ac.block_name = name
            ac.setCheckable(True)
            self.block_style_actions.append(ac)
            ac.triggered.connect(self.do_format_block)

        self.setHtml('')
        self.copyAvailable.connect(self.update_clipboard_actions)
        self.update_clipboard_actions(False)
        self.selectionChanged.connect(self.update_selection_based_actions)
        self.update_selection_based_actions()
        connect_lambda(self.undoAvailable, self,
                       lambda self, yes: self.action_undo.setEnabled(yes))
        connect_lambda(self.redoAvailable, self,
                       lambda self, yes: self.action_redo.setEnabled(yes))
        self.action_undo.setEnabled(False), self.action_redo.setEnabled(False)
        self.textChanged.connect(self.update_cursor_position_actions)
        self.cursorPositionChanged.connect(self.update_cursor_position_actions)
        self.textChanged.connect(self.data_changed)
        self.update_cursor_position_actions()
Пример #24
0
class MessageBox(QDialog):  # {{{

    ERROR = 0
    WARNING = 1
    INFO = 2
    QUESTION = 3

    resize_needed = pyqtSignal()

    def setup_ui(self):
        self.setObjectName("Dialog")
        self.resize(497, 235)
        self.gridLayout = l = QGridLayout(self)
        l.setObjectName("gridLayout")
        self.icon_label = la = QLabel('')
        la.setMaximumSize(QSize(68, 68))
        la.setScaledContents(True)
        la.setObjectName("icon_label")
        l.addWidget(la)
        self.msg = la = QLabel(self)
        la.setWordWrap(True), la.setMinimumWidth(400)
        la.setOpenExternalLinks(True)
        la.setObjectName("msg")
        l.addWidget(la, 0, 1, 1, 1)
        self.det_msg = dm = QPlainTextEdit(self)
        dm.setReadOnly(True)
        dm.setObjectName("det_msg")
        l.addWidget(dm, 1, 0, 1, 2)
        self.bb = bb = QDialogButtonBox(self)
        bb.setStandardButtons(QDialogButtonBox.Ok)
        bb.setObjectName("bb")
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        l.addWidget(bb, 3, 0, 1, 2)
        self.toggle_checkbox = tc = QCheckBox(self)
        tc.setObjectName("toggle_checkbox")
        l.addWidget(tc, 2, 0, 1, 2)

    def __init__(self,
                 type_,
                 title,
                 msg,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None,
                 default_yes=True,
                 yes_text=None,
                 no_text=None,
                 yes_icon=None,
                 no_icon=None):
        QDialog.__init__(self, parent)
        if q_icon is None:
            icon = {
                self.ERROR: 'error',
                self.WARNING: 'warning',
                self.INFO: 'information',
                self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png' % icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(
                I(q_icon))
        self.setup_ui()

        self.setWindowTitle(title)
        self.setWindowIcon(self.icon)
        self.icon_label.setPixmap(self.icon.pixmap(128, 128))
        self.msg.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                                                self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes | self.bb.No)
            self.bb.button(
                self.bb.Yes if default_yes else self.bb.No).setDefault(True)
            self.default_yes = default_yes
            if yes_text is not None:
                self.bb.button(self.bb.Yes).setText(yes_text)
            if no_text is not None:
                self.bb.button(self.bb.No).setText(no_text)
            if yes_icon is not None:
                self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(
                    yes_icon, QIcon) else QIcon(I(yes_icon)))
            if no_icon is not None:
                self.bb.button(self.bb.No).setIcon(no_icon if isinstance(
                    no_icon, QIcon) else QIcon(I(no_icon)))
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection)
        self.do_resize()

    def sizeHint(self):
        ans = QDialog.sizeHint(self)
        ans.setWidth(
            max(min(ans.width(), 500),
                self.bb.sizeHint().width() + 100))
        ans.setHeight(min(ans.height(), 500))
        return ans

    def toggle_det_msg(self, *args):
        vis = self.det_msg.isVisible()
        self.det_msg.setVisible(not vis)
        self.det_msg_toggle.setText(
            self.show_det_msg if vis else self.hide_det_msg)
        self.resize_needed.emit()

    def do_resize(self):
        self.resize(self.sizeHint())

    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.text()), unicode(self.det_msg.toPlainText())))
        if hasattr(self, 'ctc_button'):
            self.ctc_button.setText(_('Copied'))

    def showEvent(self, ev):
        ret = QDialog.showEvent(self, ev)
        if self.is_question:
            try:
                self.bb.button(
                    self.bb.Yes if self.default_yes else self.bb.No).setFocus(
                        Qt.OtherFocusReason)
            except:
                pass  # Buttons were changed
        else:
            self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason)
        return ret

    def set_details(self, msg):
        if not msg:
            msg = ''
        self.det_msg.setPlainText(msg)
        self.det_msg_toggle.setText(self.show_det_msg)
        self.det_msg_toggle.setVisible(bool(msg))
        self.det_msg.setVisible(False)
        self.resize_needed.emit()
Пример #25
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = gl = QGridLayout(self)
        self.changed = False

        self.bars = b = QComboBox(self)
        b.addItem(_('Choose which toolbar you want to customize'))
        ft = _('Tools for %s editors')
        for name, text in (
            (
                'global_book_toolbar',
                _('Book wide actions'),
            ),
            (
                'global_tools_toolbar',
                _('Book wide tools'),
            ),
            (
                'global_plugins_toolbar',
                _('Book wide tools from third party plugins'),
            ),
            ('editor_common_toolbar', ft % _('all')),
            (
                'editor_html_toolbar',
                ft % 'HTML',
            ),
            (
                'editor_css_toolbar',
                ft % 'CSS',
            ),
            (
                'editor_xml_toolbar',
                ft % 'XML',
            ),
            (
                'editor_format_toolbar',
                _('Text formatting actions'),
            ),
        ):
            b.addItem(text, name)
        self.la = la = QLabel(_('&Toolbar to customize:'))
        la.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        la.setBuddy(b)
        gl.addWidget(la), gl.addWidget(b, 0, 1)
        self.sl = l = QGridLayout()
        gl.addLayout(l, 1, 0, 1, -1)

        self.gb1 = gb1 = QGroupBox(_('A&vailable actions'), self)
        self.gb2 = gb2 = QGroupBox(_('&Current actions'), self)
        gb1.setFlat(True), gb2.setFlat(True)
        gb1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        gb2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        l.addWidget(gb1, 0, 0, -1, 1), l.addWidget(gb2, 0, 2, -1, 1)
        self.available, self.current = ToolbarList(self), ToolbarList(self)
        self.ub = b = QToolButton(self)
        connect_lambda(b.clicked, self, lambda self: self.move(up=True))
        b.setToolTip(_('Move selected action up')), b.setIcon(
            QIcon(I('arrow-up.png')))
        self.db = b = QToolButton(self)
        connect_lambda(b.clicked, self, lambda self: self.move(up=False))
        b.setToolTip(_('Move selected action down')), b.setIcon(
            QIcon(I('arrow-down.png')))
        self.gl1 = gl1 = QVBoxLayout()
        gl1.addWidget(self.available), gb1.setLayout(gl1)
        self.gl2 = gl2 = QGridLayout()
        gl2.addWidget(self.current, 0, 0, -1, 1)
        gl2.addWidget(self.ub, 0, 1), gl2.addWidget(self.db, 2, 1)
        gb2.setLayout(gl2)
        self.lb = b = QToolButton(self)
        b.setToolTip(_('Add selected actions to the toolbar')), b.setIcon(
            QIcon(I('forward.png')))
        l.addWidget(b, 1, 1), b.clicked.connect(self.add_action)
        self.rb = b = QToolButton(self)
        b.setToolTip(_('Remove selected actions from the toolbar')), b.setIcon(
            QIcon(I('back.png')))
        l.addWidget(b, 3, 1), b.clicked.connect(self.remove_action)
        self.si = QSpacerItem(20,
                              10,
                              hPolicy=QSizePolicy.Preferred,
                              vPolicy=QSizePolicy.Expanding)
        l.setRowStretch(0, 10), l.setRowStretch(2, 10), l.setRowStretch(4, 10)
        l.addItem(self.si, 4, 1)

        self.read_settings()
        self.toggle_visibility(False)
        self.bars.currentIndexChanged.connect(self.bar_changed)

        self.toolbar_icon_size = ics = QSpinBox(self)
        ics.setMinimum(16), ics.setMaximum(128), ics.setSuffix(
            ' px'), ics.setValue(tprefs['toolbar_icon_size'])
        ics.setToolTip('<p>' + _('Adjust the size of icons on all toolbars'))
        self.h = h = QHBoxLayout()
        gl.addLayout(h, gl.rowCount(), 0, 1, -1)
        self.toolbar_icon_size_label = la = QLabel(_('Toolbar &icon size:'))
        la.setBuddy(ics)
        h.addWidget(la), h.addWidget(ics), h.addStretch(10)
Пример #26
0
    def __init__(self, gui, row, toggle_shortcut):
        self.is_pane = gprefs.get('quickview_is_pane', False)

        if not self.is_pane:
            QDialog.__init__(self, gui, flags=Qt.Widget)
        else:
            QDialog.__init__(self, gui)
        Ui_Quickview.__init__(self)
        self.setupUi(self)
        self.isClosed = False
        self.current_book = None
        self.closed_by_button = False

        if self.is_pane:
            self.main_grid_layout.setContentsMargins(0, 0, 0, 0)
        else:
            self.setWindowIcon(self.windowIcon())

        self.books_table_column_widths = None
        try:
            self.books_table_column_widths = \
                        gprefs.get('quickview_dialog_books_table_widths', None)
            if not self.is_pane:
                geom = gprefs.get('quickview_dialog_geometry', None)
                if geom:
                    QApplication.instance().safe_restore_geometry(
                        self, QByteArray(geom))
        except:
            pass

        self.view = gui.library_view
        self.db = self.view.model().db
        self.gui = gui
        self.is_closed = False
        self.current_book_id = None  # the db id of the book used to fill the lh pane
        self.current_column = None  # current logical column in books list
        self.current_key = None  # current lookup key in books list
        self.last_search = None
        self.no_valid_items = False
        self.follow_library_view = True

        self.apply_vls.setCheckState(
            Qt.Checked if gprefs['qv_respects_vls'] else Qt.Unchecked)
        self.apply_vls.stateChanged.connect(self.vl_box_changed)

        self.fm = self.db.field_metadata

        self.items.setSelectionMode(QAbstractItemView.SingleSelection)
        self.items.currentTextChanged.connect(self.item_selected)
        self.items.setProperty('highlight_current_item', 150)
        self.items.itemDoubleClicked.connect(self.item_doubleclicked)
        self.items.setContextMenuPolicy(Qt.CustomContextMenu)
        self.items.customContextMenuRequested.connect(
            self.show_item_context_menu)

        focus_filter = WidgetFocusFilter(self.items)
        focus_filter.focus_entered_signal.connect(self.focus_entered)
        self.items.installEventFilter(focus_filter)

        self.tab_pressed_signal.connect(self.tab_pressed)
        return_filter = BooksTableFilter(self.books_table)
        return_filter.return_pressed_signal.connect(self.return_pressed)
        self.books_table.installEventFilter(return_filter)

        focus_filter = WidgetFocusFilter(self.books_table)
        focus_filter.focus_entered_signal.connect(self.focus_entered)
        self.books_table.installEventFilter(focus_filter)

        self.close_button.clicked.connect(self.close_button_clicked)
        self.refresh_button.clicked.connect(self.refill)

        self.tab_order_widgets = [
            self.items, self.books_table, self.lock_qv, self.dock_button,
            self.refresh_button, self.close_button
        ]
        for idx, widget in enumerate(self.tab_order_widgets):
            widget.installEventFilter(
                WidgetTabFilter(widget, idx, self.tab_pressed_signal))

        self.books_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.books_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.books_table.setProperty('highlight_current_item', 150)

        # Set up the books table columns
        self.add_columns_to_widget()

        self.books_table_header_height = self.books_table.height()
        self.books_table.cellDoubleClicked.connect(self.book_doubleclicked)
        self.books_table.currentCellChanged.connect(
            self.books_table_cell_changed)
        self.books_table.cellClicked.connect(
            self.books_table_set_search_string)
        self.books_table.cellActivated.connect(
            self.books_table_set_search_string)
        self.books_table.sortByColumn(0, Qt.AscendingOrder)

        # get the standard table row height. Do this here because calling
        # resizeRowsToContents can word wrap long cell contents, creating
        # double-high rows
        self.books_table.setRowCount(1)
        self.books_table.setItem(0, 0, TableItem('A', ''))
        self.books_table.resizeRowsToContents()
        self.books_table_row_height = self.books_table.rowHeight(0)
        self.books_table.setRowCount(0)

        # Add the data
        self.refresh(row)

        self.view.clicked.connect(self.slave)
        self.view.selectionModel().currentColumnChanged.connect(
            self.column_slave)
        QCoreApplication.instance().aboutToQuit.connect(self.save_state)
        self.view.model().new_bookdisplay_data.connect(self.book_was_changed)

        self.close_button.setDefault(False)
        self.close_button_tooltip = _(
            'The Quickview shortcut ({0}) shows/hides the Quickview panel')
        if self.is_pane:
            self.dock_button.setText(_('Undock'))
            self.dock_button.setToolTip(
                _('Show the Quickview panel in its own floating window'))
            self.dock_button.setIcon(QIcon(I('arrow-up.png')))
            # Remove the ampersands from the buttons because shortcuts exist.
            self.lock_qv.setText(_('Lock Quickview contents'))
            self.refresh_button.setText(_('Refresh'))
            self.gui.quickview_splitter.add_quickview_dialog(self)
            self.close_button.setVisible(False)
        else:
            self.dock_button.setToolTip(
                _('Embed the quickview panel into the main calibre window'))
            self.dock_button.setIcon(QIcon(I('arrow-down.png')))
        self.set_focus()

        self.books_table.horizontalHeader().sectionResized.connect(
            self.section_resized)
        self.dock_button.clicked.connect(self.show_as_pane_changed)
        self.view.model().search_done.connect(self.check_for_no_items)

        # Enable the refresh button only when QV is locked
        self.refresh_button.setEnabled(False)
        self.lock_qv.stateChanged.connect(self.lock_qv_changed)

        self.view_icon = QIcon(I('view.png'))
        self.view_plugin = self.gui.iactions['View']
        self.edit_metadata_icon = QIcon(I('edit_input.png'))
        self.quickview_icon = QIcon(I('quickview.png'))
        self.select_book_icon = QIcon(I('library.png'))
        self.search_icon = QIcon(I('search.png'))
        self.books_table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.books_table.customContextMenuRequested.connect(
            self.show_context_menu)

        # Add the quickview toggle as a shortcut for the close button
        # Don't add it if it identical to the current &X shortcut because that
        # breaks &X
        if (not self.is_pane and toggle_shortcut
                and self.close_button.shortcut() != toggle_shortcut):
            toggle_sc = QShortcut(toggle_shortcut, self.close_button)
            toggle_sc.activated.connect(lambda: self.close_button_clicked())
            toggle_sc.setEnabled(True)
            self.close_button.setToolTip(
                _('Alternate shortcut: ') + toggle_shortcut.toString())
Пример #27
0
    def __init__(self, parent=None):
        QAbstractItemModel.__init__(self, parent)
        self.categories = (
            (_('Favorites'), ()),  # {{{
            (_('European scripts'), (
                (_('Armenian'), (0x530, 0x58F)),
                (_('Armenian ligatures'), (0xFB13, 0xFB17)),
                (_('Coptic'), (0x2C80, 0x2CFF)),
                (_('Coptic in Greek block'), (0x3E2, 0x3EF)),
                (_('Cypriot syllabary'), (0x10800, 0x1083F)),
                (_('Cyrillic'), (0x400, 0x4FF)),
                (_('Cyrillic supplement'), (0x500, 0x52F)),
                (_('Cyrillic extended A'), (0x2DE0, 0x2DFF)),
                (_('Cyrillic extended B'), (0xA640, 0xA69F)),
                (_('Georgian'), (0x10A0, 0x10FF)),
                (_('Georgian supplement'), (0x2D00, 0x2D2F)),
                (_('Glagolitic'), (0x2C00, 0x2C5F)),
                (_('Gothic'), (0x10330, 0x1034F)),
                (_('Greek and Coptic'), (0x370, 0x3FF)),
                (_('Greek extended'), (0x1F00, 0x1FFF)),
                (_('Latin, Basic & Latin-1 supplement'), (0x20, 0xFF)),
                (_('Latin extended A'), (0x100, 0x17F)),
                (_('Latin extended B'), (0x180, 0x24F)),
                (_('Latin extended C'), (0x2C60, 0x2C7F)),
                (_('Latin extended D'), (0xA720, 0xA7FF)),
                (_('Latin extended additional'), (0x1E00, 0x1EFF)),
                (_('Latin ligatures'), (0xFB00, 0xFB06)),
                (_('Fullwidth Latin letters'), (0xFF00, 0xFF5E)),
                (_('Linear B syllabary'), (0x10000, 0x1007F)),
                (_('Linear B ideograms'), (0x10080, 0x100FF)),
                (_('Ogham'), (0x1680, 0x169F)),
                (_('Old italic'), (0x10300, 0x1032F)),
                (_('Phaistos disc'), (0x101D0, 0x101FF)),
                (_('Runic'), (0x16A0, 0x16FF)),
                (_('Shavian'), (0x10450, 0x1047F)),
            )),
            (_('Phonetic symbols'), (
                (_('IPA extensions'), (0x250, 0x2AF)),
                (_('Phonetic extensions'), (0x1D00, 0x1D7F)),
                (_('Phonetic extensions supplement'), (0x1D80, 0x1DBF)),
                (_('Modifier tone letters'), (0xA700, 0xA71F)),
                (_('Spacing modifier letters'), (0x2B0, 0x2FF)),
                (_('Superscripts and subscripts'), (0x2070, 0x209F)),
            )),
            (_('Combining diacritics'), (
                (_('Combining diacritical marks'), (0x300, 0x36F)),
                (_('Combining diacritical marks for symbols'), (0x20D0,
                                                                0x20FF)),
                (_('Combining diacritical marks supplement'), (0x1DC0,
                                                               0x1DFF)),
                (_('Combining half marks'), (0xFE20, 0xFE2F)),
            )),
            (_('African scripts'), (
                (_('Bamum'), (0xA6A0, 0xA6FF)),
                (_('Bamum supplement'), (0x16800, 0x16A3F)),
                (_('Egyptian hieroglyphs'), (0x13000, 0x1342F)),
                (_('Ethiopic'), (0x1200, 0x137F)),
                (_('Ethiopic supplement'), (0x1380, 0x139F)),
                (_('Ethiopic extended'), (0x2D80, 0x2DDF)),
                (_('Ethiopic extended A'), (0xAB00, 0xAB2F)),
                (_('Meroitic cursive'), (0x109A0, 0x109FF)),
                (_('Meroitic hieroglyphs'), (0x10980, 0x1099F)),
                (_('N\'Ko'), (0x7C0, 0x7FF)),
                (_('Osmanya'), (0x10480, 0x104AF)),
                (_('Tifinagh'), (0x2D30, 0x2D7F)),
                (_('Vai'), (0xA500, 0xA63F)),
            )),
            (_('Middle Eastern scripts'), (
                (_('Arabic'), (0x600, 0x6FF)),
                (_('Arabic supplement'), (0x750, 0x77F)),
                (_('Arabic extended A'), (0x8A0, 0x8FF)),
                (_('Arabic presentation forms A'), (0xFB50, 0xFDFF)),
                (_('Arabic presentation forms B'), (0xFE70, 0xFEFF)),
                (_('Avestan'), (0x10B00, 0x10B3F)),
                (_('Carian'), (0x102A0, 0x102DF)),
                (_('Cuneiform'), (0x12000, 0x123FF)),
                (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)),
                (_('Hebrew'), (0x590, 0x5FF)),
                (_('Hebrew presentation forms'), (0xFB1D, 0xFB4F)),
                (_('Imperial Aramaic'), (0x10840, 0x1085F)),
                (_('Inscriptional Pahlavi'), (0x10B60, 0x10B7F)),
                (_('Inscriptional Parthian'), (0x10B40, 0x10B5F)),
                (_('Lycian'), (0x10280, 0x1029F)),
                (_('Lydian'), (0x10920, 0x1093F)),
                (_('Mandaic'), (0x840, 0x85F)),
                (_('Old Persian'), (0x103A0, 0x103DF)),
                (_('Old South Arabian'), (0x10A60, 0x10A7F)),
                (_('Phoenician'), (0x10900, 0x1091F)),
                (_('Samaritan'), (0x800, 0x83F)),
                (_('Syriac'), (0x700, 0x74F)),
                (_('Ugaritic'), (0x10380, 0x1039F)),
            )),
            (_('Central Asian scripts'), (
                (_('Mongolian'), (0x1800, 0x18AF)),
                (_('Old Turkic'), (0x10C00, 0x10C4F)),
                (_('Phags-pa'), (0xA840, 0xA87F)),
                (_('Tibetan'), (0xF00, 0xFFF)),
            )),
            (_('South Asian scripts'), (
                (_('Bengali'), (0x980, 0x9FF)),
                (_('Brahmi'), (0x11000, 0x1107F)),
                (_('Chakma'), (0x11100, 0x1114F)),
                (_('Devanagari'), (0x900, 0x97F)),
                (_('Devanagari extended'), (0xA8E0, 0xA8FF)),
                (_('Gujarati'), (0xA80, 0xAFF)),
                (_('Gurmukhi'), (0xA00, 0xA7F)),
                (_('Kaithi'), (0x11080, 0x110CF)),
                (_('Kannada'), (0xC80, 0xCFF)),
                (_('Kharoshthi'), (0x10A00, 0x10A5F)),
                (_('Lepcha'), (0x1C00, 0x1C4F)),
                (_('Limbu'), (0x1900, 0x194F)),
                (_('Malayalam'), (0xD00, 0xD7F)),
                (_('Meetei Mayek'), (0xABC0, 0xABFF)),
                (_('Meetei Mayek extensions'), (0xAAE0, 0xAAEF)),
                (_('Ol Chiki'), (0x1C50, 0x1C7F)),
                (_('Oriya'), (0xB00, 0xB7F)),
                (_('Saurashtra'), (0xA880, 0xA8DF)),
                (_('Sinhala'), (0xD80, 0xDFF)),
                (_('Sharada'), (0x11180, 0x111DF)),
                (_('Sora Sompeng'), (0x110D0, 0x110FF)),
                (_('Syloti Nagri'), (0xA800, 0xA82F)),
                (_('Takri'), (0x11680, 0x116CF)),
                (_('Tamil'), (0xB80, 0xBFF)),
                (_('Telugu'), (0xC00, 0xC7F)),
                (_('Thaana'), (0x780, 0x7BF)),
                (_('Vedic extensions'), (0x1CD0, 0x1CFF)),
            )),
            (_('Southeast Asian scripts'), (
                (_('Balinese'), (0x1B00, 0x1B7F)),
                (_('Batak'), (0x1BC0, 0x1BFF)),
                (_('Buginese'), (0x1A00, 0x1A1F)),
                (_('Cham'), (0xAA00, 0xAA5F)),
                (_('Javanese'), (0xA980, 0xA9DF)),
                (_('Kayah Li'), (0xA900, 0xA92F)),
                (_('Khmer'), (0x1780, 0x17FF)),
                (_('Khmer symbols'), (0x19E0, 0x19FF)),
                (_('Lao'), (0xE80, 0xEFF)),
                (_('Myanmar'), (0x1000, 0x109F)),
                (_('Myanmar extended A'), (0xAA60, 0xAA7F)),
                (_('New Tai Lue'), (0x1980, 0x19DF)),
                (_('Rejang'), (0xA930, 0xA95F)),
                (_('Sundanese'), (0x1B80, 0x1BBF)),
                (_('Sundanese supplement'), (0x1CC0, 0x1CCF)),
                (_('Tai Le'), (0x1950, 0x197F)),
                (_('Tai Tham'), (0x1A20, 0x1AAF)),
                (_('Tai Viet'), (0xAA80, 0xAADF)),
                (_('Thai'), (0xE00, 0xE7F)),
            )),
            (_('Philippine scripts'), (
                (_('Buhid'), (0x1740, 0x175F)),
                (_('Hanunoo'), (0x1720, 0x173F)),
                (_('Tagalog'), (0x1700, 0x171F)),
                (_('Tagbanwa'), (0x1760, 0x177F)),
            )),
            (_('East Asian scripts'), (
                (_('Bopomofo'), (0x3100, 0x312F)),
                (_('Bopomofo extended'), (0x31A0, 0x31BF)),
                (_('CJK Unified ideographs'), (0x4E00, 0x9FFF)),
                (_('CJK Unified ideographs extension A'), (0x3400, 0x4DBF)),
                (_('CJK Unified ideographs extension B'), (0x20000, 0x2A6DF)),
                (_('CJK Unified ideographs extension C'), (0x2A700, 0x2B73F)),
                (_('CJK Unified ideographs extension D'), (0x2B740, 0x2B81F)),
                (_('CJK compatibility ideographs'), (0xF900, 0xFAFF)),
                (_('CJK compatibility ideographs supplement'), (0x2F800,
                                                                0x2FA1F)),
                (_('Kangxi radicals'), (0x2F00, 0x2FDF)),
                (_('CJK radicals supplement'), (0x2E80, 0x2EFF)),
                (_('CJK strokes'), (0x31C0, 0x31EF)),
                (_('Ideographic description characters'), (0x2FF0, 0x2FFF)),
                (_('Hiragana'), (0x3040, 0x309F)),
                (_('Katakana'), (0x30A0, 0x30FF)),
                (_('Katakana phonetic extensions'), (0x31F0, 0x31FF)),
                (_('Kana supplement'), (0x1B000, 0x1B0FF)),
                (_('Halfwidth Katakana'), (0xFF65, 0xFF9F)),
                (_('Kanbun'), (0x3190, 0x319F)),
                (_('Hangul syllables'), (0xAC00, 0xD7AF)),
                (_('Hangul Jamo'), (0x1100, 0x11FF)),
                (_('Hangul Jamo extended A'), (0xA960, 0xA97F)),
                (_('Hangul Jamo extended B'), (0xD7B0, 0xD7FF)),
                (_('Hangul compatibility Jamo'), (0x3130, 0x318F)),
                (_('Halfwidth Jamo'), (0xFFA0, 0xFFDC)),
                (_('Lisu'), (0xA4D0, 0xA4FF)),
                (_('Miao'), (0x16F00, 0x16F9F)),
                (_('Yi syllables'), (0xA000, 0xA48F)),
                (_('Yi radicals'), (0xA490, 0xA4CF)),
            )),
            (_('American scripts'), (
                (_('Cherokee'), (0x13A0, 0x13FF)),
                (_('Deseret'), (0x10400, 0x1044F)),
                (_('Unified Canadian aboriginal syllabics'), (0x1400, 0x167F)),
                (_('UCAS extended'), (0x18B0, 0x18FF)),
            )),
            (_('Other'), (
                (_('Alphabetic presentation forms'), (0xFB00, 0xFB4F)),
                (_('Halfwidth and Fullwidth forms'), (0xFF00, 0xFFEF)),
            )),
            (_('Punctuation'), (
                (_('General punctuation'), (0x2000, 0x206F)),
                (_('ASCII punctuation'), (0x21, 0x7F)),
                (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)),
                (_('Latin-1 punctuation'), (0xA1, 0xBF)),
                (_('Small form variants'), (0xFE50, 0xFE6F)),
                (_('Supplemental punctuation'), (0x2E00, 0x2E7F)),
                (_('CJK symbols and punctuation'), (0x3000, 0x303F)),
                (_('CJK compatibility forms'), (0xFE30, 0xFE4F)),
                (_('Fullwidth ASCII punctuation'), (0xFF01, 0xFF60)),
                (_('Vertical forms'), (0xFE10, 0xFE1F)),
            )),
            (_('Alphanumeric symbols'), (
                (_('Arabic mathematical alphabetic symbols'), (0x1EE00,
                                                               0x1EEFF)),
                (_('Letterlike symbols'), (0x2100, 0x214F)),
                (_('Roman symbols'), (0x10190, 0x101CF)),
                (_('Mathematical alphanumeric symbols'), (0x1D400, 0x1D7FF)),
                (_('Enclosed alphanumerics'), (0x2460, 0x24FF)),
                (_('Enclosed alphanumeric supplement'), (0x1F100, 0x1F1FF)),
                (_('Enclosed CJK letters and months'), (0x3200, 0x32FF)),
                (_('Enclosed ideographic supplement'), (0x1F200, 0x1F2FF)),
                (_('CJK compatibility'), (0x3300, 0x33FF)),
            )),
            (_('Technical symbols'), (
                (_('Miscellaneous technical'), (0x2300, 0x23FF)),
                (_('Control pictures'), (0x2400, 0x243F)),
                (_('Optical character recognition'), (0x2440, 0x245F)),
            )),
            (_('Numbers and digits'), (
                (_('Aegean numbers'), (0x10100, 0x1013F)),
                (_('Ancient Greek numbers'), (0x10140, 0x1018F)),
                (_('Common Indic number forms'), (0xA830, 0xA83F)),
                (_('Counting rod numerals'), (0x1D360, 0x1D37F)),
                (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)),
                (_('Fullwidth ASCII digits'), (0xFF10, 0xFF19)),
                (_('Number forms'), (0x2150, 0x218F)),
                (_('Rumi numeral symbols'), (0x10E60, 0x10E7F)),
                (_('Superscripts and subscripts'), (0x2070, 0x209F)),
            )),
            (_('Mathematical symbols'), (
                (_('Arrows'), (0x2190, 0x21FF)),
                (_('Supplemental arrows A'), (0x27F0, 0x27FF)),
                (_('Supplemental arrows B'), (0x2900, 0x297F)),
                (_('Miscellaneous symbols and arrows'), (0x2B00, 0x2BFF)),
                (_('Mathematical alphanumeric symbols'), (0x1D400, 0x1D7FF)),
                (_('Letterlike symbols'), (0x2100, 0x214F)),
                (_('Mathematical operators'), (0x2200, 0x22FF)),
                (_('Miscellaneous mathematical symbols A'), (0x27C0, 0x27EF)),
                (_('Miscellaneous mathematical symbols B'), (0x2980, 0x29FF)),
                (_('Supplemental mathematical operators'), (0x2A00, 0x2AFF)),
                (_('Ceilings and floors'), (0x2308, 0x230B)),
                (_('Geometric shapes'), (0x25A0, 0x25FF)),
                (_('Box drawing'), (0x2500, 0x257F)),
                (_('Block elements'), (0x2580, 0x259F)),
            )),
            (_('Musical symbols'), (
                (_('Musical symbols'), (0x1D100, 0x1D1FF)),
                (_('More musical symbols'), (0x2669, 0x266F)),
                (_('Ancient Greek musical notation'), (0x1D200, 0x1D24F)),
                (_('Byzantine musical symbols'), (0x1D000, 0x1D0FF)),
            )),
            (_('Game symbols'), (
                (_('Chess'), (0x2654, 0x265F)),
                (_('Domino tiles'), (0x1F030, 0x1F09F)),
                (_('Draughts'), (0x26C0, 0x26C3)),
                (_('Japanese chess'), (0x2616, 0x2617)),
                (_('Mahjong tiles'), (0x1F000, 0x1F02F)),
                (_('Playing cards'), (0x1F0A0, 0x1F0FF)),
                (_('Playing card suits'), (0x2660, 0x2667)),
            )),
            (_('Other symbols'), (
                (_('Alchemical symbols'), (0x1F700, 0x1F77F)),
                (_('Ancient symbols'), (0x10190, 0x101CF)),
                (_('Braille patterns'), (0x2800, 0x28FF)),
                (_('Currency symbols'), (0x20A0, 0x20CF)),
                (_('Combining diacritical marks for symbols'), (0x20D0,
                                                                0x20FF)),
                (_('Dingbats'), (0x2700, 0x27BF)),
                (_('Emoticons'), (0x1F600, 0x1F64F)),
                (_('Miscellaneous symbols'), (0x2600, 0x26FF)),
                (_('Miscellaneous symbols and arrows'), (0x2B00, 0x2BFF)),
                (_('Miscellaneous symbols and pictographs'), (0x1F300,
                                                              0x1F5FF)),
                (_('Yijing hexagram symbols'), (0x4DC0, 0x4DFF)),
                (_('Yijing mono and digrams'), (0x268A, 0x268F)),
                (_('Yijing trigrams'), (0x2630, 0x2637)),
                (_('Tai Xuan Jing symbols'), (0x1D300, 0x1D35F)),
                (_('Transport and map symbols'), (0x1F680, 0x1F6FF)),
            )),
            (_('Other'), (
                (_('Specials'), (0xFFF0, 0xFFFF)),
                (_('Tags'), (0xE0000, 0xE007F)),
                (_('Variation selectors'), (0xFE00, 0xFE0F)),
                (_('Variation selectors supplement'), (0xE0100, 0xE01EF)),
            )),
        )  # }}}

        self.category_map = {}
        self.starts = []
        for tlname, items in self.categories[1:]:
            for name, (start, end) in items:
                self.category_map[start] = (tlname, name)
                self.starts.append(start)
        self.starts.sort()
        self.bold_font = f = QApplication.font()
        f.setBold(True)
        self.fav_icon = QIcon(I('rating.png'))
Пример #28
0
    def setup_ui(self):
        self.l = l = QGridLayout(self)
        self.setLayout(l)

        self.bb.setStandardButtons(self.bb.Close)
        self.rearrange_button = b = self.bb.addButton(
            _('Re-arrange favorites'), self.bb.ActionRole)
        b.setCheckable(True)
        b.setChecked(False)
        b.setVisible(False)
        b.setDefault(True)

        self.splitter = s = QSplitter(self)
        s.setFocusPolicy(Qt.NoFocus)
        s.setChildrenCollapsible(False)

        self.search = h = HistoryLineEdit2(self)
        h.setToolTip(
            textwrap.fill(
                _('Search for Unicode characters by using the English names or nicknames.'
                  ' You can also search directly using a character code. For example, the following'
                  ' searches will all yield the no-break space character: U+A0, nbsp, no-break'
                  )))
        h.initialize('charmap_search')
        h.setPlaceholderText(_('Search by name, nickname or character code'))
        self.search_button = b = QPushButton(_('&Search'))
        b.setFocusPolicy(Qt.NoFocus)
        h.returnPressed.connect(self.do_search)
        b.clicked.connect(self.do_search)
        self.clear_button = cb = QToolButton(self)
        cb.setIcon(QIcon(I('clear_left.png')))
        cb.setFocusPolicy(Qt.NoFocus)
        cb.setText(_('Clear search'))
        cb.clicked.connect(self.clear_search)
        l.addWidget(h), l.addWidget(b, 0, 1), l.addWidget(cb, 0, 2)

        self.category_view = CategoryView(self)
        self.category_view.setFocusPolicy(Qt.NoFocus)
        l.addWidget(s, 1, 0, 1, 3)
        self.char_view = CharView(self)
        self.char_view.setFocusPolicy(Qt.NoFocus)
        self.rearrange_button.toggled[bool].connect(
            self.set_allow_drag_and_drop)
        self.category_view.category_selected.connect(self.show_chars)
        self.char_view.show_name.connect(self.show_char_info)
        self.char_view.char_selected.connect(self.char_selected)
        s.addWidget(self.category_view), s.addWidget(self.char_view)

        self.char_info = la = QLabel('\xa0')
        la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        l.addWidget(la, 2, 0, 1, 3)

        self.rearrange_msg = la = QLabel(
            _('Drag and drop characters to re-arrange them. Click the "Re-arrange" button again when you are done.'
              ))
        la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        la.setVisible(False)
        l.addWidget(la, 3, 0, 1, 3)
        self.h = h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        self.match_any = mm = QCheckBox(_('Match any word'))
        mm.setToolTip(
            _('When searching return characters whose names match any of the specified words'
              ))
        mm.setChecked(tprefs.get('char_select_match_any', True))
        connect_lambda(
            mm.stateChanged, self, lambda self: tprefs.set(
                'char_select_match_any', self.match_any.isChecked()))
        h.addWidget(mm), h.addStretch(), h.addWidget(self.bb)
        l.addLayout(h, 4, 0, 1, 3)
        self.char_view.setFocus(Qt.OtherFocusReason)
Пример #29
0
 def __init__(self, parent=None):
     self.initialized = False
     Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent)
     self.setWindowIcon(QIcon(I('character-set.png')))
     self.setFocusProxy(parent)
Пример #30
0
    def genesis(self, gui):
        self.gui = gui
        db = gui.library_view.model().db

        r = self.register

        try:
            self.icon_theme_title = json.loads(I('icon-theme.json',
                                                 data=True))['name']
        except Exception:
            self.icon_theme_title = _('Default icons')
        self.icon_theme.setText(
            _('Icon theme: <b>%s</b>') % self.icon_theme_title)
        self.commit_icon_theme = None
        self.icon_theme_button.clicked.connect(self.choose_icon_theme)
        r('gui_layout',
          config,
          restart_required=True,
          choices=[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')])
        r('ui_style',
          gprefs,
          restart_required=True,
          choices=[(_('System default'), 'system'),
                   (_('Calibre style'), 'calibre')])
        r('book_list_tooltips', gprefs)
        r('tag_browser_old_look', gprefs, restart_required=True)
        r('tag_browser_hide_empty_categories', gprefs)
        r('bd_show_cover', gprefs)
        r('bd_overlay_cover_size', gprefs)
        r('cover_grid_width', gprefs)
        r('cover_grid_height', gprefs)
        r('cover_grid_cache_size_multiple', gprefs)
        r('cover_grid_disk_cache_size', gprefs)
        r('cover_grid_spacing', gprefs)
        r('cover_grid_show_title', gprefs)

        r('cover_flow_queue_length', config, restart_required=True)
        r('cover_browser_reflections', gprefs)
        r('show_rating_in_cover_browser', gprefs)
        r('cover_browser_title_template', db.prefs)
        r('emblem_size', gprefs)
        r('emblem_position',
          gprefs,
          choices=[(_('Left'), 'left'), (_('Top'), 'top'),
                   (_('Right'), 'right'), (_('Bottom'), 'bottom')])
        r('book_list_extra_row_spacing', gprefs)
        self.cover_browser_title_template_button.clicked.connect(
            self.edit_cb_title_template)
        self.id_links_button.clicked.connect(self.edit_id_link_rules)

        def get_esc_lang(l):
            if l == 'en':
                return 'English'
            return get_language(l)

        lang = get_lang()
        if lang is None or lang not in available_translations():
            lang = 'en'
        items = [(l, get_esc_lang(l)) for l in available_translations()
                 if l != lang]
        if lang != 'en':
            items.append(('en', get_esc_lang('en')))
        items.sort(cmp=lambda x, y: cmp(x[1].lower(), y[1].lower()))
        choices = [(y, x) for x, y in items]
        # Default language is the autodetected one
        choices = [(get_language(lang), lang)] + choices
        r('language', prefs, choices=choices, restart_required=True)

        r('show_avg_rating', config)
        r('disable_animations', config)
        r('systray_icon', config, restart_required=True)
        r('show_splash_screen', gprefs)
        r('disable_tray_notification', config)
        r('use_roman_numerals_for_series_number', config)
        r('separate_cover_flow', config, restart_required=True)
        r('cb_fullscreen', gprefs)
        r('cb_preserve_aspect_ratio', gprefs)

        choices = [(_('Off'), 'off'), (_('Small'), 'small'),
                   (_('Medium'), 'medium'), (_('Large'), 'large')]
        r('toolbar_icon_size', gprefs, choices=choices)

        choices = [(_('If there is enough room'), 'auto'),
                   (_('Always'), 'always'), (_('Never'), 'never')]
        r('toolbar_text', gprefs, choices=choices)

        choices = [(_('Disabled'), 'disable'),
                   (_('By first letter'), 'first letter'),
                   (_('Partitioned'), 'partition')]
        r('tags_browser_partition_method', gprefs, choices=choices)
        r('tags_browser_collapse_at', gprefs)
        r('default_author_link', gprefs)
        r('tag_browser_dont_collapse', gprefs, setting=CommaSeparatedList)

        self.search_library_for_author_button.clicked.connect(
            lambda: self.opt_default_author_link.setText('search-calibre'))

        choices = set([
            k for k in db.field_metadata.all_field_keys()
            if (db.field_metadata[k]['is_category'] and
                (db.field_metadata[k]['datatype'] in
                 ['text', 'series', 'enumeration'])
                and not db.field_metadata[k]['display'].get('is_names', False))
            or (db.field_metadata[k]['datatype'] in ['composite'] and
                db.field_metadata[k]['display'].get('make_category', False))
        ])
        choices -= set(
            ['authors', 'publisher', 'formats', 'news', 'identifiers'])
        choices |= set(['search'])
        self.opt_categories_using_hierarchy.update_items_cache(choices)
        r('categories_using_hierarchy',
          db.prefs,
          setting=CommaSeparatedList,
          choices=sorted(list(choices), key=sort_key))

        fm = db.field_metadata
        choices = sorted(
            ((fm[k]['name'], k)
             for k in fm.displayable_field_keys() if fm[k]['name']),
            key=lambda x: sort_key(x[0]))
        r('field_under_covers_in_grid', db.prefs, choices=choices)

        self.current_font = self.initial_font = None
        self.change_font_button.clicked.connect(self.change_font)

        self.display_model = DisplayedFields(self.gui.current_db,
                                             self.field_display_order)
        self.display_model.dataChanged.connect(self.changed_signal)
        self.field_display_order.setModel(self.display_model)
        self.df_up_button.clicked.connect(self.move_df_up)
        self.df_down_button.clicked.connect(self.move_df_down)

        self.edit_rules = EditRules(self.tabWidget)
        self.edit_rules.changed.connect(self.changed_signal)
        self.tabWidget.addTab(self.edit_rules,
                              QIcon(I('format-fill-color.png')),
                              _('Column coloring'))

        self.icon_rules = EditRules(self.tabWidget)
        self.icon_rules.changed.connect(self.changed_signal)
        self.tabWidget.addTab(self.icon_rules, QIcon(I('icon_choose.png')),
                              _('Column icons'))

        self.grid_rules = EditRules(self.emblems_tab)
        self.grid_rules.changed.connect(self.changed_signal)
        self.emblems_tab.setLayout(QVBoxLayout())
        self.emblems_tab.layout().addWidget(self.grid_rules)

        self.tabWidget.setCurrentIndex(0)
        keys = [
            QKeySequence('F11', QKeySequence.PortableText),
            QKeySequence('Ctrl+Shift+F', QKeySequence.PortableText)
        ]
        keys = [unicode(x.toString(QKeySequence.NativeText)) for x in keys]
        self.fs_help_msg.setText(
            unicode(self.fs_help_msg.text()) % (_(' or ').join(keys)))
        self.size_calculated.connect(self.update_cg_cache_size,
                                     type=Qt.QueuedConnection)
        self.tabWidget.currentChanged.connect(self.tab_changed)

        l = self.cg_background_box.layout()
        self.cg_bg_widget = w = Background(self)
        l.addWidget(w, 0, 0, 3, 1)
        self.cover_grid_color_button = b = QPushButton(_('Change &color'),
                                                       self)
        b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(b, 0, 1)
        b.clicked.connect(self.change_cover_grid_color)
        self.cover_grid_texture_button = b = QPushButton(
            _('Change &background image'), self)
        b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(b, 1, 1)
        b.clicked.connect(self.change_cover_grid_texture)
        self.cover_grid_default_appearance_button = b = QPushButton(
            _('Restore &default appearance'), self)
        b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(b, 2, 1)
        b.clicked.connect(self.restore_cover_grid_appearance)
        self.cover_grid_empty_cache.clicked.connect(self.empty_cache)
        self.cover_grid_open_cache.clicked.connect(self.open_cg_cache)
        self.cover_grid_smaller_cover.clicked.connect(
            partial(self.resize_cover, True))
        self.cover_grid_larger_cover.clicked.connect(
            partial(self.resize_cover, False))
        self.cover_grid_reset_size.clicked.connect(self.cg_reset_size)
        self.opt_cover_grid_disk_cache_size.setMinimum(
            self.gui.grid_view.thumbnail_cache.min_disk_cache)
        self.opt_cover_grid_disk_cache_size.setMaximum(
            self.gui.grid_view.thumbnail_cache.min_disk_cache * 100)
        self.opt_cover_grid_width.valueChanged.connect(
            self.update_aspect_ratio)
        self.opt_cover_grid_height.valueChanged.connect(
            self.update_aspect_ratio)
Пример #31
0
    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 = Cover(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.open_with_requested.connect(self.open_with)
        self.cover.choose_open_with_requested.connect(self.choose_open_with)
        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.path_to_book = None
        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:
                QApplication.instance().safe_restore_geometry(
                    self, saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
        from calibre.gui2.ui import get_gui
        ema = get_gui().iactions['Edit Metadata'].menuless_qaction
        a = self.ema = QAction('edit metadata', self)
        a.setShortcut(ema.shortcut())
        self.addAction(a)
        a.triggered.connect(self.edit_metadata)
Пример #32
0
    def _initUi(self):

        app = Application.instance()

        icon = QIcon(app.findResource('Subtitles.png'))

        iconLabel = QLabel()
        iconLabel.setPixmap(icon.pixmap(128))
        iconLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

        appNameLabel = QLabel(self)
        appNameLabel.setText(app.applicationName())
        appNameLabel.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
        appNameLabel.setStyleSheet('font-weight: bold; font-size: 18pt')
        appNameLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)

        version_labels = self._createVersionLabels()

        licenseLabel = self._createSelectableLabel(
            'Copyright © 2018–2019 Philip Belemezov<br>'
            'Licensed under the <a href="about:blank">'
            'GNU General Public License, version 3</a>.')
        licenseLabel.setStyleSheet('color: gray; font-size: 8pt')
        licenseLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        licenseLabel.setTextFormat(Qt.RichText)
        licenseLabel.setTextInteractionFlags(Qt.TextBrowserInteraction)
        licenseLabel.linkActivated.connect(self.showLicense)

        homepageLabel = self._createLinkLabel(
            text=self.tr("Homepage"),
            href="https://github.io/philipbel/subtitles")
        homepageLabel.setAlignment(Qt.AlignCenter)

        ackLabel = self._createLinkLabel(text=self.tr("Acknowledgements"))
        ackLabel.setAlignment(Qt.AlignCenter)
        ackLabel.linkActivated.connect(self.showAcknowledgements)

        linksLayout = QVBoxLayout()
        linksLayout.addWidget(homepageLabel)
        linksLayout.addSpacing(5)
        linksLayout.addWidget(ackLabel)

        versionInfoLayout = QFormLayout()
        versionInfoLayout.setFormAlignment(Qt.AlignHCenter)
        versionInfoLayout.setHorizontalSpacing(4)
        for name, value in version_labels:
            name.setText(name.text() + ':')
            versionInfoLayout.addRow(name, value)

        mainLayout = QVBoxLayout(self)
        mainLayout.setSpacing(0)
        mainLayout.addWidget(iconLabel)
        mainLayout.addWidget(appNameLabel)
        mainLayout.addSpacing(5)
        mainLayout.addLayout(versionInfoLayout)
        mainLayout.addSpacing(20)
        mainLayout.addLayout(linksLayout)
        mainLayout.addSpacing(20)
        mainLayout.addWidget(licenseLabel)

        if sys.platform != 'darwin':
            buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
            buttonBox.setCenterButtons(True)
            buttonBox.button(QDialogButtonBox.Close).clicked.connect(
                self.reject)

            line = QFrame()
            line.setFrameShape(QFrame.HLine)
            line.setFrameShadow(QFrame.Sunken)

            mainLayout.addSpacing(8)
            mainLayout.addWidget(line)
            mainLayout.addSpacing(8)
            mainLayout.addWidget(buttonBox)
Пример #33
0
    def __init__(self,
                 type_,
                 title,
                 msg,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None,
                 default_yes=True,
                 yes_text=None,
                 no_text=None,
                 yes_icon=None,
                 no_icon=None):
        QDialog.__init__(self, parent)
        if q_icon is None:
            icon = {
                self.ERROR: 'error',
                self.WARNING: 'warning',
                self.INFO: 'information',
                self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png' % icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(
                I(q_icon))
        self.setup_ui()

        self.setWindowTitle(title)
        self.setWindowIcon(self.icon)
        self.icon_label.setPixmap(self.icon.pixmap(128, 128))
        self.msg.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                                                self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes | self.bb.No)
            self.bb.button(
                self.bb.Yes if default_yes else self.bb.No).setDefault(True)
            self.default_yes = default_yes
            if yes_text is not None:
                self.bb.button(self.bb.Yes).setText(yes_text)
            if no_text is not None:
                self.bb.button(self.bb.No).setText(no_text)
            if yes_icon is not None:
                self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(
                    yes_icon, QIcon) else QIcon(I(yes_icon)))
            if no_icon is not None:
                self.bb.button(self.bb.No).setIcon(no_icon if isinstance(
                    no_icon, QIcon) else QIcon(I(no_icon)))
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection)
        self.do_resize()
Пример #34
0
    def __init__(self, gui, initial_panel=None):
        QDialog.__init__(self, gui)
        self.l = l = QGridLayout(self)
        self.setLayout(l)
        self.setWindowTitle(_('Preferences for Edit book'))
        self.setWindowIcon(QIcon(I('config.png')))

        self.stacks = QStackedWidget(self)
        l.addWidget(self.stacks, 0, 1, 1, 1)

        self.categories_list = cl = QListWidget(self)
        cl.currentRowChanged.connect(self.stacks.setCurrentIndex)
        cl.clearPropertyFlags()
        cl.setViewMode(cl.IconMode)
        cl.setFlow(cl.TopToBottom)
        cl.setMovement(cl.Static)
        cl.setWrapping(False)
        cl.setSpacing(15)
        if get_lang()[:2] not in ('zh', 'ja'):
            cl.setWordWrap(True)
        l.addWidget(cl, 0, 0, 1, 1)

        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok
                                        | QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.rdb = b = bb.addButton(_('Restore all &defaults'), bb.ResetRole)
        b.setToolTip(_('Restore defaults for all preferences'))
        b.clicked.connect(self.restore_all_defaults)
        self.rcdb = b = bb.addButton(_('Restore &current defaults'),
                                     bb.ResetRole)
        b.setToolTip(_('Restore defaults for currently displayed preferences'))
        b.clicked.connect(self.restore_current_defaults)
        self.rconfs = b = bb.addButton(_('Restore c&onfirmations'),
                                       bb.ResetRole)
        b.setToolTip(_('Restore all disabled confirmation prompts'))
        b.clicked.connect(self.restore_confirmations)

        l.addWidget(bb, 1, 0, 1, 2)

        self.resize(800, 600)
        geom = tprefs.get('preferences_geom', None)
        if geom is not None:
            self.restoreGeometry(geom)

        self.keyboard_panel = ShortcutConfig(self)
        self.keyboard_panel.initialize(gui.keyboard)
        self.editor_panel = EditorSettings(self)
        self.integration_panel = IntegrationSettings(self)
        self.main_window_panel = MainWindowSettings(self)
        self.preview_panel = PreviewSettings(self)
        self.toolbars_panel = ToolbarSettings(self)

        for name, icon, panel in [
            (_('Main window'), 'page.png', 'main_window'),
            (_('Editor settings'), 'modified.png', 'editor'),
            (_('Preview settings'), 'viewer.png', 'preview'),
            (_('Keyboard shortcuts'), 'keyboard-prefs.png', 'keyboard'),
            (_('Toolbars'), 'wizard.png', 'toolbars'),
            (_('Integration with calibre'), 'lt.png', 'integration'),
        ]:
            i = QListWidgetItem(QIcon(I(icon)), name, cl)
            cl.addItem(i)
            self.stacks.addWidget(getattr(self, panel + '_panel'))

        cl.setCurrentRow(0)
        cl.item(0).setSelected(True)
        w, h = cl.sizeHintForColumn(0), 0
        for i in range(cl.count()):
            h = cl.sizeHintForRow(i)
            cl.item(i).setSizeHint(QSize(w, h))

        cl.setMaximumWidth(cl.sizeHintForColumn(0) + 35)
        cl.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
Пример #35
0
    def context_menu_handler(self,
                             action=None,
                             category=None,
                             key=None,
                             index=None,
                             search_state=None,
                             use_vl=None):
        if not action:
            return
        try:
            if action == 'set_icon':
                try:
                    path = choose_files(self,
                                        'choose_category_icon',
                                        _('Change Icon for: %s') % key,
                                        filters=[
                                            ('Images',
                                             ['png', 'gif', 'jpg', 'jpeg'])
                                        ],
                                        all_files=False,
                                        select_only_single_file=True)
                    if path:
                        path = path[0]
                        p = QIcon(path).pixmap(QSize(128, 128))
                        d = os.path.join(config_dir, 'tb_icons')
                        if not os.path.exists(d):
                            os.makedirs(d)
                        with open(
                                os.path.join(
                                    d, 'icon_' +
                                    sanitize_file_name_unicode(key) + '.png'),
                                'wb') as f:
                            f.write(pixmap_to_data(p, format='PNG'))
                            path = os.path.basename(f.name)
                        self._model.set_custom_category_icon(
                            key, unicode(path))
                        self.recount()
                except:
                    import traceback
                    traceback.print_exc()
                return
            if action == 'clear_icon':
                self._model.set_custom_category_icon(key, None)
                self.recount()
                return

            if action == 'edit_item_no_vl':
                item = self.model().get_node(index)
                item.use_vl = False
                self.edit(index)
                return
            if action == 'edit_item_in_vl':
                item = self.model().get_node(index)
                item.use_vl = True
                self.edit(index)
                return
            if action == 'delete_item_in_vl':
                self.tag_item_delete.emit(key, index.id, index.original_name,
                                          self.model().get_book_ids_to_use())
                return
            if action == 'delete_item_no_vl':
                self.tag_item_delete.emit(key, index.id, index.original_name,
                                          None)
                return
            if action == 'open_editor':
                self.tags_list_edit.emit(category, key)
                return
            if action == 'manage_categories':
                self.edit_user_category.emit(category)
                return
            if action == 'search':
                self._toggle(index, set_to=search_state)
                return
            if action == 'add_to_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.all_children():
                        self.add_item_to_user_cat.emit(category,
                                                       c.tag.original_name,
                                                       c.tag.category)
                self.add_item_to_user_cat.emit(category, tag.original_name,
                                               tag.category)
                return
            if action == 'add_subcategory':
                self.add_subcategory.emit(key)
                return
            if action == 'search_category':
                self._toggle(index, set_to=search_state)
                return
            if action == 'delete_user_category':
                self.delete_user_category.emit(key)
                return
            if action == 'delete_search':
                self.model().db.saved_search_delete(key)
                self.rebuild_saved_searches.emit()
                return
            if action == 'delete_item_from_user_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.children:
                        self.del_item_from_user_cat.emit(
                            key, c.tag.original_name, c.tag.category)
                self.del_item_from_user_cat.emit(key, tag.original_name,
                                                 tag.category)
                return
            if action == 'manage_searches':
                self.saved_search_edit.emit(category)
                return
            if action == 'edit_author_sort':
                self.author_sort_edit.emit(self, index, True, False)
                return
            if action == 'edit_author_link':
                self.author_sort_edit.emit(self, index, False, True)
                return

            reset_filter_categories = True
            if action == 'hide':
                self.hidden_categories.add(category)
            elif action == 'show':
                self.hidden_categories.discard(category)
            elif action == 'categorization':
                changed = self.collapse_model != category
                self._model.collapse_model = category
                if changed:
                    reset_filter_categories = False
                    gprefs['tags_browser_partition_method'] = category
            elif action == 'defaults':
                self.hidden_categories.clear()
            self.db.new_api.set_pref('tag_browser_hidden_categories',
                                     list(self.hidden_categories))
            if reset_filter_categories:
                self._model.set_categories_filter(None)
            self._model.rebuild_node_tree()
        except:
            return
Пример #36
0
    def __init__(self, db, book_id_map, parent=None):
        from calibre.ebooks.oeb.polish.main import HELP
        QDialog.__init__(self, parent)
        self.db, self.book_id_map = weakref.ref(db), book_id_map
        self.setWindowIcon(QIcon(I('polish.png')))
        title = _('Polish book')
        if len(book_id_map) > 1:
            title = _('Polish %d books')%len(book_id_map)
        self.setWindowTitle(title)

        self.help_text = {
            'polish': _('<h3>About Polishing books</h3>%s')%HELP['about'].format(
                _('''<p>If you have both EPUB and ORIGINAL_EPUB in your book,
                  then polishing will run on ORIGINAL_EPUB (the same for other
                  ORIGINAL_* formats).  So if you
                  want Polishing to not run on the ORIGINAL_* format, delete the
                  ORIGINAL_* format before running it.</p>''')
            ),

            'embed':_('<h3>Embed referenced fonts</h3>%s')%HELP['embed'],
            'subset':_('<h3>Subsetting fonts</h3>%s')%HELP['subset'],

            'smarten_punctuation':
            _('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'],

            'metadata':_('<h3>Updating metadata</h3>'
                         '<p>This will update all metadata <i>except</i> the cover in the'
                         ' e-book files to match the current metadata in the'
                         ' calibre library.</p>'
                         ' <p>Note that most e-book'
                         ' formats are not capable of supporting all the'
                         ' metadata in calibre.</p><p>There is a separate option to'
                         ' update the cover.</p>'),
            'do_cover': _('<h3>Update cover</h3><p>Update the covers in the e-book files to match the'
                        ' current cover in the calibre library.</p>'
                        '<p>If the e-book file does not have'
                        ' an identifiable cover, a new cover is inserted.</p>'
                        ),
            'jacket':_('<h3>Book jacket</h3>%s')%HELP['jacket'],
            'remove_jacket':_('<h3>Remove book jacket</h3>%s')%HELP['remove_jacket'],
            'remove_unused_css':_('<h3>Remove unused CSS rules</h3>%s')%HELP['remove_unused_css'],
            'compress_images': _('<h3>Losslessly compress images</h3>%s') % HELP['compress_images'],
            'add_soft_hyphens': _('<h3>Add soft-hyphens</h3>%s') % HELP['add_soft_hyphens'],
            'remove_soft_hyphens': _('<h3>Remove soft-hyphens</h3>%s') % HELP['remove_soft_hyphens'],
            'upgrade_book': _('<h3>Upgrade book internals</h3>%s') % HELP['upgrade_book'],
        }

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

        self.la = la = QLabel('<b>'+_('Select actions to perform:'))
        l.addWidget(la, 0, 0, 1, 2)

        count = 0
        self.all_actions = OrderedDict([
            ('embed', _('&Embed all referenced fonts')),
            ('subset', _('&Subset all embedded fonts')),
            ('smarten_punctuation', _('Smarten &punctuation')),
            ('metadata', _('Update &metadata in the book files')),
            ('do_cover', _('Update the &cover in the book files')),
            ('jacket', _('Add/replace metadata as a "book &jacket" page')),
            ('remove_jacket', _('&Remove a previously inserted book jacket')),
            ('remove_unused_css', _('Remove &unused CSS rules from the book')),
            ('compress_images', _('Losslessly &compress images')),
            ('add_soft_hyphens', _('Add s&oft hyphens')),
            ('remove_soft_hyphens', _('Remove soft hyphens')),
            ('upgrade_book', _('&Upgrade book internals')),
        ])
        prefs = gprefs.get('polishing_settings', {})
        for name, text in iteritems(self.all_actions):
            count += 1
            x = QCheckBox(text, self)
            x.setChecked(prefs.get(name, False))
            x.setObjectName(name)
            connect_lambda(x.stateChanged, self, lambda self, state: self.option_toggled(self.sender().objectName(), state))
            l.addWidget(x, count, 0, 1, 1)
            setattr(self, 'opt_'+name, x)
            la = QLabel(' <a href="#%s">%s</a>'%(name, _('About')))
            setattr(self, 'label_'+name, x)
            la.linkActivated.connect(self.help_link_activated)
            l.addWidget(la, count, 1, 1, 1)

        count += 1
        l.addItem(QSpacerItem(10, 10, vPolicy=QSizePolicy.Policy.Expanding), count, 1, 1, 2)

        la = self.help_label = QLabel('')
        self.help_link_activated('#polish')
        la.setWordWrap(True)
        la.setTextFormat(Qt.TextFormat.RichText)
        la.setFrameShape(QFrame.Shape.StyledPanel)
        la.setAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignTop)
        la.setLineWidth(2)
        la.setStyleSheet('QLabel { margin-left: 75px }')
        l.addWidget(la, 0, 2, count+1, 1)
        l.setColumnStretch(2, 1)

        self.show_reports = sr = QCheckBox(_('Show &report'), self)
        sr.setChecked(gprefs.get('polish_show_reports', True))
        sr.setToolTip(textwrap.fill(_('Show a report of all the actions performed'
                        ' after polishing is completed')))
        l.addWidget(sr, count+1, 0, 1, 1)
        self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.save_button = sb = bb.addButton(_('&Save settings'), QDialogButtonBox.ButtonRole.ActionRole)
        sb.clicked.connect(self.save_settings)
        self.load_button = lb = bb.addButton(_('&Load settings'), QDialogButtonBox.ButtonRole.ActionRole)
        self.load_menu = QMenu(lb)
        lb.setMenu(self.load_menu)
        self.all_button = b = bb.addButton(_('Select &all'), QDialogButtonBox.ButtonRole.ActionRole)
        connect_lambda(b.clicked, self, lambda self: self.select_all(True))
        self.none_button = b = bb.addButton(_('Select &none'), QDialogButtonBox.ButtonRole.ActionRole)
        connect_lambda(b.clicked, self, lambda self: self.select_all(False))
        l.addWidget(bb, count+1, 1, 1, -1)
        self.setup_load_button()

        self.resize(QSize(950, 600))
Пример #37
0
class CoverMessageBox(QDialog, Ui_Dialog):

    ERROR = 0
    WARNING = 1
    INFO = 2
    QUESTION = 3

    def __init__(self, type_, title, msg, opts,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None, default_yes=True):
        QDialog.__init__(self, parent)

        if q_icon is None:
            icon = {
                    self.ERROR: 'error',
                    self.WARNING: 'warning',
                    self.INFO:    'information',
                    self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png' % icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon
        self.setupUi(self)

        self.setWindowTitle(title)
        self.setWindowIcon(opts.icon)
        #self.icon_label.setPixmap(self.icon.pixmap(self.COVER_SIZE, self.COVER_SIZE))
        self.icon_label.setPixmap(self.icon.pixmap(COVER_ICON_SIZE))
        self.msg.setText(msg)
        self.msg.setOpenExternalLinks(True)

        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                    self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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'))

        self.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes | self.bb.No)
            self.bb.button(self.bb.Yes if default_yes else self.bb.No
                    ).setDefault(True)
            self.default_yes = default_yes
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.do_resize()

    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):
        sz = self.sizeHint() + QSize(100, 0)
        sz.setWidth(min(500, sz.width()))
        sz.setHeight(min(500, sz.height()))
        self.resize(sz)

    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.text()),
                    unicode(self.det_msg.toPlainText())))
        if hasattr(self, 'ctc_button'):
            self.ctc_button.setText(_('Copied'))

    def showEvent(self, ev):
        ret = QDialog.showEvent(self, ev)
        if self.is_question:
            try:
                self.bb.button(self.bb.Yes if self.default_yes else self.bb.No
                        ).setFocus(Qt.OtherFocusReason)
            except:
                # Buttons were changed
                pass
        else:
            self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason)
        return ret

    def set_details(self, msg):
        if not msg:
            msg = ''
        self.det_msg.setPlainText(msg)
        self.det_msg_toggle.setText(self.show_det_msg)
        self.det_msg_toggle.setVisible(bool(msg))
        self.det_msg.setVisible(False)
        self.do_resize()
Пример #38
0
def register_text_editor_actions(_reg, palette):
    def reg(*args, **kw):
        ac = _reg(*args)
        for s in kw.get('syntaxes', ('format', )):
            editor_toolbar_actions[s][args[3]] = ac
        return ac

    ac = reg('format-text-bold', _('&Bold'), ('format_text', 'bold'),
             'format-text-bold', 'Ctrl+B', _('Make the selected text bold'))
    ac.setToolTip(_('<h3>Bold</h3>Make the selected text bold'))
    ac = reg('format-text-italic', _('&Italic'),
             ('format_text', 'italic'), 'format-text-italic', 'Ctrl+I',
             _('Make the selected text italic'))
    ac.setToolTip(_('<h3>Italic</h3>Make the selected text italic'))
    ac = reg('format-text-underline', _('&Underline'),
             ('format_text', 'underline'), 'format-text-underline', (),
             _('Underline the selected text'))
    ac.setToolTip(_('<h3>Underline</h3>Underline the selected text'))
    ac = reg('format-text-strikethrough', _('&Strikethrough'),
             ('format_text', 'strikethrough'), 'format-text-strikethrough', (),
             _('Draw a line through the selected text'))
    ac.setToolTip(
        _('<h3>Strikethrough</h3>Draw a line through the selected text'))
    ac = reg('format-text-superscript', _('&Superscript'),
             ('format_text', 'superscript'), 'format-text-superscript', (),
             _('Make the selected text a superscript'))
    ac.setToolTip(
        _('<h3>Superscript</h3>Set the selected text slightly smaller and above the normal line'
          ))
    ac = reg('format-text-subscript', _('&Subscript'),
             ('format_text', 'subscript'), 'format-text-subscript', (),
             _('Make the selected text a subscript'))
    ac.setToolTip(
        _('<h3>Subscript</h3>Set the selected text slightly smaller and below the normal line'
          ))
    ac = reg('format-text-color', _('&Color'), ('format_text', 'color'),
             'format-text-color', (), _('Change text color'))
    ac.setToolTip(_('<h3>Color</h3>Change the color of the selected text'))
    ac = reg('format-fill-color', _('&Background Color'),
             ('format_text', 'background-color'),
             'format-text-background-color', (),
             _('Change background color of text'))
    ac.setToolTip(
        _('<h3>Background Color</h3>Change the background color of the selected text'
          ))
    ac = reg('format-justify-left', _('Align &left'),
             ('format_text', 'justify_left'), 'format-text-justify-left', (),
             _('Align left'))
    ac.setToolTip(_('<h3>Align left</h3>Align the paragraph to the left'))
    ac = reg('format-justify-center', _('&Center'),
             ('format_text', 'justify_center'), 'format-text-justify-center',
             (), _('Center'))
    ac.setToolTip(_('<h3>Center</h3>Center the paragraph'))
    ac = reg('format-justify-right', _('Align &right'),
             ('format_text', 'justify_right'), 'format-text-justify-right', (),
             _('Align right'))
    ac.setToolTip(_('<h3>Align right</h3>Align the paragraph to the right'))
    ac = reg('format-justify-fill', _('&Justify'),
             ('format_text', 'justify_justify'), 'format-text-justify-fill',
             (), _('Justify'))
    ac.setToolTip(
        _('<h3>Justify</h3>Align the paragraph to both the left and right margins'
          ))

    ac = reg('view-image',
             _('&Insert image'), ('insert_resource', 'image'),
             'insert-image', (),
             _('Insert an image into the text'),
             syntaxes=('html', 'css'))
    ac.setToolTip(_('<h3>Insert image</h3>Insert an image into the text'))

    ac = reg('insert-link',
             _('Insert &hyperlink'), ('insert_hyperlink', ),
             'insert-hyperlink', (),
             _('Insert hyperlink'),
             syntaxes=('html', ))
    ac.setToolTip(
        _('<h3>Insert hyperlink</h3>Insert a hyperlink into the text'))

    for i, name in enumerate(('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p')):
        text = ('&' + name) if name == 'p' else (name[0] + '&' + name[1])
        desc = _('Convert the paragraph to &lt;%s&gt;') % name
        ac = reg(create_icon(name),
                 text, ('rename_block_tag', name),
                 'rename-block-tag-' + name,
                 'Ctrl+%d' % (i + 1),
                 desc,
                 syntaxes=())
        ac.setToolTip(desc)

    ac = reg('code',
             _('Insert &tag'), ('insert_tag', ),
             'insert-tag', ('Ctrl+<'),
             _('Insert tag'),
             syntaxes=('html', 'xml'))
    ac.setToolTip(
        _('<h3>Insert tag</h3>Insert a tag, if some text is selected the tag will be inserted around the selected text'
          ))

    editor_toolbar_actions['html']['fix-html-current'] = actions[
        'fix-html-current']
    for s in ('xml', 'html', 'css'):
        editor_toolbar_actions[s]['pretty-current'] = actions['pretty-current']
    editor_toolbar_actions['html']['change-paragraph'] = actions[
        'change-paragraph'] = QAction(QIcon(I('format-text-heading.png')),
                                      _('Change paragraph to heading'),
                                      ac.parent())
Пример #39
0
 def show_plugin(self, plugin=None):
     self.icon.set_icon(
         QIcon(I('lt.png') if plugin is None else plugin.icon))
     self.title.setText(
         '<h1>' + (_('Preferences') if plugin is None else plugin.gui_name))
Пример #40
0
    def setup_ui(self):
        self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False)
        self.l = l = QVBoxLayout(self)
        self.setLayout(l)

        self.bb.clear()
        self.bb.addButton(self.bb.Close)
        self.splitter = s = QSplitter(self)
        self.h = h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        self.install_fonts_button = b = QPushButton(_('&Install fonts'), self)
        h.addWidget(b), b.setIcon(QIcon(I('plus.png')))
        b.setToolTip(textwrap.fill(_('Install fonts from .ttf/.otf files to make them available for embedding')))
        b.clicked.connect(self.install_fonts)
        l.addWidget(s), l.addLayout(h), h.addStretch(10), h.addWidget(self.bb)

        self.fonts_view = fv = QTableView(self)
        fv.doubleClicked.connect(self.show_embedding_data)
        self.model = m = AllFonts(fv)
        fv.horizontalHeader().setStretchLastSection(True)
        fv.setModel(m)
        fv.setSortingEnabled(True)
        fv.setShowGrid(False)
        fv.setAlternatingRowColors(True)
        fv.setSelectionMode(fv.ExtendedSelection)
        fv.setSelectionBehavior(fv.SelectRows)
        fv.horizontalHeader().setSortIndicator(1, Qt.SortOrder.AscendingOrder)
        self.container = c = QWidget()
        l = c.l = QVBoxLayout(c)
        c.setLayout(l)
        s.addWidget(fv), s.addWidget(c)

        self.cb = b = QPushButton(_('&Change selected fonts'))
        b.setIcon(QIcon(I('wizard.png')))
        b.clicked.connect(self.change_fonts)
        l.addWidget(b)
        self.rb = b = QPushButton(_('&Remove selected fonts'))
        b.clicked.connect(self.remove_fonts)
        b.setIcon(QIcon(I('trash.png')))
        l.addWidget(b)
        self.eb = b = QPushButton(_('&Embed all fonts'))
        b.setIcon(QIcon(I('embed-fonts.png')))
        b.clicked.connect(self.embed_fonts)
        l.addWidget(b)
        self.sb = b = QPushButton(_('&Subset all fonts'))
        b.setIcon(QIcon(I('subset-fonts.png')))
        b.clicked.connect(self.subset_fonts)
        l.addWidget(b)
        self.refresh_button = b = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
        b.setToolTip(_('Rescan the book for fonts in case you have made changes'))
        b.setIcon(QIcon(I('view-refresh.png')))
        b.clicked.connect(self.refresh)

        self.la = la = QLabel(
            '<p>' + _(
            ''' All the fonts declared in this book are shown to the left, along with whether they are embedded or not.
            You can remove or replace any selected font and also embed any declared fonts that are not already embedded.''') + '<p>' + _(
            ''' Double click any font family to see if the font is available for embedding on your computer. ''')
        )
        la.setWordWrap(True)
        l.addWidget(la)

        l.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter)
Пример #41
0
 def __init__(self, results, parent=None):
     QAbstractTableModel.__init__(self, parent)
     self.results = results
     self.yes_icon = (QIcon(I('ok.png')))
Пример #42
0
 def editor_modified(self, *args):
     tb = self.editor_tabs.tabBar()
     for i in xrange(self.editor_tabs.count()):
         editor = self.editor_tabs.widget(i)
         modified = getattr(editor, 'is_modified', False)
         tb.setTabIcon(i, self.modified_icon if modified else QIcon())
Пример #43
0
 def process(node, parent):
     parent.setIcon(0, QIcon(I('mimetypes/dir.png')))
     for child in sorted(node, key=sort_key):
         c = QTreeWidgetItem(parent, (child, ))
         process(node[child], c)
Пример #44
0
    def create_menubar(self):
        if isosx:
            p, q = self.create_application_menubar()
            q.triggered.connect(self.action_quit.trigger)
            p.triggered.connect(self.action_preferences.trigger)
        f = factory(app_id='com.calibre-ebook.EditBook-%d' % os.getpid())
        b = f.create_window_menubar(self)

        f = b.addMenu(_('&File'))
        f.addAction(self.action_new_file)
        f.addAction(self.action_import_files)
        f.addSeparator()
        f.addAction(self.action_open_book)
        f.addAction(self.action_new_book)
        f.addAction(self.action_import_book)
        f.addAction(self.action_open_book_folder)
        self.recent_books_menu = f.addMenu(_('&Recently opened books'))
        self.update_recent_books()
        f.addSeparator()
        f.addAction(self.action_save)
        f.addAction(self.action_save_copy)
        f.addSeparator()
        f.addAction(self.action_compare_book)
        f.addAction(self.action_quit)

        e = b.addMenu(_('&Edit'))
        e.addAction(self.action_global_undo)
        e.addAction(self.action_global_redo)
        e.addAction(self.action_create_checkpoint)
        e.addSeparator()
        e.addAction(self.action_editor_undo)
        e.addAction(self.action_editor_redo)
        e.addSeparator()
        e.addAction(self.action_editor_cut)
        e.addAction(self.action_editor_copy)
        e.addAction(self.action_editor_paste)
        e.addAction(self.action_insert_char)
        e.addSeparator()
        e.addAction(self.action_quick_edit)
        e.addAction(self.action_preferences)

        e = b.addMenu(_('&Tools'))
        tm = e.addMenu(_('Table of Contents'))
        tm.addAction(self.action_toc)
        tm.addAction(self.action_inline_toc)
        e.addAction(self.action_manage_fonts)
        e.addAction(self.action_embed_fonts)
        e.addAction(self.action_subset_fonts)
        e.addAction(self.action_compress_images)
        e.addAction(self.action_smarten_punctuation)
        e.addAction(self.action_remove_unused_css)
        e.addAction(self.action_transform_styles)
        e.addAction(self.action_fix_html_all)
        e.addAction(self.action_pretty_all)
        e.addAction(self.action_rationalize_folders)
        e.addAction(self.action_add_cover)
        e.addAction(self.action_set_semantics)
        e.addAction(self.action_filter_css)
        e.addAction(self.action_spell_check_book)
        er = e.addMenu(_('External &links'))
        er.addAction(self.action_check_external_links)
        er.addAction(self.action_get_ext_resources)
        e.addAction(self.action_check_book)
        e.addAction(self.action_reports)

        e = b.addMenu(_('&View'))
        t = e.addMenu(_('Tool&bars'))
        e.addSeparator()
        for name in sorted(actions, key=lambda x: sort_key(actions[x].text())):
            ac = actions[name]
            if name.endswith('-dock'):
                e.addAction(ac)
            elif name.endswith('-bar'):
                t.addAction(ac)
        e.addAction(self.action_browse_images)
        e.addSeparator()
        e.addAction(self.action_close_current_tab)
        e.addAction(self.action_close_all_but_current_tab)

        e = b.addMenu(_('&Search'))
        a = e.addAction
        a(self.action_find)
        e.addSeparator()
        a(self.action_find_next)
        a(self.action_find_previous)
        e.addSeparator()
        a(self.action_replace)
        a(self.action_replace_next)
        a(self.action_replace_previous)
        a(self.action_replace_all)
        e.addSeparator()
        a(self.action_count)
        e.addSeparator()
        a(self.action_mark)
        e.addSeparator()
        a(self.action_go_to_line)
        e.addSeparator()
        a(self.action_saved_searches)
        e.aboutToShow.connect(self.search_menu_about_to_show)
        e.addSeparator()
        a(self.action_text_search)

        if self.plugin_menu_actions:
            e = b.addMenu(_('&Plugins'))
            for ac in sorted(self.plugin_menu_actions,
                             key=lambda x: sort_key(unicode(x.text()))):
                e.addAction(ac)

        e = b.addMenu(_('&Help'))
        a = e.addAction
        a(self.action_help)
        a(QIcon(I('donate.png')), _('&Donate to support calibre development'),
          open_donate)
        a(self.action_preferences)
Пример #45
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()
Пример #46
0
    def __init__(self, gui, parent=None, query=''):
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.config = JSONConfig('store/search')
        self.search_title.initialize('store_search_search_title')
        self.search_author.initialize('store_search_search_author')
        self.search_edit.initialize('store_search_search')

        # Loads variables that store various settings.
        # This needs to be called soon in __init__ because
        # the variables it sets up are used later.
        self.load_settings()

        self.gui = gui

        # Setup our worker threads.
        self.search_pool = SearchThreadPool(self.search_thread_count)
        self.cache_pool = CacheUpdateThreadPool(self.cache_thread_count)
        self.results_view.model().cover_pool.set_thread_count(
            self.cover_thread_count)
        self.results_view.model().details_pool.set_thread_count(
            self.details_thread_count)
        self.results_view.setCursor(Qt.PointingHandCursor)

        # Check for results and hung threads.
        self.checker = QTimer()
        self.progress_checker = QTimer()
        self.hang_check = 0

        # Update store caches silently.
        for p in self.gui.istores.values():
            self.cache_pool.add_task(p, self.timeout)

        self.store_checks = {}
        self.setup_store_checks()

        # Set the search query
        if isinstance(query, (str, unicode)):
            self.search_edit.setText(query)
        elif isinstance(query, dict):
            if 'author' in query:
                self.search_author.setText(query['author'])
            if 'title' in query:
                self.search_title.setText(query['title'])

        # Create and add the progress indicator
        self.pi = ProgressIndicator(self, 24)
        self.button_layout.takeAt(0)
        self.button_layout.setAlignment(Qt.AlignCenter)
        self.button_layout.insertWidget(0, self.pi, 0, Qt.AlignCenter)

        self.adv_search_button.setIcon(QIcon(I('gear.png')))
        self.adv_search_button.setToolTip(_('Advanced search'))
        self.configure.setIcon(QIcon(I('config.png')))

        self.adv_search_button.clicked.connect(self.build_adv_search)
        self.search.clicked.connect(self.toggle_search)
        self.checker.timeout.connect(self.get_results)
        self.progress_checker.timeout.connect(self.check_progress)
        self.results_view.activated.connect(self.result_item_activated)
        self.results_view.download_requested.connect(self.download_book)
        self.results_view.open_requested.connect(self.open_store)
        self.results_view.model().total_changed.connect(self.update_book_total)
        self.select_all_stores.clicked.connect(self.stores_select_all)
        self.select_invert_stores.clicked.connect(self.stores_select_invert)
        self.select_none_stores.clicked.connect(self.stores_select_none)
        self.configure.clicked.connect(self.do_config)
        self.finished.connect(self.dialog_closed)
        self.searching = False

        self.progress_checker.start(100)

        self.restore_state()
Пример #47
0
    def __init__(self, type_, title, msg,
                 det_msg='',
                 q_icon=None,
                 show_copy_button=True,
                 parent=None, default_yes=True,
                 yes_text=None, no_text=None, yes_icon=None, no_icon=None):
        QDialog.__init__(self, parent)
        if q_icon is None:
            icon = {
                    self.ERROR : 'error',
                    self.WARNING: 'warning',
                    self.INFO:    'information',
                    self.QUESTION: 'question',
            }[type_]
            icon = 'dialog_%s.png'%icon
            self.icon = QIcon(I(icon))
        else:
            self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(I(q_icon))
        self.setup_ui()

        self.setWindowTitle(title)
        self.setWindowIcon(self.icon)
        self.icon_label.setPixmap(self.icon.pixmap(128, 128))
        self.msg.setText(msg)
        self.det_msg.setPlainText(det_msg)
        self.det_msg.setVisible(False)
        self.toggle_checkbox.setVisible(False)

        if show_copy_button:
            self.ctc_button = self.bb.addButton(_('&Copy to clipboard'),
                    self.bb.ActionRole)
            self.ctc_button.clicked.connect(self.copy_to_clipboard)

        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.copy_action = QAction(self)
        self.addAction(self.copy_action)
        self.copy_action.setShortcuts(QKeySequence.Copy)
        self.copy_action.triggered.connect(self.copy_to_clipboard)

        self.is_question = type_ == self.QUESTION
        if self.is_question:
            self.bb.setStandardButtons(self.bb.Yes|self.bb.No)
            self.bb.button(self.bb.Yes if default_yes else self.bb.No
                    ).setDefault(True)
            self.default_yes = default_yes
            if yes_text is not None:
                self.bb.button(self.bb.Yes).setText(yes_text)
            if no_text is not None:
                self.bb.button(self.bb.No).setText(no_text)
            if yes_icon is not None:
                self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(yes_icon, QIcon) else QIcon(I(yes_icon)))
            if no_icon is not None:
                self.bb.button(self.bb.No).setIcon(no_icon if isinstance(no_icon, QIcon) else QIcon(I(no_icon)))
        else:
            self.bb.button(self.bb.Ok).setDefault(True)

        if not det_msg:
            self.det_msg_toggle.setVisible(False)

        self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection)
        self.do_resize()
Пример #48
0
    def __init__(self, window, cat_name, tag_to_match, get_book_ids, sorter):
        QDialog.__init__(self, window)
        Ui_TagListEditor.__init__(self)
        self.setupUi(self)
        self.search_box.setMinimumContentsLength(25)

        # Put the category name into the title bar
        t = self.windowTitle()
        self.setWindowTitle(t + ' (' + cat_name + ')')
        # Remove help icon on title bar
        icon = self.windowIcon()
        self.setWindowFlags(self.windowFlags()
                            & (~Qt.WindowContextHelpButtonHint))
        self.setWindowIcon(icon)

        # Get saved geometry info
        try:
            self.table_column_widths = \
                        gprefs.get('tag_list_editor_table_widths', None)
        except:
            pass

        # initialization
        self.ordered_tags = []
        self.sorter = sorter
        self.get_book_ids = get_book_ids

        # Set up the column headings
        self.down_arrow_icon = QIcon(I('arrow-down.png'))
        self.up_arrow_icon = QIcon(I('arrow-up.png'))
        self.blank_icon = QIcon(I('blank.png'))

        # Capture clicks on the horizontal header to sort the table columns
        hh = self.table.horizontalHeader()
        hh.setSectionsClickable(True)
        hh.sectionClicked.connect(self.header_clicked)
        hh.sectionResized.connect(self.table_column_resized)
        self.name_order = 0
        self.count_order = 1
        self.was_order = 1

        self.table.setItemDelegate(EditColumnDelegate(self.table))

        # Add the data
        select_item = self.fill_in_table(None, tag_to_match)

        # Scroll to the selected item if there is one
        if select_item is not None:
            self.table.setCurrentItem(select_item)

        self.delete_button.clicked.connect(self.delete_tags)
        self.rename_button.clicked.connect(self.rename_tag)
        self.undo_button.clicked.connect(self.undo_edit)
        self.table.itemDoubleClicked.connect(self._rename_tag)
        self.table.itemChanged.connect(self.finish_editing)

        self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK'))
        self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel'))
        self.buttonBox.accepted.connect(self.accepted)

        self.search_box.initialize('tag_list_search_box_' + cat_name)
        self.search_button.clicked.connect(self.all_matching_clicked)
        self.search_button.setDefault(True)

        self.apply_vl_checkbox.clicked.connect(self.vl_box_changed)

        self.table.setEditTriggers(QTableWidget.EditKeyPressed)

        try:
            geom = gprefs.get('tag_list_editor_dialog_geometry', None)
            if geom is not None:
                self.restoreGeometry(QByteArray(geom))
            else:
                self.resize(self.sizeHint() + QSize(150, 100))
        except:
            pass
Пример #49
0
    def initialize(self, library_path, db, listener, actions, show_gui=True):
        opts = self.opts
        self.preferences_action, self.quit_action = actions
        self.library_path = library_path
        self.content_server = None
        self._spare_pool = None
        self.must_restart_before_config = False
        self.listener = Listener(listener)
        self.check_messages_timer = QTimer()
        self.check_messages_timer.timeout.connect(self.another_instance_wants_to_talk)
        self.check_messages_timer.start(1000)

        for ac in self.iactions.values():
            try:
                ac.do_genesis()
            except Exception:
                # Ignore errors in third party plugins
                import traceback
                traceback.print_exc()
                if getattr(ac, 'plugin_path', None) is None:
                    raise
        self.donate_action = QAction(QIcon(I('donate.png')),
                _('&Donate to support calibre'), self)
        for st in self.istores.values():
            st.do_genesis()
        MainWindowMixin.init_main_window_mixin(self, db)

        # Jobs Button {{{
        self.job_manager = JobManager()
        self.jobs_dialog = JobsDialog(self, self.job_manager)
        self.jobs_button = JobsButton(horizontal=True, parent=self)
        self.jobs_button.initialize(self.jobs_dialog, self.job_manager)
        # }}}

        LayoutMixin.init_layout_mixin(self)
        DeviceMixin.init_device_mixin(self)

        self.progress_indicator = ProgressIndicator(self)
        self.progress_indicator.pos = (0, 20)
        self.verbose = opts.verbose
        self.get_metadata = GetMetadata()
        self.upload_memory = {}
        self.metadata_dialogs = []
        self.default_thumbnail = None
        self.tb_wrapper = textwrap.TextWrapper(width=40)
        self.viewers = collections.deque()
        self.system_tray_icon = None
        if config['systray_icon']:
            self.system_tray_icon = factory(app_id='com.calibre-ebook.gui').create_system_tray_icon(parent=self, title='calibre')
        if self.system_tray_icon is not None:
            self.system_tray_icon.setIcon(QIcon(I('lt.png')))
            if not (iswindows or isosx):
                self.system_tray_icon.setIcon(QIcon.fromTheme('calibre-gui', QIcon(I('lt.png'))))
            self.system_tray_icon.setToolTip(self.jobs_button.tray_tooltip())
            self.system_tray_icon.setVisible(True)
            self.jobs_button.tray_tooltip_updated.connect(self.system_tray_icon.setToolTip)
        elif config['systray_icon']:
            prints('Failed to create system tray icon, your desktop environment probably does not support the StatusNotifier spec')
        self.system_tray_menu = QMenu(self)
        self.toggle_to_tray_action = self.system_tray_menu.addAction(QIcon(I('page.png')), '')
        self.toggle_to_tray_action.triggered.connect(self.system_tray_icon_activated)
        self.system_tray_menu.addAction(self.donate_action)
        self.donate_button.clicked.connect(self.donate_action.trigger)
        self.donate_button.setToolTip(self.donate_action.text().replace('&', ''))
        self.donate_button.setIcon(self.donate_action.icon())
        self.donate_button.setStatusTip(self.donate_button.toolTip())
        self.eject_action = self.system_tray_menu.addAction(
                QIcon(I('eject.png')), _('&Eject connected device'))
        self.eject_action.setEnabled(False)
        self.addAction(self.quit_action)
        self.system_tray_menu.addAction(self.quit_action)
        self.keyboard.register_shortcut('quit calibre', _('Quit calibre'),
                default_keys=('Ctrl+Q',), action=self.quit_action)
        if self.system_tray_icon is not None:
            self.system_tray_icon.setContextMenu(self.system_tray_menu)
            self.system_tray_icon.activated.connect(self.system_tray_icon_activated)
        self.quit_action.triggered[bool].connect(self.quit)
        self.donate_action.triggered[bool].connect(self.donate)
        self.minimize_action = QAction(_('Minimize the calibre window'), self)
        self.addAction(self.minimize_action)
        self.keyboard.register_shortcut('minimize calibre', self.minimize_action.text(),
                default_keys=(), action=self.minimize_action)
        self.minimize_action.triggered.connect(self.showMinimized)

        self.esc_action = QAction(self)
        self.addAction(self.esc_action)
        self.keyboard.register_shortcut('clear current search',
                _('Clear the current search'), default_keys=('Esc',),
                action=self.esc_action)
        self.esc_action.triggered.connect(self.esc)

        self.shift_esc_action = QAction(self)
        self.addAction(self.shift_esc_action)
        self.keyboard.register_shortcut('focus book list',
                _('Focus the book list'), default_keys=('Shift+Esc',),
                action=self.shift_esc_action)
        self.shift_esc_action.triggered.connect(self.shift_esc)

        self.ctrl_esc_action = QAction(self)
        self.addAction(self.ctrl_esc_action)
        self.keyboard.register_shortcut('clear virtual library',
                _('Clear the virtual library'), default_keys=('Ctrl+Esc',),
                action=self.ctrl_esc_action)
        self.ctrl_esc_action.triggered.connect(self.ctrl_esc)

        self.alt_esc_action = QAction(self)
        self.addAction(self.alt_esc_action)
        self.keyboard.register_shortcut('clear additional restriction',
                _('Clear the additional restriction'), default_keys=('Alt+Esc',),
                action=self.alt_esc_action)
        self.alt_esc_action.triggered.connect(self.clear_additional_restriction)

        # ###################### Start spare job server ########################
        QTimer.singleShot(1000, self.create_spare_pool)

        # ###################### Location Manager ########################
        self.location_manager.location_selected.connect(self.location_selected)
        self.location_manager.unmount_device.connect(self.device_manager.umount_device)
        self.location_manager.configure_device.connect(self.configure_connected_device)
        self.location_manager.update_device_metadata.connect(self.update_metadata_on_device)
        self.eject_action.triggered.connect(self.device_manager.umount_device)

        # ################### Update notification ###################
        UpdateMixin.init_update_mixin(self, opts)

        # ###################### Search boxes ########################
        SearchRestrictionMixin.init_search_restriction_mixin(self)
        SavedSearchBoxMixin.init_saved_seach_box_mixin(self)

        # ###################### Library view ########################
        LibraryViewMixin.init_library_view_mixin(self, db)
        SearchBoxMixin.init_search_box_mixin(self)  # Requires current_db

        if show_gui:
            self.show()

        if self.system_tray_icon is not None and self.system_tray_icon.isVisible() and opts.start_in_tray:
            self.hide_windows()
        self.library_view.model().count_changed_signal.connect(
                self.iactions['Choose Library'].count_changed)
        if not gprefs.get('quick_start_guide_added', False):
            try:
                add_quick_start_guide(self.library_view)
            except:
                import traceback
                traceback.print_exc()
        for view in ('library', 'memory', 'card_a', 'card_b'):
            v = getattr(self, '%s_view' % view)
            v.selectionModel().selectionChanged.connect(self.update_status_bar)
            v.model().count_changed_signal.connect(self.update_status_bar)

        self.library_view.model().count_changed()
        self.bars_manager.database_changed(self.library_view.model().db)
        self.library_view.model().database_changed.connect(self.bars_manager.database_changed,
                type=Qt.QueuedConnection)

        # ########################## Tags Browser ##############################
        TagBrowserMixin.init_tag_browser_mixin(self, db)

        # ######################## Search Restriction ##########################
        if db.prefs['virtual_lib_on_startup']:
            self.apply_virtual_library(db.prefs['virtual_lib_on_startup'])
        self.rebuild_vl_tabs()

        # ########################## Cover Flow ################################

        CoverFlowMixin.init_cover_flow_mixin(self)

        self._calculated_available_height = min(max_available_height()-15,
                self.height())
        self.resize(self.width(), self._calculated_available_height)

        self.build_context_menus()

        for ac in self.iactions.values():
            try:
                ac.gui_layout_complete()
            except:
                import traceback
                traceback.print_exc()
                if ac.plugin_path is None:
                    raise

        if config['autolaunch_server']:
            self.start_content_server()

        self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)

        self.read_settings()
        self.finalize_layout()
        if self.bars_manager.showing_donate:
            self.donate_button.start_animation()
        self.set_window_title()

        for ac in self.iactions.values():
            try:
                ac.initialization_complete()
            except:
                import traceback
                traceback.print_exc()
                if ac.plugin_path is None:
                    raise
        self.set_current_library_information(current_library_name(), db.library_id,
                                             db.field_metadata)

        register_keyboard_shortcuts()
        self.keyboard.finalize()
        self.auto_adder = AutoAdder(gprefs['auto_add_path'], self)

        self.save_layout_state()

        # Collect cycles now
        gc.collect()

        if show_gui and self.gui_debug is not None:
            QTimer.singleShot(10, self.show_gui_debug_msg)

        self.iactions['Connect Share'].check_smartdevice_menus()
        QTimer.singleShot(1, self.start_smartdevice)
        QTimer.singleShot(100, self.update_toggle_to_tray_action)
Пример #50
0
def main(args=sys.argv):
    # Ensure viewer can continue to function if GUI is closed
    os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None)
    reset_base_dir()
    scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii'))
    scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host)
    scheme.setFlags(QWebEngineUrlScheme.SecureScheme)
    QWebEngineUrlScheme.registerScheme(scheme)
    override = 'calibre-ebook-viewer' if islinux else None
    app = Application(args,
                      override_program_name=override,
                      color_prefs=vprefs,
                      windows_app_uid=VIEWER_APP_UID)

    parser = option_parser()
    opts, args = parser.parse_args(args)

    if opts.open_at and not (opts.open_at.startswith('toc:')
                             or opts.open_at.startswith('epubcfi(/')):
        raise SystemExit('Not a valid --open-at value: {}'.format(
            opts.open_at))

    listener = None
    if vprefs['singleinstance']:
        try:
            listener = ensure_single_instance(args, opts.open_at)
        except Exception as e:
            import traceback
            error_dialog(None,
                         _('Failed to start viewer'),
                         as_unicode(e),
                         det_msg=traceback.format_exc(),
                         show=True)
            raise SystemExit(1)

    acc = EventAccumulator(app)
    app.file_event_hook = acc
    app.load_builtin_fonts()
    app.setWindowIcon(QIcon(I('viewer.png')))
    migrate_previous_viewer_prefs()
    main = EbookViewer(open_at=opts.open_at,
                       continue_reading=opts.continue_reading)
    main.set_exception_handler()
    if len(args) > 1:
        acc.events.append(args[-1])
    acc.got_file.connect(main.handle_commandline_arg)
    main.show()
    main.msg_from_anotherinstance.connect(main.another_instance_wants_to_talk,
                                          type=Qt.QueuedConnection)
    if listener is not None:
        t = Thread(name='ConnListener',
                   target=listen,
                   args=(listener, main.msg_from_anotherinstance))
        t.daemon = True
        t.start()
    QTimer.singleShot(0, acc.flush)
    if opts.raise_window:
        main.raise_()
    if opts.full_screen:
        main.set_full_screen(True)

    app.exec_()
    if listener is not None:
        listener.close()
Пример #51
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()
Пример #52
0
    def ask_link(self):
        class Ask(QDialog):
            def accept(self):
                if self.treat_as_image.isChecked():
                    url = self.url.text()
                    if url.lower().split(':', 1)[0] in ('http', 'https'):
                        error_dialog(
                            self,
                            _('Remote images not supported'),
                            _('You must download the image to your computer, URLs pointing'
                              ' to remote images are not supported.'),
                            show=True)
                        return
                QDialog.accept(self)

        d = Ask(self)
        d.setWindowTitle(_('Create link'))
        l = QFormLayout()
        l.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
        d.setLayout(l)
        d.url = QLineEdit(d)
        d.name = QLineEdit(d)
        d.treat_as_image = QCheckBox(d)
        d.setMinimumWidth(600)
        d.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        d.br = b = QPushButton(_('&Browse'))
        b.setIcon(QIcon(I('document_open.png')))

        def cf():
            filetypes = []
            if d.treat_as_image.isChecked():
                filetypes = [(_('Images'), 'png jpeg jpg gif'.split())]
            files = choose_files(d,
                                 'select link file',
                                 _('Choose file'),
                                 filetypes,
                                 select_only_single_file=True)
            if files:
                path = files[0]
                d.url.setText(path)
                if path and os.path.exists(path):
                    with lopen(path, 'rb') as f:
                        q = what(f)
                    is_image = q in {'jpeg', 'png', 'gif'}
                    d.treat_as_image.setChecked(is_image)

        b.clicked.connect(cf)
        d.la = la = QLabel(
            _('Enter a URL. If you check the "Treat the URL as an image" box '
              'then the URL will be added as an image reference instead of as '
              'a link. You can also choose to create a link to a file on '
              'your computer. '
              'Note that if you create a link to a file on your computer, it '
              'will stop working if the file is moved.'))
        la.setWordWrap(True)
        la.setStyleSheet('QLabel { margin-bottom: 1.5ex }')
        l.setWidget(0, l.SpanningRole, la)
        l.addRow(_('Enter &URL:'), d.url)
        l.addRow(_('Treat the URL as an &image'), d.treat_as_image)
        l.addRow(_('Enter &name (optional):'), d.name)
        l.addRow(_('Choose a file on your computer:'), d.br)
        l.addRow(d.bb)
        d.bb.accepted.connect(d.accept)
        d.bb.rejected.connect(d.reject)
        d.resize(d.sizeHint())
        link, name, is_image = None, None, False
        if d.exec_() == d.Accepted:
            link, name = unicode_type(d.url.text()).strip(), unicode_type(
                d.name.text()).strip()
            is_image = d.treat_as_image.isChecked()
        return link, name, is_image
Пример #53
0
    def __init__(self, parent=None, panel_name='search'):
        QWidget.__init__(self, parent)
        self.ignore_search_type_changes = False
        self.l = l = QVBoxLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        l.addLayout(h)

        self.search_box = sb = SearchBox(self)
        self.panel_name = panel_name
        sb.initialize('viewer-{}-panel-expression'.format(panel_name))
        sb.item_selected.connect(self.saved_search_selected)
        sb.history_saved.connect(self.history_saved)
        sb.cleared.connect(self.cleared)
        sb.lineEdit().returnPressed.connect(self.find_next)
        h.addWidget(sb)

        self.next_button = nb = QToolButton(self)
        h.addWidget(nb)
        nb.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        nb.setIcon(QIcon(I('arrow-down.png')))
        nb.clicked.connect(self.find_next)
        nb.setToolTip(_('Find next match'))

        self.prev_button = nb = QToolButton(self)
        h.addWidget(nb)
        nb.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        nb.setIcon(QIcon(I('arrow-up.png')))
        nb.clicked.connect(self.find_previous)
        nb.setToolTip(_('Find previous match'))

        h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        l.addLayout(h)
        self.query_type = qt = QComboBox(self)
        qt.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        qt.addItem(_('Contains'), 'normal')
        qt.addItem(_('Whole words'), 'word')
        qt.addItem(_('Regex'), 'regex')
        qt.setToolTip(('<p>' + _(
            'Choose the type of search: <ul>'
            '<li><b>Contains</b> will search for the entered text anywhere.'
            '<li><b>Whole words</b> will search for whole words that equal the entered text.'
            '<li><b>Regex</b> will interpret the text as a regular expression.'
        )))
        qt.setCurrentIndex(
            qt.findData(
                vprefs.get('viewer-{}-mode'.format(self.panel_name), 'normal')
                or 'normal'))
        qt.currentIndexChanged.connect(self.save_search_type)
        h.addWidget(qt)

        self.case_sensitive = cs = QCheckBox(_('&Case sensitive'), self)
        cs.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        cs.setChecked(
            bool(
                vprefs.get('viewer-{}-case-sensitive'.format(self.panel_name),
                           False)))
        cs.stateChanged.connect(self.save_search_type)
        h.addWidget(cs)

        self.return_button = rb = QToolButton(self)
        rb.setIcon(QIcon(I('back.png')))
        rb.setToolTip(_('Go back to where you were before searching'))
        rb.clicked.connect(self.go_back)
        h.addWidget(rb)
Пример #54
0
    def initialize(self, library_path, db, listener, actions, show_gui=True):
        opts = self.opts
        self.preferences_action, self.quit_action = actions
        self.library_path = library_path
        self.content_server = None
        self._spare_pool = None
        self.must_restart_before_config = False
        self.listener = Listener(listener)
        self.check_messages_timer = QTimer()
        self.check_messages_timer.timeout.connect(self.another_instance_wants_to_talk)
        self.check_messages_timer.start(1000)

        for ac in self.iactions.values():
            try:
                ac.do_genesis()
            except Exception:
                # Ignore errors in third party plugins
                import traceback
                traceback.print_exc()
                if getattr(ac, 'plugin_path', None) is None:
                    raise
        self.donate_action = QAction(QIcon(I('donate.png')),
                _('&Donate to support calibre'), self)
        for st in self.istores.values():
            st.do_genesis()
        MainWindowMixin.init_main_window_mixin(self, db)

        # Jobs Button {{{
        self.job_manager = JobManager()
        self.jobs_dialog = JobsDialog(self, self.job_manager)
        self.jobs_button = JobsButton(horizontal=True, parent=self)
        self.jobs_button.initialize(self.jobs_dialog, self.job_manager)
        # }}}

        LayoutMixin.init_layout_mixin(self)
        DeviceMixin.init_device_mixin(self)

        self.progress_indicator = ProgressIndicator(self)
        self.progress_indicator.pos = (0, 20)
        self.verbose = opts.verbose
        self.get_metadata = GetMetadata()
        self.upload_memory = {}
        self.metadata_dialogs = []
        self.default_thumbnail = None
        self.tb_wrapper = textwrap.TextWrapper(width=40)
        self.viewers = collections.deque()
        self.system_tray_icon = None
        if config['systray_icon']:
            self.system_tray_icon = factory(app_id='com.calibre-ebook.gui').create_system_tray_icon(parent=self, title='calibre')
        if self.system_tray_icon is not None:
            self.system_tray_icon.setIcon(QIcon(I('lt.png')))
            if not (iswindows or isosx):
                self.system_tray_icon.setIcon(QIcon.fromTheme('calibre-gui', QIcon(I('lt.png'))))
            self.system_tray_icon.setToolTip(self.jobs_button.tray_tooltip())
            self.system_tray_icon.setVisible(True)
            self.jobs_button.tray_tooltip_updated.connect(self.system_tray_icon.setToolTip)
        elif config['systray_icon']:
            prints('Failed to create system tray icon, your desktop environment probably does not support the StatusNotifier spec')
        self.system_tray_menu = QMenu(self)
        self.toggle_to_tray_action = self.system_tray_menu.addAction(QIcon(I('page.png')), '')
        self.toggle_to_tray_action.triggered.connect(self.system_tray_icon_activated)
        self.system_tray_menu.addAction(self.donate_action)
        self.donate_button.clicked.connect(self.donate_action.trigger)
        self.donate_button.setToolTip(self.donate_action.text().replace('&', ''))
        self.donate_button.setIcon(self.donate_action.icon())
        self.donate_button.setStatusTip(self.donate_button.toolTip())
        self.eject_action = self.system_tray_menu.addAction(
                QIcon(I('eject.png')), _('&Eject connected device'))
        self.eject_action.setEnabled(False)
        self.addAction(self.quit_action)
        self.system_tray_menu.addAction(self.quit_action)
        self.keyboard.register_shortcut('quit calibre', _('Quit calibre'),
                default_keys=('Ctrl+Q',), action=self.quit_action)
        if self.system_tray_icon is not None:
            self.system_tray_icon.setContextMenu(self.system_tray_menu)
            self.system_tray_icon.activated.connect(self.system_tray_icon_activated)
        self.quit_action.triggered[bool].connect(self.quit)
        self.donate_action.triggered[bool].connect(self.donate)
        self.minimize_action = QAction(_('Minimize the calibre window'), self)
        self.addAction(self.minimize_action)
        self.keyboard.register_shortcut('minimize calibre', self.minimize_action.text(),
                default_keys=(), action=self.minimize_action)
        self.minimize_action.triggered.connect(self.showMinimized)

        self.esc_action = QAction(self)
        self.addAction(self.esc_action)
        self.keyboard.register_shortcut('clear current search',
                _('Clear the current search'), default_keys=('Esc',),
                action=self.esc_action)
        self.esc_action.triggered.connect(self.esc)

        self.shift_esc_action = QAction(self)
        self.addAction(self.shift_esc_action)
        self.keyboard.register_shortcut('focus book list',
                _('Focus the book list'), default_keys=('Shift+Esc',),
                action=self.shift_esc_action)
        self.shift_esc_action.triggered.connect(self.shift_esc)

        self.ctrl_esc_action = QAction(self)
        self.addAction(self.ctrl_esc_action)
        self.keyboard.register_shortcut('clear virtual library',
                _('Clear the virtual library'), default_keys=('Ctrl+Esc',),
                action=self.ctrl_esc_action)
        self.ctrl_esc_action.triggered.connect(self.ctrl_esc)

        self.alt_esc_action = QAction(self)
        self.addAction(self.alt_esc_action)
        self.keyboard.register_shortcut('clear additional restriction',
                _('Clear the additional restriction'), default_keys=('Alt+Esc',),
                action=self.alt_esc_action)
        self.alt_esc_action.triggered.connect(self.clear_additional_restriction)

        # ###################### Start spare job server ########################
        QTimer.singleShot(1000, self.create_spare_pool)

        # ###################### Location Manager ########################
        self.location_manager.location_selected.connect(self.location_selected)
        self.location_manager.unmount_device.connect(self.device_manager.umount_device)
        self.location_manager.configure_device.connect(self.configure_connected_device)
        self.location_manager.update_device_metadata.connect(self.update_metadata_on_device)
        self.eject_action.triggered.connect(self.device_manager.umount_device)

        # ################### Update notification ###################
        UpdateMixin.init_update_mixin(self, opts)

        # ###################### Search boxes ########################
        SearchRestrictionMixin.init_search_restirction_mixin(self)
        SavedSearchBoxMixin.init_saved_seach_box_mixin(self)

        # ###################### Library view ########################
        LibraryViewMixin.init_library_view_mixin(self, db)
        SearchBoxMixin.init_search_box_mixin(self)  # Requires current_db

        if show_gui:
            self.show()

        if self.system_tray_icon is not None and self.system_tray_icon.isVisible() and opts.start_in_tray:
            self.hide_windows()
        self.library_view.model().count_changed_signal.connect(
                self.iactions['Choose Library'].count_changed)
        if not gprefs.get('quick_start_guide_added', False):
            try:
                add_quick_start_guide(self.library_view)
            except:
                import traceback
                traceback.print_exc()
        for view in ('library', 'memory', 'card_a', 'card_b'):
            v = getattr(self, '%s_view' % view)
            v.selectionModel().selectionChanged.connect(self.update_status_bar)
            v.model().count_changed_signal.connect(self.update_status_bar)

        self.library_view.model().count_changed()
        self.bars_manager.database_changed(self.library_view.model().db)
        self.library_view.model().database_changed.connect(self.bars_manager.database_changed,
                type=Qt.QueuedConnection)

        # ########################## Tags Browser ##############################
        TagBrowserMixin.init_tag_browser_mixin(self, db)

        # ######################## Search Restriction ##########################
        if db.prefs['virtual_lib_on_startup']:
            self.apply_virtual_library(db.prefs['virtual_lib_on_startup'])
        self.rebuild_vl_tabs()

        # ########################## Cover Flow ################################

        CoverFlowMixin.init_cover_flow_mixin(self)

        self._calculated_available_height = min(max_available_height()-15,
                self.height())
        self.resize(self.width(), self._calculated_available_height)

        self.build_context_menus()

        for ac in self.iactions.values():
            try:
                ac.gui_layout_complete()
            except:
                import traceback
                traceback.print_exc()
                if ac.plugin_path is None:
                    raise

        if config['autolaunch_server']:
            self.start_content_server()

        self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)

        self.read_settings()
        self.finalize_layout()
        if self.bars_manager.showing_donate:
            self.donate_button.start_animation()
        self.set_window_title()

        for ac in self.iactions.values():
            try:
                ac.initialization_complete()
            except:
                import traceback
                traceback.print_exc()
                if ac.plugin_path is None:
                    raise
        self.set_current_library_information(current_library_name(), db.library_id,
                                             db.field_metadata)

        register_keyboard_shortcuts()
        self.keyboard.finalize()
        self.auto_adder = AutoAdder(gprefs['auto_add_path'], self)

        self.save_layout_state()

        # Collect cycles now
        gc.collect()

        if show_gui and self.gui_debug is not None:
            QTimer.singleShot(10, self.show_gui_debug_msg)

        self.iactions['Connect Share'].check_smartdevice_menus()
        QTimer.singleShot(1, self.start_smartdevice)
        QTimer.singleShot(100, self.update_toggle_to_tray_action)