Exemple #1
0
class BlockingBusy(QDialog):

    def __init__(self, msg, parent=None, window_title=_('Working')):
        QDialog.__init__(self, parent)

        self._layout = QVBoxLayout()
        self.setLayout(self._layout)
        self.msg = QLabel(msg)
        # self.msg.setWordWrap(True)
        self.font = QFont()
        self.font.setPointSize(self.font.pointSize() + 8)
        self.msg.setFont(self.font)
        self.pi = ProgressIndicator(self)
        self.pi.setDisplaySize(100)
        self._layout.addWidget(self.pi, 0, Qt.AlignHCenter)
        self._layout.addSpacing(15)
        self._layout.addWidget(self.msg, 0, Qt.AlignHCenter)
        self.start()
        self.setWindowTitle(window_title)
        self.resize(self.sizeHint())

    def start(self):
        self.pi.startAnimation()

    def stop(self):
        self.pi.stopAnimation()

    def accept(self):
        self.stop()
        return QDialog.accept(self)

    def reject(self):
        pass  # Cannot cancel this dialog
Exemple #2
0
    def paint_line_numbers(self, ev):
        painter = QPainter(self.line_number_area)
        painter.fillRect(ev.rect(), self.line_number_palette.color(QPalette.Base))

        block = self.firstVisibleBlock()
        num = block.blockNumber()
        top = int(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
        bottom = top + int(self.blockBoundingRect(block).height())
        current = self.textCursor().block().blockNumber()
        painter.setPen(self.line_number_palette.color(QPalette.Text))

        while block.isValid() and top <= ev.rect().bottom():
            if block.isVisible() and bottom >= ev.rect().top():
                if current == num:
                    painter.save()
                    painter.setPen(self.line_number_palette.color(QPalette.BrightText))
                    f = QFont(self.font())
                    f.setBold(True)
                    painter.setFont(f)
                    self.last_current_lnum = (top, bottom - top)
                painter.drawText(
                    0, top, self.line_number_area.width() - 5, self.fontMetrics().height(), Qt.AlignRight, str(num + 1)
                )
                if current == num:
                    painter.restore()
            block = block.next()
            top = bottom
            bottom = top + int(self.blockBoundingRect(block).height())
            num += 1
Exemple #3
0
    def font(self, text_style):
        device_font = text_style.fontfacename in LIBERATION_FONT_MAP
        try:
            if device_font:
                face = self.font_map[text_style.fontfacename]
            else:
                face = self.face_map[text_style.fontfacename]
        except KeyError:  # Bad fontfacename field in LRF
            face = self.font_map['Dutch801 Rm BT Roman']

        sz = text_style.fontsize
        wt = text_style.fontweight
        style = text_style.fontstyle
        font = (face, wt, style, sz,)
        if font in self.cache:
            rfont = self.cache[font]
        else:
            italic = font[2] == QFont.StyleItalic
            rfont = QFont(font[0], font[3], font[1], italic)
            rfont.setPixelSize(font[3])
            rfont.setBold(wt>=69)
            self.cache[font] = rfont
        qfont = rfont
        if text_style.emplinetype != 'none':
            qfont = QFont(rfont)
            qfont.setOverline(text_style.emplineposition == 'before')
            qfont.setUnderline(text_style.emplineposition == 'after')
        return qfont
Exemple #4
0
class NewsCategory(NewsTreeItem):

    def __init__(self, category, builtin, custom, scheduler_config, parent):
        NewsTreeItem.__init__(self, builtin, custom, scheduler_config, parent)
        self.category = category
        self.cdata = get_language(self.category)
        self.bold_font = QFont()
        self.bold_font.setBold(True)
        self.bold_font = (self.bold_font)

    def data(self, role):
        if role == Qt.DisplayRole:
            return (self.cdata + ' [%d]'%len(self.children))
        elif role == Qt.FontRole:
            return self.bold_font
        elif role == Qt.ForegroundRole and self.category == _('Scheduled'):
            return (QColor(0, 255, 0))
        return None

    def flags(self):
        return Qt.ItemIsEnabled

    def __cmp__(self, other):
        def decorate(x):
            if x == _('Scheduled'):
                x = '0' + x
            elif x == _('Custom'):
                x = '1' + x
            else:
                x = '2' + x
            return x

        return cmp(decorate(self.cdata), decorate(getattr(other, 'cdata', '')))
Exemple #5
0
class NewsCategory(NewsTreeItem):

    def __init__(self, category, builtin, custom, scheduler_config, parent):
        NewsTreeItem.__init__(self, builtin, custom, scheduler_config, parent)
        self.category = category
        self.cdata = get_language(self.category)
        if self.category == _('Scheduled'):
            self.sortq = 0, ''
        elif self.category == _('Custom'):
            self.sortq = 1, ''
        else:
            self.sortq = 2, self.cdata
        self.bold_font = QFont()
        self.bold_font.setBold(True)
        self.bold_font = (self.bold_font)

    def data(self, role):
        if role == Qt.DisplayRole:
            return (self.cdata + ' [%d]'%len(self.children))
        elif role == Qt.FontRole:
            return self.bold_font
        elif role == Qt.ForegroundRole and self.category == _('Scheduled'):
            return (QColor(0, 255, 0))
        return None

    def flags(self):
        return Qt.ItemIsEnabled

    def __eq__(self, other):
        return self.cdata == other.cdata

    def __lt__(self, other):
        return self.sortq < getattr(other, 'sortq', (3, ''))
Exemple #6
0
    def __init__(self, log, icon):
        '''
        :param log: The text to show in the dialog
        :param icon: The window icon
        '''
        QDialog.__init__(self)

        self.setWindowTitle(_('Prince log'))
        self.setWindowIcon(icon)

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

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

        self.box = QPlainTextEdit()
        self.box.setPlainText(log)
        self.box.setStyleSheet('* { font-family: monospace }')
        self.box.setMinimumWidth(500)
        self.box.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.box.setReadOnly(True)
        self.box.setToolTip(_('<qt>Console output from the last Prince run</qt>'))
        self.l.addWidget(self.box)
         
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.accept)

        self.adjustSize()
Exemple #7
0
class RatingDelegate(QStyledItemDelegate):  # {{{

    def __init__(self, *args, **kwargs):
        QStyledItemDelegate.__init__(self, *args, **kwargs)
        self.rf = QFont(rating_font())
        self.em = Qt.ElideMiddle
        delta = 0
        if iswindows and sys.getwindowsversion().major >= 6:
            delta = 2
        self.rf.setPointSize(QFontInfo(QApplication.font()).pointSize()+delta)

    def createEditor(self, parent, option, index):
        sb = QStyledItemDelegate.createEditor(self, parent, option, index)
        sb.setMinimum(0)
        sb.setMaximum(5)
        sb.setSuffix(' ' + _('stars'))
        return sb

    def displayText(self, value, locale):
        r = int(value)
        if r < 0 or r > 5:
            r = 0
        return u'\u2605'*r

    def sizeHint(self, option, index):
        option.font = self.rf
        option.textElideMode = self.em
        return QStyledItemDelegate.sizeHint(self, option, index)

    def paint(self, painter, option, index):
        option.font = self.rf
        option.textElideMode = self.em
        return QStyledItemDelegate.paint(self, painter, option, index)
Exemple #8
0
    def __init__(self, parent, recipe_model):
        ResizableDialog.__init__(self, parent)

        self._model = self.model = CustomRecipeModel(recipe_model)
        self.available_profiles.setModel(self._model)
        self.available_profiles.currentChanged = self.current_changed
        f = QFont()
        f.setStyleHint(f.Monospace)
        self.source_code.setFont(f)

        self.remove_feed_button.clicked[(bool)].connect(self.added_feeds.remove_selected_items)
        self.remove_profile_button.clicked[(bool)].connect(self.remove_selected_items)
        self.add_feed_button.clicked[(bool)].connect(self.add_feed)
        self.load_button.clicked.connect(self.load)
        self.opml_button.clicked.connect(self.opml_import)
        self.builtin_recipe_button.clicked.connect(self.add_builtin_recipe)
        self.share_button.clicked.connect(self.share)
        self.show_recipe_files_button.clicked.connect(self.show_recipe_files)
        self.down_button.clicked.connect(self.down)
        self.up_button.clicked.connect(self.up)
        self.add_profile_button.clicked[(bool)].connect(self.add_profile)
        self.feed_url.returnPressed[()].connect(self.add_feed)
        self.feed_title.returnPressed[()].connect(self.add_feed)
        self.toggle_mode_button.clicked[(bool)].connect(self.toggle_mode)
        self.clear()
Exemple #9
0
class NewsCategory(NewsTreeItem):
    def __init__(self, category, builtin, custom, scheduler_config, parent):
        NewsTreeItem.__init__(self, builtin, custom, scheduler_config, parent)
        self.category = category
        self.cdata = get_language(self.category)
        self.bold_font = QFont()
        self.bold_font.setBold(True)
        self.bold_font = self.bold_font

    def data(self, role):
        if role == Qt.DisplayRole:
            return self.cdata + " [%d]" % len(self.children)
        elif role == Qt.FontRole:
            return self.bold_font
        elif role == Qt.ForegroundRole and self.category == _("Scheduled"):
            return QColor(0, 255, 0)
        return None

    def flags(self):
        return Qt.ItemIsEnabled

    def __cmp__(self, other):
        def decorate(x):
            if x == _("Scheduled"):
                x = "0" + x
            elif x == _("Custom"):
                x = "1" + x
            else:
                x = "2" + x
            return x

        return cmp(decorate(self.cdata), decorate(getattr(other, "cdata", "")))
Exemple #10
0
 def __init__ (self,parent=None):
     super(Title,self).__init__(parent)
     self.setAlignment(QtCore.Qt.AlignCenter)
     font = QFont()
     #font.setFamily("Nyala")
     font.setFamily("Old English Text MT")
     font.setPointSize(24)
     self.setFont(font)
Exemple #11
0
 def capture_clicked(self, which=1):
     self.capture = which
     button = getattr(self, "button%d" % which)
     button.setText(_("Press a key..."))
     button.setFocus(Qt.OtherFocusReason)
     font = QFont()
     font.setBold(True)
     button.setFont(font)
Exemple #12
0
 def capture_clicked(self, which=1):
     self.capture = which
     for w in 1, 2:
         self.clear_button(w)
     button = getattr(self, 'button%d'%which)
     button.setText(_('Press a key...'))
     button.setFocus(Qt.OtherFocusReason)
     font = QFont()
     font.setBold(True)
     button.setFont(font)
Exemple #13
0
def message_image(text, width=500, height=400, font_size=20):
    init_environment()
    img = QImage(width, height, QImage.Format_ARGB32)
    img.fill(Qt.white)
    p = QPainter(img)
    f = QFont()
    f.setPixelSize(font_size)
    p.setFont(f)
    r = img.rect().adjusted(10, 10, -10, -10)
    p.drawText(r, Qt.AlignJustify | Qt.AlignVCenter | Qt.TextWordWrap, text)
    p.end()
    return pixmap_to_data(img)
    def __init__(self, parent, icon_name, title):
        QHBoxLayout.__init__(self)
        self.title_image_label = QLabel(parent)
        self.update_title_icon(icon_name)
        self.addWidget(self.title_image_label)

        title_font = QFont()
        title_font.setPointSize(16)
        shelf_label = QLabel(title, parent)
        shelf_label.setFont(title_font)
        self.addWidget(shelf_label)
        self.insertStretch(-1)
Exemple #15
0
 def set_window_title(self):
     db = self.current_db
     restrictions = [x for x in (db.data.get_base_restriction_name(), db.data.get_search_restriction_name()) if x]
     restrictions = " :: ".join(restrictions)
     font = QFont()
     if restrictions:
         restrictions = " :: " + restrictions
         font.setBold(True)
         font.setItalic(True)
     self.virtual_library.setFont(font)
     title = u"{0} - || {1}{2} ||".format(__appname__, self.iactions["Choose Library"].library_name(), restrictions)
     self.setWindowTitle(title)
Exemple #16
0
    def popup(self, select_first=True):
        if self.disable_popup:
            return
        p = self
        m = p.model()
        widget = self.completer_widget()
        if widget is None:
            return
        screen = QApplication.desktop().availableGeometry(widget)
        h = (p.sizeHintForRow(0) * min(self.max_visible_items, m.rowCount()) + 3) + 3
        hsb = p.horizontalScrollBar()
        if hsb and hsb.isVisible():
            h += hsb.sizeHint().height()

        rh = widget.height()
        pos = widget.mapToGlobal(QPoint(0, widget.height() - 2))
        w = min(widget.width(), screen.width())

        if (pos.x() + w) > (screen.x() + screen.width()):
            pos.setX(screen.x() + screen.width() - w)
        if pos.x() < screen.x():
            pos.setX(screen.x())

        top = pos.y() - rh - screen.top() + 2
        bottom = screen.bottom() - pos.y()
        h = max(h, p.minimumHeight())
        if h > bottom:
            h = min(max(top, bottom), h)

            if top > bottom:
                pos.setY(pos.y() - h - rh + 2)

        p.setGeometry(pos.x(), pos.y(), w, h)

        if (
            tweaks["preselect_first_completion"]
            and select_first
            and not self.currentIndex().isValid()
            and self.model().rowCount() > 0
        ):
            self.setCurrentIndex(self.model().index(0))

        if not p.isVisible():
            if isosx and get_osx_version() >= (10, 9, 0):
                # On mavericks the popup menu seems to use a font smaller than
                # the widgets font, see for example:
                # https://bugs.launchpad.net/bugs/1243761
                fp = QFontInfo(widget.font())
                f = QFont()
                f.setPixelSize(fp.pixelSize())
                self.setFont(f)
            p.show()
Exemple #17
0
class HeaderView(QHeaderView):  # {{{

    def __init__(self, *args):
        QHeaderView.__init__(self, *args)
        self.hover = -1
        self.current_font = QFont(self.font())
        self.current_font.setBold(True)
        self.current_font.setItalic(True)

    def event(self, e):
        if e.type() in (e.HoverMove, e.HoverEnter):
            self.hover = self.logicalIndexAt(e.pos())
        elif e.type() in (e.Leave, e.HoverLeave):
            self.hover = -1
        return QHeaderView.event(self, e)

    def paintSection(self, painter, rect, logical_index):
        opt = QStyleOptionHeader()
        self.initStyleOption(opt)
        opt.rect = rect
        opt.section = logical_index
        opt.orientation = self.orientation()
        opt.textAlignment = Qt.AlignHCenter | Qt.AlignVCenter
        model = self.parent().model()
        opt.text = unicode(model.headerData(logical_index, opt.orientation, Qt.DisplayRole) or '')
        if self.isSortIndicatorShown() and self.sortIndicatorSection() == logical_index:
            opt.sortIndicator = QStyleOptionHeader.SortDown if self.sortIndicatorOrder() == Qt.AscendingOrder else QStyleOptionHeader.SortUp
        opt.text = opt.fontMetrics.elidedText(opt.text, Qt.ElideRight, rect.width() - 4)
        if self.isEnabled():
            opt.state |= QStyle.State_Enabled
            if self.window().isActiveWindow():
                opt.state |= QStyle.State_Active
                if self.hover == logical_index:
                    opt.state |= QStyle.State_MouseOver
        sm = self.selectionModel()
        if opt.orientation == Qt.Vertical:
            try:
                opt.icon = model.headerData(logical_index, opt.orientation, Qt.DecorationRole)
                opt.iconAlignment = Qt.AlignVCenter
            except (IndexError, ValueError, TypeError):
                pass
            if sm.isRowSelected(logical_index, QModelIndex()):
                opt.state |= QStyle.State_Sunken

        painter.save()
        if (
                (opt.orientation == Qt.Horizontal and sm.currentIndex().column() == logical_index) or
                (opt.orientation == Qt.Vertical and sm.currentIndex().row() == logical_index)):
            painter.setFont(self.current_font)
        self.style().drawControl(QStyle.CE_Header, opt, painter, self)
        painter.restore()
Exemple #18
0
class StatusBar(QStatusBar):  # {{{

    def __init__(self, parent=None):
        QStatusBar.__init__(self, parent)
        self.default_message = __appname__ + ' ' + _('version') + ' ' + \
                __version__ + ' ' + _('created by Kovid Goyal')
        self.device_string = ''
        self._font = QFont()
        self._font.setBold(True)
        self.setFont(self._font)

        self.w = QLabel(self.default_message)
        self.w.setFont(self._font)
        self.addWidget(self.w)
Exemple #19
0
 def data(self, index, role):
     try:
         widget = self.widgets[index.row()]
     except:
         return None
     if role == Qt.DisplayRole:
         return (widget.config_title())
     if role == Qt.DecorationRole:
         return (widget.config_icon())
     if role == Qt.FontRole:
         f = QFont()
         f.setBold(True)
         return (f)
     return None
Exemple #20
0
class RatingDelegate(QStyledItemDelegate, UpdateEditorGeometry):  # {{{

    def __init__(self, *args, **kwargs):
        QStyledItemDelegate.__init__(self, *args, **kwargs)
        self.table_widget = args[0]
        self.rf = QFont(rating_font())
        self.em = Qt.ElideMiddle
        delta = 0
        if iswindows and sys.getwindowsversion().major >= 6:
            delta = 2
        self.rf.setPointSize(QFontInfo(QApplication.font()).pointSize()+delta)

    def createEditor(self, parent, option, index):
        sb = QSpinBox(parent)
        sb.setMinimum(0)
        sb.setMaximum(5)
        sb.setSuffix(' ' + _('stars'))
        sb.setSpecialValueText(_('Not rated'))
        return sb

    def get_required_width(self, editor, style, fm):
        val = editor.maximum()
        text = editor.textFromValue(val) + editor.suffix()
        srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignLeft, False,
                                   text + u'M')
        return srect.width()

    def displayText(self, value, locale):
        r = int(value)
        if r < 0 or r > 5:
            r = 0
        return u'\u2605'*r

    def setEditorData(self, editor, index):
        if check_key_modifier(Qt.ControlModifier):
            val = 0
        else:
            val = index.data(Qt.EditRole)
        editor.setValue(val)

    def sizeHint(self, option, index):
        option.font = self.rf
        option.textElideMode = self.em
        return QStyledItemDelegate.sizeHint(self, option, index)

    def paint(self, painter, option, index):
        option.font = self.rf
        option.textElideMode = self.em
        return QStyledItemDelegate.paint(self, painter, option, index)
Exemple #21
0
    def populate(self, phrase, ts, process_space=True):
        phrase_pos = 0
        processed = False
        matches = self.__class__.whitespace.finditer(phrase)
        font = QFont(ts.font)
        if self.valign is not None:
            font.setPixelSize(font.pixelSize()/1.5)
        fm = QFontMetrics(font)
        single_space_width = fm.width(' ')
        height, descent = fm.height(), fm.descent()
        for match in matches:
            processed = True
            left, right = match.span()
            if not process_space:
                right = left
            space_width = single_space_width * (right-left)
            word = phrase[phrase_pos:left]
            width = fm.width(word)
            if self.current_width + width < self.line_length:
                self.commit(word, width, height, descent, ts, font)
                if space_width > 0 and self.current_width + space_width < self.line_length:
                    self.add_space(space_width)
                phrase_pos = right
                continue

            # Word doesn't fit on line
            if self.hyphenate and len(word) > 3:
                tokens = hyphenate_word(word)
                for i in range(len(tokens)-2, -1, -1):
                    word = ''.join(tokens[0:i+1])+'-'
                    width = fm.width(word)
                    if self.current_width + width < self.line_length:
                        self.commit(word, width, height, descent, ts, font)
                        return phrase_pos + len(word)-1, True
            if self.current_width < 5:  # Force hyphenation as word is longer than line
                for i in range(len(word)-5, 0, -5):
                    part = word[:i] + '-'
                    width = fm.width(part)
                    if self.current_width + width < self.line_length:
                        self.commit(part, width, height, descent, ts, font)
                        return phrase_pos + len(part)-1, True
            # Failed to add word.
            return phrase_pos, True

        if not processed:
            return self.populate(phrase+' ', ts, False)

        return phrase_pos, False
Exemple #22
0
 def __init__(self, spine, toc, depth, all_items, parent=None):
     text = toc.text
     if text:
         text = re.sub(r'\s', ' ', text)
     self.title = text
     self.parent = parent
     QStandardItem.__init__(self, text if text else '')
     self.abspath = toc.abspath if toc.href else None
     self.fragment = toc.fragment
     all_items.append(self)
     self.emphasis_font = QFont(self.font())
     self.emphasis_font.setBold(True), self.emphasis_font.setItalic(True)
     self.normal_font = self.font()
     for t in toc:
         self.appendRow(TOCItem(spine, t, depth+1, all_items, parent=self))
     self.setFlags(Qt.ItemIsEnabled)
     self.is_current_search_result = False
     spos = 0
     for i, si in enumerate(spine):
         if si == self.abspath:
             spos = i
             break
     am = {}
     if self.abspath is not None:
         try:
             am = getattr(spine[i], 'anchor_map', {})
         except UnboundLocalError:
             # Spine was empty?
             pass
     frag = self.fragment if (self.fragment and self.fragment in am) else None
     self.starts_at = spos
     self.start_anchor = frag
     self.start_src_offset = am.get(frag, 0)
     self.depth = depth
     self.is_being_viewed = False
Exemple #23
0
 def __init__(self, *args):
     QHeaderView.__init__(self, *args)
     self.hover = -1
     self.current_font = QFont(self.font())
     self.current_font.setBold(True)
     self.current_font.setItalic(True)
     self.fm = QFontMetrics(self.current_font)
Exemple #24
0
 def apply_theme(self, theme):
     self.theme = theme
     pal = self.palette()
     pal.setColor(pal.Base, theme_color(theme, 'Normal', 'bg'))
     pal.setColor(pal.AlternateBase, theme_color(theme, 'CursorLine', 'bg'))
     pal.setColor(pal.Text, theme_color(theme, 'Normal', 'fg'))
     pal.setColor(pal.Highlight, theme_color(theme, 'Visual', 'bg'))
     pal.setColor(pal.HighlightedText, theme_color(theme, 'Visual', 'fg'))
     self.setPalette(pal)
     self.tooltip_palette = pal = QPalette()
     pal.setColor(pal.ToolTipBase, theme_color(theme, 'Tooltip', 'bg'))
     pal.setColor(pal.ToolTipText, theme_color(theme, 'Tooltip', 'fg'))
     self.line_number_palette = pal = QPalette()
     pal.setColor(pal.Base, theme_color(theme, 'LineNr', 'bg'))
     pal.setColor(pal.Text, theme_color(theme, 'LineNr', 'fg'))
     pal.setColor(pal.BrightText, theme_color(theme, 'LineNrC', 'fg'))
     self.match_paren_format = theme_format(theme, 'MatchParen')
     font = self.font()
     ff = tprefs['editor_font_family']
     if ff is None:
         ff = default_font_family()
     font.setFamily(ff)
     font.setPointSize(tprefs['editor_font_size'])
     self.tooltip_font = QFont(font)
     self.tooltip_font.setPointSize(font.pointSize() - 1)
     self.setFont(font)
     self.highlighter.apply_theme(theme)
     w = self.fontMetrics()
     self.number_width = max(map(lambda x:w.width(str(x)), xrange(10)))
     self.size_hint = QSize(self.expected_geometry[0] * w.averageCharWidth(), self.expected_geometry[1] * w.height())
     self.highlight_color = theme_color(theme, 'HighlightRegion', 'bg')
     self.highlight_cursor_line()
Exemple #25
0
 def __init__(self, accounts, subjects, aliases={}):
     QAbstractTableModel.__init__(self)
     self.accounts = accounts
     self.subjects = subjects
     self.aliases = aliases
     self.account_order = sorted(self.accounts.keys())
     self.headers = map(unicode, [_("Email"), _("Formats"), _("Subject"), _("Auto send"), _("Alias")])
     self.default_font = QFont()
     self.default_font.setBold(True)
     self.default_font = self.default_font
     self.tooltips = [None] + list(
         map(
             unicode,
             map(
                 textwrap.fill,
                 [
                     _("Formats to email. The first matching format will be sent."),
                     _(
                         "Subject of the email to use when sending. When left blank "
                         "the title will be used for the subject. Also, the same "
                         'templates used for "Save to disk" such as {title} and '
                         "{author_sort} can be used here."
                     ),
                     "<p>"
                     + _(
                         "If checked, downloaded news will be automatically "
                         "mailed <br>to this email address "
                         "(provided it is in one of the listed formats)."
                     ),
                     _("Friendly name to use for this email address"),
                 ],
             ),
         )
     )
Exemple #26
0
 def __init__(self, accounts, subjects, aliases={}, tags={}):
     QAbstractTableModel.__init__(self)
     self.accounts = accounts
     self.subjects = subjects
     self.aliases = aliases
     self.tags = tags
     self.sorted_on = (0, True)
     self.account_order = self.accounts.keys()
     self.do_sort()
     self.headers  = map(unicode, [_('Email'), _('Formats'), _('Subject'),
         _('Auto send'), _('Alias'), _('Auto send only tags')])
     self.default_font = QFont()
     self.default_font.setBold(True)
     self.default_font = (self.default_font)
     self.tooltips =[None] + list(map(unicode, map(textwrap.fill,
         [_('Formats to email. The first matching format will be sent.'),
          _('Subject of the email to use when sending. When left blank '
            'the title will be used for the subject. Also, the same '
            'templates used for "Save to disk" such as {title} and '
            '{author_sort} can be used here.'),
          '<p>'+_('If checked, downloaded news will be automatically '
                  'mailed to this email address '
                  '(provided it is in one of the listed formats and has not been filtered by tags).'),
          _('Friendly name to use for this email address'),
          _('If specified, only news with one of these tags will be sent to'
            ' this email address. All news downloads have their title as a'
            ' tag, so you can use this to easily control which news downloads'
            ' are sent to this email address.')
          ])))
Exemple #27
0
 def __init__(self, category, builtin, custom, scheduler_config, parent):
     NewsTreeItem.__init__(self, builtin, custom, scheduler_config, parent)
     self.category = category
     self.cdata = get_language(self.category)
     self.bold_font = QFont()
     self.bold_font.setBold(True)
     self.bold_font = self.bold_font
Exemple #28
0
    def __init__(self, args, ids, db, refresh_books, cc_widgets, s_r_func, do_sr, sr_calls, parent=None, window_title=_('Working')):
        QDialog.__init__(self, parent)

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

        self.msg = QLabel(_('Processing %d books, please wait...') % len(ids))
        self.font = QFont()
        self.font.setPointSize(self.font.pointSize() + 8)
        self.msg.setFont(self.font)
        self.pi = ProgressIndicator(self)
        self.pi.setDisplaySize(100)
        self._layout.addWidget(self.pi, 0, Qt.AlignHCenter)
        self._layout.addSpacing(15)
        self._layout.addWidget(self.msg, 0, Qt.AlignHCenter)
        self.setWindowTitle(window_title + '...')
        self.setMinimumWidth(200)
        self.resize(self.sizeHint())
        self.error = None
        self.all_done.connect(self.on_all_done, type=Qt.QueuedConnection)
        self.args, self.ids = args, ids
        self.db, self.cc_widgets = db, cc_widgets
        self.s_r_func = FunctionDispatcher(s_r_func)
        self.do_sr = do_sr
        self.sr_calls = sr_calls
        self.refresh_books = refresh_books
Exemple #29
0
 def apply_theme(self, theme):
     self.theme = theme
     pal = self.palette()
     pal.setColor(pal.Base, theme_color(theme, "Normal", "bg"))
     pal.setColor(pal.AlternateBase, theme_color(theme, "CursorLine", "bg"))
     pal.setColor(pal.Text, theme_color(theme, "Normal", "fg"))
     pal.setColor(pal.Highlight, theme_color(theme, "Visual", "bg"))
     pal.setColor(pal.HighlightedText, theme_color(theme, "Visual", "fg"))
     self.setPalette(pal)
     self.tooltip_palette = pal = QPalette()
     pal.setColor(pal.ToolTipBase, theme_color(theme, "Tooltip", "bg"))
     pal.setColor(pal.ToolTipText, theme_color(theme, "Tooltip", "fg"))
     self.line_number_palette = pal = QPalette()
     pal.setColor(pal.Base, theme_color(theme, "LineNr", "bg"))
     pal.setColor(pal.Text, theme_color(theme, "LineNr", "fg"))
     pal.setColor(pal.BrightText, theme_color(theme, "LineNrC", "fg"))
     self.match_paren_format = theme_format(theme, "MatchParen")
     font = self.font()
     ff = tprefs["editor_font_family"]
     if ff is None:
         ff = default_font_family()
     font.setFamily(ff)
     font.setPointSize(tprefs["editor_font_size"])
     self.tooltip_font = QFont(font)
     self.tooltip_font.setPointSize(font.pointSize() - 1)
     self.setFont(font)
     self.highlighter.apply_theme(theme)
     w = self.fontMetrics()
     self.number_width = max(map(lambda x: w.width(str(x)), xrange(10)))
     self.size_hint = QSize(self.expected_geometry[0] * w.averageCharWidth(), self.expected_geometry[1] * w.height())
     self.highlight_color = theme_color(theme, "HighlightRegion", "bg")
     self.highlight_cursor_line()
     self.completion_popup.clear_caches(), self.completion_popup.update()
Exemple #30
0
    def __init__(self, name, plugins, gui_name, parent=None):
        QWidget.__init__(self, parent)
        self._layout = QVBoxLayout()
        self.setLayout(self._layout)
        self.label = QLabel(gui_name)
        self.sep = QFrame(self)
        self.bf = QFont()
        self.bf.setBold(True)
        self.label.setFont(self.bf)
        self.sep.setFrameShape(QFrame.HLine)
        self._layout.addWidget(self.label)
        self._layout.addWidget(self.sep)

        self.plugins = plugins

        self.bar = QToolBar(self)
        self.bar.setStyleSheet(
                'QToolBar { border: none; background: none }')
        self.bar.setIconSize(QSize(32, 32))
        self.bar.setMovable(False)
        self.bar.setFloatable(False)
        self.bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self._layout.addWidget(self.bar)
        self.actions = []
        for p in plugins:
            target = partial(self.triggered, p)
            ac = self.bar.addAction(QIcon(p.icon), p.gui_name, target)
            ac.setToolTip(textwrap.fill(p.description))
            ac.setWhatsThis(textwrap.fill(p.description))
            ac.setStatusTip(p.description)
            self.actions.append(ac)
            w = self.bar.widgetForAction(ac)
            w.setCursor(Qt.PointingHandCursor)
            w.setAutoRaise(True)
            w.setMinimumWidth(100)
Exemple #31
0
 def set_window_title(self):
     db = self.current_db
     restrictions = [
         x for x in (db.data.get_base_restriction_name(),
                     db.data.get_search_restriction_name()) if x
     ]
     restrictions = ' :: '.join(restrictions)
     font = QFont()
     if restrictions:
         restrictions = ' :: ' + restrictions
         font.setBold(True)
         font.setItalic(True)
     self.virtual_library.setFont(font)
     title = u'{0} - || {1}{2} ||'.format(
         __appname__, self.iactions['Choose Library'].library_name(),
         restrictions)
     self.setWindowTitle(title)
Exemple #32
0
 def key_press_event(self, ev, which=0):
     code = ev.key()
     if self.capture == 0 or code in (0, Qt.Key_unknown, Qt.Key_Shift,
                                      Qt.Key_Control, Qt.Key_Alt,
                                      Qt.Key_Meta, Qt.Key_AltGr,
                                      Qt.Key_CapsLock, Qt.Key_NumLock,
                                      Qt.Key_ScrollLock):
         return QWidget.keyPressEvent(self, ev)
     button = getattr(self, 'button%d' % which)
     font = QFont()
     button.setFont(font)
     sequence = QKeySequence(code
                             | (int(ev.modifiers()) & ~Qt.KeypadModifier))
     button.setText(sequence.toString(QKeySequence.NativeText))
     self.capture = 0
     setattr(self, 'shortcut%d' % which, sequence)
     dup_desc = self.dup_check(sequence, self.key)
     if dup_desc is not None:
         error_dialog(self,
                      _('Already assigned'),
                      unicode(sequence.toString(QKeySequence.NativeText)) +
                      ' ' + _('already assigned to') + ' ' + dup_desc,
                      show=True)
         self.clear_clicked(which=which)
Exemple #33
0
    def drawTowerPrices(self):
        font = QFont("Arial",15)
        arrowtower = QLabel("50")
        arrowtower.setFont(font)
        arrowtower.move(QPoint(650,70))
        self.scene.addWidget(arrowtower)

        guntower = QLabel("100")
        guntower.setFont(font)
        guntower.move(QPoint(650,150))
        self.scene.addWidget(guntower)

        lasertower = QLabel("500")
        lasertower.setFont(font)
        lasertower.move(QPoint(650,230))
        self.scene.addWidget(lasertower)
        
        

        
        
            

        
Exemple #34
0
 def set_value(self, g, val):
     from calibre.gui2.convert.xpath_wizard import XPathEdit
     from calibre.gui2.convert.regex_builder import RegexEdit
     from calibre.gui2.widgets import EncodingComboBox
     if self.set_value_handler(g, val):
         return
     if isinstance(g, (QSpinBox, QDoubleSpinBox)):
         g.setValue(val)
     elif isinstance(g, (QLineEdit, QTextEdit, QPlainTextEdit)):
         if not val:
             val = ''
         getattr(g, 'setPlainText', getattr(g, 'setText', None))(val)
         getattr(g, 'setCursorPosition', lambda x: x)(0)
     elif isinstance(g, QFontComboBox):
         g.setCurrentFont(QFont(val or ''))
     elif isinstance(g, FontFamilyChooser):
         g.font_family = val
     elif isinstance(g, EncodingComboBox):
         if val:
             g.setEditText(val)
         else:
             g.setCurrentIndex(0)
     elif isinstance(g, QComboBox) and val:
         idx = g.findText(val, Qt.MatchFixedString)
         if idx < 0:
             g.addItem(val)
             idx = g.findText(val, Qt.MatchFixedString)
         g.setCurrentIndex(idx)
     elif isinstance(g, QCheckBox):
         g.setCheckState(Qt.Checked if bool(val) else Qt.Unchecked)
     elif isinstance(g, (XPathEdit, RegexEdit)):
         g.edit.setText(val if val else '')
     else:
         raise Exception('Can\'t set value %s in %s'%(repr(val),
             unicode(g.objectName())))
     self.post_set_value(g, val)
    def __init__(self, parent=None):
        super().__init__(parent)

        font = QFont('Lucida Console', 10)

        self.input_prompt_label = QLabel()
        self.input_prompt_label.setFont(font)
        self.set_continue_input_prompt(False)

        self.command_line = QLineEdit()
        self.command_line.setFont(font)
        self.command_line.returnPressed.connect(self.on_command_line_return_pressed)

        self.output_widget = QTextEdit()
        self.setFont(font)

        layout = QVBoxLayout()
        layout.addWidget(self.output_widget)

        command_line_layout = QFormLayout()
        command_line_layout.addRow(self.input_prompt_label, self.command_line)
        layout.addLayout(command_line_layout)

        self.setLayout(layout)
    def __init__(self):
        super().__init__()

        self.label = QLabel()
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setFont(QFont('Courier', 25))

        def loop():
            i = 0

            while True:
                self.label.setText(str(i))

                i += 1
                time.sleep(1)

        class Thread(QThread):
            def run(self):
                loop()

        self.thread = Thread()
        self.thread.start()

        self.setCentralWidget(self.label)
Exemple #37
0
    def __init__(self, admin: bool):
        super().__init__()

        grid = QGridLayout()
        self.setLayout(grid)

        email_label = QLabel("Email:")
        email_label.setFont(QFont("Segeo UI", 20))
        grid.addWidget(email_label)

        self.email_entry = QLineEdit()
        self.email_entry.setFont(QFont("Segeo UI", 20))
        grid.addWidget(self.email_entry)

        password_label = QLabel("Password:"******"Segeo UI", 20))
        grid.addWidget(password_label)

        self.password_entry = QLineEdit()
        self.password_entry.setFont(QFont("Segeo UI", 20))
        self.password_entry.setEchoMode(QLineEdit.Password)
        grid.addWidget(self.password_entry)

        repeat_password_label = QLabel("Repeat Password:"******"Segeo UI", 20))
        grid.addWidget(repeat_password_label)

        self.repeat_password_entry = QLineEdit()
        self.repeat_password_entry.setFont(QFont("Segeo UI", 20))
        self.repeat_password_entry.setEchoMode(QLineEdit.Password)
        grid.addWidget(self.repeat_password_entry)

        create_account_btn = QPushButton(text="Create Account")
        create_account_btn.setFont(QFont("Segeo UI", 20))
        create_account_btn.clicked.connect(lambda: self.create_account(admin))
        grid.addWidget(create_account_btn)
Exemple #38
0
def generate_masthead(title,
                      output_path=None,
                      width=600,
                      height=60,
                      as_qimage=False,
                      font_family=None):
    init_environment()
    font_family = font_family or cprefs[
        'title_font_family'] or 'Liberation Serif'
    img = QImage(width, height, QImage.Format_ARGB32)
    img.fill(Qt.white)
    p = QPainter(img)
    f = QFont(font_family)
    f.setPixelSize((height * 3) // 4), f.setBold(True)
    p.setFont(f)
    p.drawText(img.rect(), Qt.AlignLeft | Qt.AlignVCenter, sanitize(title))
    p.end()
    if as_qimage:
        return img
    data = pixmap_to_data(img)
    if output_path is None:
        return data
    with open(output_path, 'wb') as f:
        f.write(data)
Exemple #39
0
 def generate_buttons(self):
     self.buttons = []
     self.GameName.setText(str(self.N)+'-Puzzle')
     width = int(m.sqrt(self.N+1))
     for i in range(width):
         for j in range(width):
             button = QtWidgets.QPushButton(self.widget)
             button.setMaximumHeight(120)
             button.setMaximumWidth(120)
             button.setObjectName(str(i*width+j))
             
             font = QFont()
             font.setPointSize(14)
             font.setBold(1)
             button.setFont(font)
             
             
             button.setText(str(state[i*width+j]))
             button.clicked.connect(lambda x:self.push_button(int(self.sender().objectName())))
             
             self.buttons.append(button)
             self.ButtonLayout.addWidget(button, i, j)
Exemple #40
0
    def __init__(self):
        super(ModelTrain, self).__init__()
        self.setObjectName('ModelTrain')
        self.setStyleSheet(
            GetQssFile.readQss('../resource/qss/modelTrain.qss'))

        self.log = logging.getLogger('StarCraftII')

        # font
        font = QFont()
        font.setWeight(50)
        font.setPixelSize(15)

        # set widget of layout
        self.frame = QFrame(self)
        self.frame.setGeometry(QDesktopWidget().screenGeometry())
        self.main_layout = QHBoxLayout(self)
        self.main_layout.setSpacing(20)
        self.setLayout(self.main_layout)

        # model tarin
        self.modelTrain = QPushButton()
        self.modelTrain.setObjectName('modelTrain')
        self.modelTrainLabel = QLabel('model train')
        self.modelTrainLabel.setFont(font)
        self.modelTrain_layout = QVBoxLayout()
        self.modelTrain_layout.addWidget(self.modelTrain,
                                         alignment=Qt.AlignCenter)
        self.modelTrain_layout.addWidget(self.modelTrainLabel,
                                         alignment=Qt.AlignCenter)
        self.main_layout.addLayout(self.modelTrain_layout)

        # a description dialog
        self.dialog = None
        # add stretch
        self.main_layout.addStretch(1)

        # initialization
        self.initUI()
Exemple #41
0
 def __init__(self, *args, **kwargs):
     QStyledItemDelegate.__init__(self, *args, **kwargs)
     self.old_look = gprefs['tag_browser_old_look']
     self.rating_pat = re.compile(r'[%s]' % rating_to_stars(3, True))
     self.rating_font = QFont(rating_font())
Exemple #42
0
 def family_setter(w, val):
     w.setCurrentFont(QFont(val))
Exemple #43
0
class TextEdit(PlainTextEdit):

    link_clicked = pyqtSignal(object)
    smart_highlighting_updated = pyqtSignal()

    def __init__(self, parent=None, expected_geometry=(100, 50)):
        PlainTextEdit.__init__(self, parent)
        self.snippet_manager = SnippetManager(self)
        self.completion_popup = CompletionPopup(self)
        self.request_completion = self.completion_doc_name = None
        self.clear_completion_cache_timer = t = QTimer(self)
        t.setInterval(5000), t.timeout.connect(
            self.clear_completion_cache), t.setSingleShot(True)
        self.textChanged.connect(t.start)
        self.last_completion_request = -1
        self.gutter_width = 0
        self.tw = 2
        self.expected_geometry = expected_geometry
        self.saved_matches = {}
        self.syntax = None
        self.smarts = NullSmarts(self)
        self.current_cursor_line = None
        self.current_search_mark = None
        self.smarts_highlight_timer = t = QTimer()
        t.setInterval(750), t.setSingleShot(True), t.timeout.connect(
            self.update_extra_selections)
        self.highlighter = SyntaxHighlighter()
        self.line_number_area = LineNumbers(self)
        self.apply_settings()
        self.setMouseTracking(True)
        self.cursorPositionChanged.connect(self.highlight_cursor_line)
        self.blockCountChanged[int].connect(self.update_line_number_area_width)
        self.updateRequest.connect(self.update_line_number_area)

    def get_droppable_files(self, md):
        def is_mt_ok(mt):
            return self.syntax == 'html' and (mt in OEB_DOCS
                                              or mt in OEB_STYLES
                                              or mt.startswith('image/'))

        if md.hasFormat(CONTAINER_DND_MIMETYPE):
            for line in bytes(md.data(CONTAINER_DND_MIMETYPE)).decode(
                    'utf-8').splitlines():
                mt = current_container().mime_map.get(
                    line, 'application/octet-stream')
                if is_mt_ok(mt):
                    yield line, mt, True
            return
        for qurl in md.urls():
            if qurl.isLocalFile() and os.access(qurl.toLocalFile(), os.R_OK):
                path = qurl.toLocalFile()
                mt = guess_type(path)
                if is_mt_ok(mt):
                    yield path, mt, False

    def canInsertFromMimeData(self, md):
        if md.hasText() or (md.hasHtml()
                            and self.syntax == 'html') or md.hasImage():
            return True
        elif tuple(self.get_droppable_files(md)):
            return True
        return False

    def insertFromMimeData(self, md):
        files = tuple(self.get_droppable_files(md))
        base = self.highlighter.doc_name or None

        def get_name(name):
            return get_recommended_folders(current_container(),
                                           (name, ))[name] + '/' + name

        def get_href(name):
            return current_container().name_to_href(name, base)

        def insert_text(text):
            c = self.textCursor()
            c.insertText(text)
            self.setTextCursor(c)

        def add_file(name, data, mt=None):
            from calibre.gui2.tweak_book.boss import get_boss
            name = current_container().add_file(name,
                                                data,
                                                media_type=mt,
                                                modify_name_if_needed=True)
            get_boss().refresh_file_list()
            return name

        if files:
            for path, mt, is_name in files:
                if is_name:
                    name = path
                else:
                    name = get_name(os.path.basename(path))
                    with lopen(path, 'rb') as f:
                        name = add_file(name, f.read(), mt)
                href = get_href(name)
                if mt.startswith('image/'):
                    self.insert_image(href)
                elif mt in OEB_STYLES:
                    insert_text(
                        '<link href="{}" rel="stylesheet" type="text/css"/>'.
                        format(href))
                elif mt in OEB_DOCS:
                    self.insert_hyperlink(href, name)
            return
        if md.hasImage():
            img = md.imageData()
            if img.isValid():
                data = image_to_data(img, fmt='PNG')
                name = add_file(get_name('dropped_image.png', data))
                self.insert_image(get_href(name))
                return
        if md.hasHtml():
            insert_text(md.html())
            return
        if md.hasText():
            return insert_text(md.text())

    @dynamic_property
    def is_modified(self):
        ''' True if the document has been modified since it was loaded or since
        the last time is_modified was set to False. '''
        def fget(self):
            return self.document().isModified()

        def fset(self, val):
            self.document().setModified(bool(val))

        return property(fget=fget, fset=fset)

    def sizeHint(self):
        return self.size_hint

    def apply_settings(self, prefs=None, dictionaries_changed=False):  # {{{
        prefs = prefs or tprefs
        self.setAcceptDrops(prefs.get('editor_accepts_drops', True))
        self.setLineWrapMode(
            QPlainTextEdit.WidgetWidth
            if prefs['editor_line_wrap'] else QPlainTextEdit.NoWrap)
        theme = get_theme(prefs['editor_theme'])
        self.apply_theme(theme)
        w = self.fontMetrics()
        self.space_width = w.width(' ')
        self.tw = self.smarts.override_tab_stop_width if self.smarts.override_tab_stop_width is not None else prefs[
            'editor_tab_stop_width']
        self.setTabStopWidth(self.tw * self.space_width)
        if dictionaries_changed:
            self.highlighter.rehighlight()

    def apply_theme(self, theme):
        self.theme = theme
        pal = self.palette()
        pal.setColor(pal.Base, theme_color(theme, 'Normal', 'bg'))
        pal.setColor(pal.AlternateBase, theme_color(theme, 'CursorLine', 'bg'))
        pal.setColor(pal.Text, theme_color(theme, 'Normal', 'fg'))
        pal.setColor(pal.Highlight, theme_color(theme, 'Visual', 'bg'))
        pal.setColor(pal.HighlightedText, theme_color(theme, 'Visual', 'fg'))
        self.setPalette(pal)
        self.tooltip_palette = pal = QPalette()
        pal.setColor(pal.ToolTipBase, theme_color(theme, 'Tooltip', 'bg'))
        pal.setColor(pal.ToolTipText, theme_color(theme, 'Tooltip', 'fg'))
        self.line_number_palette = pal = QPalette()
        pal.setColor(pal.Base, theme_color(theme, 'LineNr', 'bg'))
        pal.setColor(pal.Text, theme_color(theme, 'LineNr', 'fg'))
        pal.setColor(pal.BrightText, theme_color(theme, 'LineNrC', 'fg'))
        self.match_paren_format = theme_format(theme, 'MatchParen')
        font = self.font()
        ff = tprefs['editor_font_family']
        if ff is None:
            ff = default_font_family()
        font.setFamily(ff)
        font.setPointSize(tprefs['editor_font_size'])
        self.tooltip_font = QFont(font)
        self.tooltip_font.setPointSize(font.pointSize() - 1)
        self.setFont(font)
        self.highlighter.apply_theme(theme)
        w = self.fontMetrics()
        self.number_width = max(map(lambda x: w.width(str(x)), xrange(10)))
        self.size_hint = QSize(
            self.expected_geometry[0] * w.averageCharWidth(),
            self.expected_geometry[1] * w.height())
        self.highlight_color = theme_color(theme, 'HighlightRegion', 'bg')
        self.highlight_cursor_line()
        self.completion_popup.clear_caches(), self.completion_popup.update()

    # }}}

    def load_text(self,
                  text,
                  syntax='html',
                  process_template=False,
                  doc_name=None):
        self.syntax = syntax
        self.highlighter = get_highlighter(syntax)()
        self.highlighter.apply_theme(self.theme)
        self.highlighter.set_document(self.document(), doc_name=doc_name)
        sclass = get_smarts(syntax)
        if sclass is not None:
            self.smarts = sclass(self)
            if self.smarts.override_tab_stop_width is not None:
                self.tw = self.smarts.override_tab_stop_width
                self.setTabStopWidth(self.tw * self.space_width)
        self.setPlainText(unicodedata.normalize('NFC', unicode(text)))
        if process_template and QPlainTextEdit.find(self, '%CURSOR%'):
            c = self.textCursor()
            c.insertText('')

    def change_document_name(self, newname):
        self.highlighter.doc_name = newname
        self.highlighter.rehighlight(
        )  # Ensure links are checked w.r.t. the new name correctly

    def replace_text(self, text):
        c = self.textCursor()
        pos = c.position()
        c.beginEditBlock()
        c.clearSelection()
        c.select(c.Document)
        c.insertText(unicodedata.normalize('NFC', text))
        c.endEditBlock()
        c.setPosition(min(pos, len(text)))
        self.setTextCursor(c)
        self.ensureCursorVisible()

    def simple_replace(self, text, cursor=None):
        c = cursor or self.textCursor()
        c.insertText(unicodedata.normalize('NFC', text))
        self.setTextCursor(c)

    def go_to_line(self, lnum, col=None):
        lnum = max(1, min(self.blockCount(), lnum))
        c = self.textCursor()
        c.clearSelection()
        c.movePosition(c.Start)
        c.movePosition(c.NextBlock, n=lnum - 1)
        c.movePosition(c.StartOfLine)
        c.movePosition(c.EndOfLine, c.KeepAnchor)
        text = unicode(c.selectedText()).rstrip('\0')
        if col is None:
            c.movePosition(c.StartOfLine)
            lt = text.lstrip()
            if text and lt and lt != text:
                c.movePosition(c.NextWord)
        else:
            c.setPosition(c.block().position() + col)
            if c.blockNumber() + 1 > lnum:
                # We have moved past the end of the line
                c.setPosition(c.block().position())
                c.movePosition(c.EndOfBlock)
        self.setTextCursor(c)
        self.ensureCursorVisible()

    def update_extra_selections(self, instant=True):
        sel = []
        if self.current_cursor_line is not None:
            sel.append(self.current_cursor_line)
        if self.current_search_mark is not None:
            sel.append(self.current_search_mark)
        if instant and not self.highlighter.has_requests and self.smarts is not None:
            sel.extend(self.smarts.get_extra_selections(self))
            self.smart_highlighting_updated.emit()
        else:
            self.smarts_highlight_timer.start()
        self.setExtraSelections(sel)

    # Search and replace {{{
    def mark_selected_text(self):
        sel = QTextEdit.ExtraSelection()
        sel.format.setBackground(self.highlight_color)
        sel.cursor = self.textCursor()
        if sel.cursor.hasSelection():
            self.current_search_mark = sel
            c = self.textCursor()
            c.clearSelection()
            self.setTextCursor(c)
        else:
            self.current_search_mark = None
        self.update_extra_selections()

    def find_in_marked(self, pat, wrap=False, save_match=None):
        if self.current_search_mark is None:
            return False
        csm = self.current_search_mark.cursor
        reverse = pat.flags & regex.REVERSE
        c = self.textCursor()
        c.clearSelection()
        m_start = min(csm.position(), csm.anchor())
        m_end = max(csm.position(), csm.anchor())
        if c.position() < m_start:
            c.setPosition(m_start)
        if c.position() > m_end:
            c.setPosition(m_end)
        pos = m_start if reverse else m_end
        if wrap:
            pos = m_end if reverse else m_start
        c.setPosition(pos, c.KeepAnchor)
        raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                '\n').rstrip('\0')
        m = pat.search(raw)
        if m is None:
            return False
        start, end = m.span()
        if start == end:
            return False
        if wrap:
            if reverse:
                textpos = c.anchor()
                start, end = textpos + end, textpos + start
            else:
                start, end = m_start + start, m_start + end
        else:
            if reverse:
                start, end = m_start + end, m_start + start
            else:
                start, end = c.anchor() + start, c.anchor() + end

        c.clearSelection()
        c.setPosition(start)
        c.setPosition(end, c.KeepAnchor)
        self.setTextCursor(c)
        # Center search result on screen
        self.centerCursor()
        if save_match is not None:
            self.saved_matches[save_match] = (pat, m)
        return True

    def all_in_marked(self, pat, template=None):
        if self.current_search_mark is None:
            return 0
        c = self.current_search_mark.cursor
        raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                '\n').rstrip('\0')
        if template is None:
            count = len(pat.findall(raw))
        else:
            from calibre.gui2.tweak_book.function_replace import Function
            repl_is_func = isinstance(template, Function)
            if repl_is_func:
                template.init_env()
            raw, count = pat.subn(template, raw)
            if repl_is_func:
                from calibre.gui2.tweak_book.search import show_function_debug_output
                if getattr(template.func, 'append_final_output_to_marked',
                           False):
                    retval = template.end()
                    if retval:
                        raw += unicode(retval)
                else:
                    template.end()
                show_function_debug_output(template)
            if count > 0:
                start_pos = min(c.anchor(), c.position())
                c.insertText(raw)
                end_pos = max(c.anchor(), c.position())
                c.setPosition(start_pos), c.setPosition(end_pos, c.KeepAnchor)
                self.update_extra_selections()
        return count

    def smart_comment(self):
        from calibre.gui2.tweak_book.editor.comments import smart_comment
        smart_comment(self, self.syntax)

    def sort_css(self):
        from calibre.gui2.dialogs.confirm_delete import confirm
        if confirm(_(
                'Sorting CSS rules can in rare cases change the effective styles applied to the book.'
                ' Are you sure you want to proceed?'),
                   'edit-book-confirm-sort-css',
                   parent=self,
                   config_set=tprefs):
            c = self.textCursor()
            c.beginEditBlock()
            c.movePosition(c.Start), c.movePosition(c.End, c.KeepAnchor)
            text = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                     '\n').rstrip('\0')
            from calibre.ebooks.oeb.polish.css import sort_sheet
            text = sort_sheet(current_container(), text).cssText
            c.insertText(text)
            c.movePosition(c.Start)
            c.endEditBlock()
            self.setTextCursor(c)

    def find(self,
             pat,
             wrap=False,
             marked=False,
             complete=False,
             save_match=None):
        if marked:
            return self.find_in_marked(pat, wrap=wrap, save_match=save_match)
        reverse = pat.flags & regex.REVERSE
        c = self.textCursor()
        c.clearSelection()
        if complete:
            # Search the entire text
            c.movePosition(c.End if reverse else c.Start)
        pos = c.Start if reverse else c.End
        if wrap and not complete:
            pos = c.End if reverse else c.Start
        c.movePosition(pos, c.KeepAnchor)
        raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                '\n').rstrip('\0')
        m = pat.search(raw)
        if m is None:
            return False
        start, end = m.span()
        if start == end:
            return False
        if wrap and not complete:
            if reverse:
                textpos = c.anchor()
                start, end = textpos + end, textpos + start
        else:
            if reverse:
                # Put the cursor at the start of the match
                start, end = end, start
            else:
                textpos = c.anchor()
                start, end = textpos + start, textpos + end
        c.clearSelection()
        c.setPosition(start)
        c.setPosition(end, c.KeepAnchor)
        self.setTextCursor(c)
        # Center search result on screen
        self.centerCursor()
        if save_match is not None:
            self.saved_matches[save_match] = (pat, m)
        return True

    def find_text(self, pat, wrap=False, complete=False):
        reverse = pat.flags & regex.REVERSE
        c = self.textCursor()
        c.clearSelection()
        if complete:
            # Search the entire text
            c.movePosition(c.End if reverse else c.Start)
        pos = c.Start if reverse else c.End
        if wrap and not complete:
            pos = c.End if reverse else c.Start
        c.movePosition(pos, c.KeepAnchor)
        if hasattr(self.smarts, 'find_text'):
            self.highlighter.join()
            found, start, end = self.smarts.find_text(pat, c)
            if not found:
                return False
        else:
            raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                    '\n').rstrip('\0')
            m = pat.search(raw)
            if m is None:
                return False
            start, end = m.span()
            if start == end:
                return False
        if reverse:
            start, end = end, start
        c.clearSelection()
        c.setPosition(start)
        c.setPosition(end, c.KeepAnchor)
        self.setTextCursor(c)
        # Center search result on screen
        self.centerCursor()
        return True

    def find_spell_word(self,
                        original_words,
                        lang,
                        from_cursor=True,
                        center_on_cursor=True):
        c = self.textCursor()
        c.setPosition(c.position())
        if not from_cursor:
            c.movePosition(c.Start)
        c.movePosition(c.End, c.KeepAnchor)

        def find_first_word(haystack):
            match_pos, match_word = -1, None
            for w in original_words:
                idx = index_of(w, haystack, lang=lang)
                if idx > -1 and (match_pos == -1 or match_pos > idx):
                    match_pos, match_word = idx, w
            return match_pos, match_word

        while True:
            text = unicode(c.selectedText()).rstrip('\0')
            idx, word = find_first_word(text)
            if idx == -1:
                return False
            c.setPosition(c.anchor() + idx)
            c.setPosition(c.position() + string_length(word), c.KeepAnchor)
            if self.smarts.verify_for_spellcheck(c, self.highlighter):
                self.highlighter.join()  # Ensure highlighting is finished
                locale = self.spellcheck_locale_for_cursor(c)
                if not lang or not locale or (locale
                                              and lang == locale.langcode):
                    self.setTextCursor(c)
                    if center_on_cursor:
                        self.centerCursor()
                    return True
            c.setPosition(c.position())
            c.movePosition(c.End, c.KeepAnchor)

        return False

    def find_next_spell_error(self, from_cursor=True):
        c = self.textCursor()
        if not from_cursor:
            c.movePosition(c.Start)
        block = c.block()
        while block.isValid():
            for r in block.layout().additionalFormats():
                if r.format.property(SPELL_PROPERTY):
                    if not from_cursor or block.position(
                    ) + r.start + r.length > c.position():
                        c.setPosition(block.position() + r.start)
                        c.setPosition(c.position() + r.length, c.KeepAnchor)
                        self.setTextCursor(c)
                        return True
            block = block.next()
        return False

    def replace(self, pat, template, saved_match='gui'):
        c = self.textCursor()
        raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR,
                                                '\n').rstrip('\0')
        m = pat.fullmatch(raw)
        if m is None:
            # This can happen if either the user changed the selected text or
            # the search expression uses lookahead/lookbehind operators. See if
            # the saved match matches the currently selected text and
            # use it, if so.
            if saved_match is not None and saved_match in self.saved_matches:
                saved_pat, saved = self.saved_matches.pop(saved_match)
                if saved_pat == pat and saved.group() == raw:
                    m = saved
        if m is None:
            return False
        if callable(template):
            text = template(m)
        else:
            text = m.expand(template)
        c.insertText(text)
        return True

    def go_to_anchor(self, anchor):
        if anchor is TOP:
            c = self.textCursor()
            c.movePosition(c.Start)
            self.setTextCursor(c)
            return True
        base = r'''%%s\s*=\s*['"]{0,1}%s''' % regex.escape(anchor)
        raw = unicode(self.toPlainText())
        m = regex.search(base % 'id', raw)
        if m is None:
            m = regex.search(base % 'name', raw)
        if m is not None:
            c = self.textCursor()
            c.setPosition(m.start())
            self.setTextCursor(c)
            return True
        return False

    # }}}

    # Line numbers and cursor line {{{
    def highlight_cursor_line(self):
        sel = QTextEdit.ExtraSelection()
        sel.format.setBackground(self.palette().alternateBase())
        sel.format.setProperty(QTextFormat.FullWidthSelection, True)
        sel.cursor = self.textCursor()
        sel.cursor.clearSelection()
        self.current_cursor_line = sel
        self.update_extra_selections(instant=False)
        # Update the cursor line's line number in the line number area
        try:
            self.line_number_area.update(0, self.last_current_lnum[0],
                                         self.line_number_area.width(),
                                         self.last_current_lnum[1])
        except AttributeError:
            pass
        block = self.textCursor().block()
        top = int(
            self.blockBoundingGeometry(block).translated(
                self.contentOffset()).top())
        height = int(self.blockBoundingRect(block).height())
        self.line_number_area.update(0, top, self.line_number_area.width(),
                                     height)

    def update_line_number_area_width(self, block_count=0):
        self.gutter_width = self.line_number_area_width()
        self.setViewportMargins(self.gutter_width, 0, 0, 0)

    def line_number_area_width(self):
        digits = 1
        limit = max(1, self.blockCount())
        while limit >= 10:
            limit /= 10
            digits += 1

        return 8 + self.number_width * digits

    def update_line_number_area(self, rect, dy):
        if dy:
            self.line_number_area.scroll(0, dy)
        else:
            self.line_number_area.update(0, rect.y(),
                                         self.line_number_area.width(),
                                         rect.height())
        if rect.contains(self.viewport().rect()):
            self.update_line_number_area_width()

    def resizeEvent(self, ev):
        QPlainTextEdit.resizeEvent(self, ev)
        cr = self.contentsRect()
        self.line_number_area.setGeometry(
            QRect(cr.left(), cr.top(), self.line_number_area_width(),
                  cr.height()))

    def paint_line_numbers(self, ev):
        painter = QPainter(self.line_number_area)
        painter.fillRect(ev.rect(),
                         self.line_number_palette.color(QPalette.Base))

        block = self.firstVisibleBlock()
        num = block.blockNumber()
        top = int(
            self.blockBoundingGeometry(block).translated(
                self.contentOffset()).top())
        bottom = top + int(self.blockBoundingRect(block).height())
        current = self.textCursor().block().blockNumber()
        painter.setPen(self.line_number_palette.color(QPalette.Text))

        while block.isValid() and top <= ev.rect().bottom():
            if block.isVisible() and bottom >= ev.rect().top():
                if current == num:
                    painter.save()
                    painter.setPen(
                        self.line_number_palette.color(QPalette.BrightText))
                    f = QFont(self.font())
                    f.setBold(True)
                    painter.setFont(f)
                    self.last_current_lnum = (top, bottom - top)
                painter.drawText(0, top,
                                 self.line_number_area.width() - 5,
                                 self.fontMetrics().height(), Qt.AlignRight,
                                 str(num + 1))
                if current == num:
                    painter.restore()
            block = block.next()
            top = bottom
            bottom = top + int(self.blockBoundingRect(block).height())
            num += 1

    # }}}

    def override_shortcut(self, ev):
        # Let the global cut/copy/paste/undo/redo shortcuts work, this avoids the nbsp
        # problem as well, since they use the overridden copy() method
        # instead of the one from Qt, and allows proper customization
        # of the shortcuts
        if ev in (QKeySequence.Copy, QKeySequence.Cut, QKeySequence.Paste,
                  QKeySequence.Undo, QKeySequence.Redo):
            ev.ignore()
            return True
        # This is used to convert typed hex codes into unicode
        # characters
        if ev.key() == Qt.Key_X and ev.modifiers() == Qt.AltModifier:
            ev.accept()
            return True
        return PlainTextEdit.override_shortcut(self, ev)

    def text_for_range(self, block, r):
        c = self.textCursor()
        c.setPosition(block.position() + r.start)
        c.setPosition(c.position() + r.length, c.KeepAnchor)
        return unicode(c.selectedText())

    def spellcheck_locale_for_cursor(self, c):
        with store_locale:
            formats = self.highlighter.parse_single_block(c.block())[0]
        pos = c.positionInBlock()
        for r in formats:
            if r.start <= pos <= r.start + r.length and r.format.property(
                    SPELL_PROPERTY):
                return r.format.property(SPELL_LOCALE_PROPERTY)

    def recheck_word(self, word, locale):
        c = self.textCursor()
        c.movePosition(c.Start)
        block = c.block()
        while block.isValid():
            for r in block.layout().additionalFormats():
                if r.format.property(SPELL_PROPERTY) and self.text_for_range(
                        block, r) == word:
                    self.highlighter.reformat_block(block)
                    break
            block = block.next()

    # Tooltips {{{
    def syntax_range_for_cursor(self, cursor):
        if cursor.isNull():
            return
        pos = cursor.positionInBlock()
        for r in cursor.block().layout().additionalFormats():
            if r.start <= pos <= r.start + r.length and r.format.property(
                    SYNTAX_PROPERTY):
                return r

    def syntax_format_for_cursor(self, cursor):
        return getattr(self.syntax_range_for_cursor(cursor), 'format', None)

    def show_tooltip(self, ev):
        c = self.cursorForPosition(ev.pos())
        fmt = self.syntax_format_for_cursor(c)
        if fmt is not None:
            tt = unicode(fmt.toolTip())
            if tt:
                QToolTip.setFont(self.tooltip_font)
                QToolTip.setPalette(self.tooltip_palette)
                QToolTip.showText(ev.globalPos(), textwrap.fill(tt))
                return
        QToolTip.hideText()
        ev.ignore()

    # }}}

    def link_for_position(self, pos):
        c = self.cursorForPosition(pos)
        r = self.syntax_range_for_cursor(c)
        if r is not None and r.format.property(LINK_PROPERTY):
            return self.text_for_range(c.block(), r)

    def mousePressEvent(self, ev):
        if self.completion_popup.isVisible(
        ) and not self.completion_popup.rect().contains(ev.pos()):
            # For some reason using eventFilter for this does not work, so we
            # implement it here
            self.completion_popup.abort()
        if ev.modifiers() & Qt.CTRL:
            url = self.link_for_position(ev.pos())
            if url is not None:
                ev.accept()
                self.link_clicked.emit(url)
                return
        return PlainTextEdit.mousePressEvent(self, ev)

    def get_range_inside_tag(self):
        c = self.textCursor()
        left = min(c.anchor(), c.position())
        right = max(c.anchor(), c.position())
        # For speed we use QPlainTextEdit's toPlainText as we dont care about
        # spaces in this context
        raw = unicode(QPlainTextEdit.toPlainText(self))
        # Make sure the left edge is not within a <>
        gtpos = raw.find('>', left)
        ltpos = raw.find('<', left)
        if gtpos < ltpos:
            left = gtpos + 1 if gtpos > -1 else left
        right = max(left, right)
        if right != left:
            gtpos = raw.find('>', right)
            ltpos = raw.find('<', right)
            if ltpos > gtpos:
                ltpos = raw.rfind('<', left, right + 1)
                right = max(ltpos, left)
        return left, right

    def format_text(self, formatting):
        if self.syntax != 'html':
            return
        if formatting.startswith('justify_'):
            return self.smarts.set_text_alignment(
                self,
                formatting.partition('_')[-1])
        color = 'currentColor'
        if formatting in {'color', 'background-color'}:
            color = QColorDialog.getColor(
                QColor(Qt.black if formatting == 'color' else Qt.white), self,
                _('Choose color'), QColorDialog.ShowAlphaChannel)
            if not color.isValid():
                return
            r, g, b, a = color.getRgb()
            if a == 255:
                color = 'rgb(%d, %d, %d)' % (r, g, b)
            else:
                color = 'rgba(%d, %d, %d, %.2g)' % (r, g, b, a / 255)
        prefix, suffix = {
            'bold': ('<b>', '</b>'),
            'italic': ('<i>', '</i>'),
            'underline': ('<u>', '</u>'),
            'strikethrough': ('<strike>', '</strike>'),
            'superscript': ('<sup>', '</sup>'),
            'subscript': ('<sub>', '</sub>'),
            'color': ('<span style="color: %s">' % color, '</span>'),
            'background-color':
            ('<span style="background-color: %s">' % color, '</span>'),
        }[formatting]
        left, right = self.get_range_inside_tag()
        c = self.textCursor()
        c.setPosition(left)
        c.setPosition(right, c.KeepAnchor)
        prev_text = unicode(c.selectedText()).rstrip('\0')
        c.insertText(prefix + prev_text + suffix)
        if prev_text:
            right = c.position()
            c.setPosition(left)
            c.setPosition(right, c.KeepAnchor)
        else:
            c.setPosition(c.position() - len(suffix))
        self.setTextCursor(c)

    def insert_image(self, href, fullpage=False, preserve_aspect_ratio=False):
        c = self.textCursor()
        template, alt = 'url(%s)', ''
        left = min(c.position(), c.anchor)
        if self.syntax == 'html':
            left, right = self.get_range_inside_tag()
            c.setPosition(left)
            c.setPosition(right, c.KeepAnchor)
            href = prepare_string_for_xml(href, True)
            if fullpage:
                template = '''\
<div style="page-break-before:always; page-break-after:always; page-break-inside:avoid">\
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" \
version="1.1" width="100%%" height="100%%" viewBox="0 0 1200 1600" preserveAspectRatio="{}">\
<image width="1200" height="1600" xlink:href="%s"/>\
</svg></div>'''.format('xMidYMid meet' if preserve_aspect_ratio else 'none')
            else:
                alt = _('Image')
                template = '<img alt="{0}" src="%s" />'.format(alt)
        text = template % href
        c.insertText(text)
        if self.syntax == 'html' and not fullpage:
            c.setPosition(left + 10)
            c.setPosition(c.position() + len(alt), c.KeepAnchor)
        else:
            c.setPosition(left)
            c.setPosition(left + len(text), c.KeepAnchor)
        self.setTextCursor(c)

    def insert_hyperlink(self, target, text):
        if hasattr(self.smarts, 'insert_hyperlink'):
            self.smarts.insert_hyperlink(self, target, text)

    def insert_tag(self, tag):
        if hasattr(self.smarts, 'insert_tag'):
            self.smarts.insert_tag(self, tag)

    def keyPressEvent(self, ev):
        if ev.key() == Qt.Key_X and ev.modifiers() == Qt.AltModifier:
            if self.replace_possible_unicode_sequence():
                ev.accept()
                return
        if ev.key() == Qt.Key_Insert:
            self.setOverwriteMode(self.overwriteMode() ^ True)
            ev.accept()
            return
        if self.snippet_manager.handle_key_press(ev):
            self.completion_popup.hide()
            return
        if self.smarts.handle_key_press(ev, self):
            self.handle_keypress_completion(ev)
            return
        QPlainTextEdit.keyPressEvent(self, ev)
        self.handle_keypress_completion(ev)

    def handle_keypress_completion(self, ev):
        if self.request_completion is None:
            return
        code = ev.key()
        if code in (0, Qt.Key_unknown, Qt.Key_Shift, Qt.Key_Control,
                    Qt.Key_Alt, Qt.Key_Meta, Qt.Key_AltGr, Qt.Key_CapsLock,
                    Qt.Key_NumLock, Qt.Key_ScrollLock, Qt.Key_Up, Qt.Key_Down):
            # We ignore up/down arrow so as to not break scrolling through the
            # text with the arrow keys
            return
        result = self.smarts.get_completion_data(self, ev)
        if result is None:
            self.last_completion_request += 1
        else:
            self.last_completion_request = self.request_completion(*result)
        self.completion_popup.mark_completion(
            self, None if result is None else result[-1])

    def handle_completion_result(self, result):
        if result.request_id[0] >= self.last_completion_request:
            self.completion_popup.handle_result(result)

    def clear_completion_cache(self):
        if self.request_completion is not None and self.completion_doc_name:
            self.request_completion(None, 'file:' + self.completion_doc_name)

    def replace_possible_unicode_sequence(self):
        c = self.textCursor()
        has_selection = c.hasSelection()
        if has_selection:
            text = unicode(c.selectedText()).rstrip('\0')
        else:
            c.setPosition(c.position() - min(c.positionInBlock(), 6),
                          c.KeepAnchor)
            text = unicode(c.selectedText()).rstrip('\0')
        m = re.search(r'[a-fA-F0-9]{2,6}$', text)
        if m is None:
            return False
        text = m.group()
        try:
            num = int(text, 16)
        except ValueError:
            return False
        if num > 0x10ffff or num < 1:
            return False
        end_pos = max(c.anchor(), c.position())
        c.setPosition(end_pos - len(text)), c.setPosition(
            end_pos, c.KeepAnchor)
        c.insertText(safe_chr(num))
        return True

    def select_all(self):
        c = self.textCursor()
        c.clearSelection()
        c.setPosition(0)
        c.movePosition(c.End, c.KeepAnchor)
        self.setTextCursor(c)

    def rename_block_tag(self, new_name):
        if hasattr(self.smarts, 'rename_block_tag'):
            self.smarts.rename_block_tag(self, new_name)

    def current_tag(self, for_position_sync=True):
        return self.smarts.cursor_position_with_sourceline(
            self.textCursor(), for_position_sync=for_position_sync)

    def goto_sourceline(self, sourceline, tags, attribute=None):
        return self.smarts.goto_sourceline(self,
                                           sourceline,
                                           tags,
                                           attribute=attribute)

    def get_tag_contents(self):
        c = self.smarts.get_inner_HTML(self)
        if c is not None:
            return self.selected_text_from_cursor(c)

    def goto_css_rule(self, rule_address, sourceline_address=None):
        from calibre.gui2.tweak_book.editor.smarts.css import find_rule
        block = None
        if self.syntax == 'css':
            raw = unicode(self.toPlainText())
            line, col = find_rule(raw, rule_address)
            if line is not None:
                block = self.document().findBlockByNumber(line - 1)
        elif sourceline_address is not None:
            sourceline, tags = sourceline_address
            if self.goto_sourceline(sourceline, tags):
                c = self.textCursor()
                c.setPosition(c.position() + 1)
                self.setTextCursor(c)
                raw = self.get_tag_contents()
                line, col = find_rule(raw, rule_address)
                if line is not None:
                    block = self.document().findBlockByNumber(c.blockNumber() +
                                                              line - 1)

        if block is not None and block.isValid():
            c = self.textCursor()
            c.setPosition(block.position() + col)
            self.setTextCursor(c)

    def change_case(self, action, cursor=None):
        cursor = cursor or self.textCursor()
        text = self.selected_text_from_cursor(cursor)
        text = {
            'lower': lower,
            'upper': upper,
            'capitalize': capitalize,
            'title': titlecase,
            'swap': swapcase
        }[action](text)
        cursor.insertText(text)
        self.setTextCursor(cursor)
Exemple #44
0
class ResultsList(QTreeWidget):

    current_result_changed = pyqtSignal(object)
    open_annotation = pyqtSignal(object, object, object)

    def __init__(self, parent):
        QTreeWidget.__init__(self, parent)
        self.setHeaderHidden(True)
        self.setSelectionMode(self.ExtendedSelection)
        self.delegate = AnnotsResultsDelegate(self)
        self.setItemDelegate(self.delegate)
        self.section_font = QFont(self.font())
        self.itemDoubleClicked.connect(self.item_activated)
        self.section_font.setItalic(True)
        self.currentItemChanged.connect(self.current_item_changed)
        self.number_of_results = 0
        self.item_map = []

    def item_activated(self, item):
        r = item.data(0, Qt.UserRole)
        if isinstance(r, dict):
            self.open_annotation.emit(r['book_id'], r['format'],
                                      r['annotation'])

    def set_results(self, results, emphasize_text):
        self.clear()
        self.delegate.emphasize_text = emphasize_text
        self.number_of_results = 0
        self.item_map = []
        book_id_map = {}
        db = current_db()
        for result in results:
            book_id = result['book_id']
            if book_id not in book_id_map:
                book_id_map[book_id] = {
                    'title': db.field_for('title', book_id),
                    'matches': []
                }
            book_id_map[book_id]['matches'].append(result)
        for book_id, entry in book_id_map.items():
            section = QTreeWidgetItem([entry['title']], 1)
            section.setFlags(Qt.ItemIsEnabled)
            section.setFont(0, self.section_font)
            self.addTopLevelItem(section)
            section.setExpanded(True)
            for result in entry['matches']:
                item = QTreeWidgetItem(section, [' '], 2)
                self.item_map.append(item)
                item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                              | Qt.ItemNeverHasChildren)
                item.setData(0, Qt.UserRole, result)
                item.setData(0, Qt.UserRole + 1, self.number_of_results)
                self.number_of_results += 1
        if self.item_map:
            self.setCurrentItem(self.item_map[0])

    def current_item_changed(self, current, previous):
        if current is not None:
            r = current.data(0, Qt.UserRole)
            if isinstance(r, dict):
                self.current_result_changed.emit(r)
        else:
            self.current_result_changed.emit(None)

    def show_next(self, backwards=False):
        item = self.currentItem()
        if item is None:
            return
        i = int(item.data(0, Qt.UserRole + 1))
        i += -1 if backwards else 1
        i %= self.number_of_results
        self.setCurrentItem(self.item_map[i])

    def keyPressEvent(self, ev):
        key = ev.key()
        if key == Qt.Key_Down:
            self.show_next()
            return
        if key == Qt.Key_Up:
            self.show_next(backwards=True)
            return
        return QTreeWidget.keyPressEvent(self, ev)

    @property
    def selected_annot_ids(self):
        for item in self.selectedItems():
            yield item.data(0, Qt.UserRole)['id']

    @property
    def selected_annotations(self):
        for item in self.selectedItems():
            x = item.data(0, Qt.UserRole)
            ans = x['annotation'].copy()
            for key in ('book_id', 'format'):
                ans[key] = x[key]
            yield ans
Exemple #45
0
 def set_subtitle_font(self, for_ratings=True):
     if for_ratings:
         self.setSubtitleFont(QFont(rating_font()))
     else:
         self.setSubtitleFont(self.font())
Exemple #46
0
    def __init__(self,
                 field_metadata,
                 parent=None,
                 revert_tooltip=None,
                 datetime_fmt='MMMM yyyy',
                 blank_as_equal=True,
                 fields=('title', 'authors', 'series', 'tags', 'rating',
                         'publisher', 'pubdate', 'identifiers', 'languages',
                         'comments', 'cover'),
                 db=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout()
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)
        revert_tooltip = revert_tooltip or _('Revert %s')
        self.current_mi = None
        self.changed_font = QFont(QApplication.font())
        self.changed_font.setBold(True)
        self.changed_font.setItalic(True)
        self.blank_as_equal = blank_as_equal

        self.widgets = OrderedDict()
        row = 0

        for field in fields:
            m = field_metadata[field]
            dt = m['datatype']
            extra = None
            if 'series' in {field, dt}:
                cls = SeriesEdit
            elif field == 'identifiers':
                cls = IdentifiersEdit
            elif field == 'languages':
                cls = LanguagesEdit
            elif 'comments' in {field, dt}:
                cls = CommentsEdit
            elif 'rating' in {field, dt}:
                cls = RatingsEdit
            elif dt == 'datetime':
                extra = datetime_fmt
                cls = DateEdit
            elif field == 'cover':
                cls = CoverView
            elif dt in {'text', 'enum'}:
                cls = LineEdit
            else:
                continue
            neww = cls(field, True, self, m, extra)
            neww.changed.connect(partial(self.changed, field))
            if isinstance(neww, EditWithComplete):
                try:
                    neww.update_items_cache(db.new_api.all_field_names(field))
                except ValueError:
                    pass  # A one-one field like title
            if isinstance(neww, SeriesEdit):
                neww.set_db(db.new_api)
            oldw = cls(field, False, self, m, extra)
            newl = QLabel('&%s:' % m['name'])
            newl.setBuddy(neww)
            button = RightClickButton(self)
            button.setIcon(QIcon(I('back.png')))
            button.clicked.connect(partial(self.revert, field))
            button.setToolTip(revert_tooltip % m['name'])
            if field == 'identifiers':
                button.m = m = QMenu(button)
                button.setMenu(m)
                button.setPopupMode(QToolButton.DelayedPopup)
                m.addAction(button.toolTip()).triggered.connect(button.click)
                m.actions()[0].setIcon(button.icon())
                m.addAction(_('Merge identifiers')).triggered.connect(
                    self.merge_identifiers)
                m.actions()[1].setIcon(QIcon(I('merge.png')))
            elif field == 'tags':
                button.m = m = QMenu(button)
                button.setMenu(m)
                button.setPopupMode(QToolButton.DelayedPopup)
                m.addAction(button.toolTip()).triggered.connect(button.click)
                m.actions()[0].setIcon(button.icon())
                m.addAction(_('Merge tags')).triggered.connect(self.merge_tags)
                m.actions()[1].setIcon(QIcon(I('merge.png')))

            self.widgets[field] = Widgets(neww, oldw, newl, button)
            for i, w in enumerate((newl, neww, button, oldw)):
                c = i if i < 2 else i + 1
                if w is oldw:
                    c += 1
                l.addWidget(w, row, c)
            row += 1

        self.sep = f = QFrame(self)
        f.setFrameShape(f.VLine)
        l.addWidget(f, 0, 2, row, 1)
        self.sep2 = f = QFrame(self)
        f.setFrameShape(f.VLine)
        l.addWidget(f, 0, 4, row, 1)
        if 'comments' in self.widgets and not gprefs.get(
                'diff_widget_show_comments_controls', True):
            self.widgets['comments'].new.hide_toolbars()
Exemple #47
0
 def family_setter(which, w, val):
     w.setCurrentFont(QFont(val or default_font(which)))
class EmailAccounts(QAbstractTableModel):  # {{{
    def __init__(self, accounts, subjects, aliases={}, tags={}):
        QAbstractTableModel.__init__(self)
        self.accounts = accounts
        self.subjects = subjects
        self.aliases = aliases
        self.tags = tags
        self.sorted_on = (0, True)
        self.account_order = self.accounts.keys()
        self.do_sort()
        self.headers = map(unicode, [
            _('Email'),
            _('Formats'),
            _('Subject'),
            _('Auto send'),
            _('Alias'),
            _('Auto send only tags')
        ])
        self.default_font = QFont()
        self.default_font.setBold(True)
        self.default_font = (self.default_font)
        self.tooltips = [None] + list(
            map(
                unicode,
                map(textwrap.fill, [
                    _('Formats to email. The first matching format will be sent.'
                      ),
                    _('Subject of the email to use when sending. When left blank '
                      'the title will be used for the subject. Also, the same '
                      'templates used for "Save to disk" such as {title} and '
                      '{author_sort} can be used here.'), '<p>' +
                    _('If checked, downloaded news will be automatically '
                      'mailed to this email address '
                      '(provided it is in one of the listed formats and has not been filtered by tags).'
                      ),
                    _('Friendly name to use for this email address'),
                    _('If specified, only news with one of these tags will be sent to'
                      ' this email address. All news downloads have their title as a'
                      ' tag, so you can use this to easily control which news downloads'
                      ' are sent to this email address.')
                ])))

    def do_sort(self):
        col = self.sorted_on[0]
        if col == 0:

            def key(account_key):
                return numeric_sort_key(account_key)
        elif col == 1:

            def key(account_key):
                return numeric_sort_key(self.accounts[account_key][0] or '')
        elif col == 2:

            def key(account_key):
                return numeric_sort_key(self.subjects.get(account_key) or '')
        elif col == 3:

            def key(account_key):
                return numeric_sort_key(
                    type(u'')(self.accounts[account_key][0]) or '')
        elif col == 4:

            def key(account_key):
                return numeric_sort_key(self.aliases.get(account_key) or '')
        elif col == 5:

            def key(account_key):
                return numeric_sort_key(self.tags.get(account_key) or '')

        self.account_order.sort(key=key, reverse=not self.sorted_on[1])

    def sort(self, column, order=Qt.AscendingOrder):
        nsort = (column, order == Qt.AscendingOrder)
        if nsort != self.sorted_on:
            self.sorted_on = nsort
            self.beginResetModel()
            try:
                self.do_sort()
            finally:
                self.endResetModel()

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

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

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.headers[section]
        return None

    def data(self, index, role):
        row, col = index.row(), index.column()
        if row < 0 or row >= self.rowCount():
            return None
        account = self.account_order[row]
        if account not in self.accounts:
            return None
        if role == Qt.UserRole:
            return (account, self.accounts[account])
        if role == Qt.ToolTipRole:
            return self.tooltips[col]
        if role in [Qt.DisplayRole, Qt.EditRole]:
            if col == 0:
                return (account)
            if col == 1:
                return (self.accounts[account][0])
            if col == 2:
                return (self.subjects.get(account, ''))
            if col == 4:
                return (self.aliases.get(account, ''))
            if col == 5:
                return (self.tags.get(account, ''))
        if role == Qt.FontRole and self.accounts[account][2]:
            return self.default_font
        if role == Qt.CheckStateRole and col == 3:
            return (Qt.Checked if self.accounts[account][1] else Qt.Unchecked)
        return None

    def flags(self, index):
        if index.column() == 3:
            return QAbstractTableModel.flags(self,
                                             index) | Qt.ItemIsUserCheckable
        else:
            return QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable

    def setData(self, index, value, role):
        if not index.isValid():
            return False
        row, col = index.row(), index.column()
        account = self.account_order[row]
        if col == 3:
            self.accounts[account][1] ^= True
        elif col == 2:
            self.subjects[account] = unicode(value or '')
        elif col == 4:
            self.aliases.pop(account, None)
            aval = unicode(value or '').strip()
            if aval:
                self.aliases[account] = aval
        elif col == 5:
            self.tags.pop(account, None)
            aval = unicode(value or '').strip()
            if aval:
                self.tags[account] = aval
        elif col == 1:
            self.accounts[account][0] = unicode(value or '').upper()
        elif col == 0:
            na = unicode(value or '')
            from email.utils import parseaddr
            addr = parseaddr(na)[-1]
            if not addr:
                return False
            self.accounts[na] = self.accounts.pop(account)
            self.account_order[row] = na
            if '@kindle.com' in addr:
                self.accounts[na][0] = 'AZW, MOBI, TPZ, PRC, AZW1'

        self.dataChanged.emit(self.index(index.row(), 0),
                              self.index(index.row(), 3))
        return True

    def make_default(self, index):
        if index.isValid():
            self.beginResetModel()
            row = index.row()
            for x in self.accounts.values():
                x[2] = False
            self.accounts[self.account_order[row]][2] = True
            self.endResetModel()

    def add(self):
        x = _('new email address')
        y = x
        c = 0
        while y in self.accounts:
            c += 1
            y = x + str(c)
        auto_send = len(self.accounts) < 1
        self.beginResetModel()
        self.accounts[y] = [
            'MOBI, EPUB', auto_send,
            len(self.account_order) == 0
        ]
        self.account_order = self.accounts.keys()
        self.do_sort()
        self.endResetModel()
        return self.index(self.account_order.index(y), 0)

    def remove(self, index):
        if index.isValid():
            row = index.row()
            account = self.account_order[row]
            self.accounts.pop(account)
            self.account_order = sorted(self.accounts.keys())
            has_default = False
            for account in self.account_order:
                if self.accounts[account][2]:
                    has_default = True
                    break
            if not has_default and self.account_order:
                self.accounts[self.account_order[0]][2] = True

            self.beginResetModel()
            self.endResetModel()
    def __init__(self):
        super(SituationInformation, self).__init__()
        self.setObjectName('SituationInformation')
        self.setStyleSheet(
            GetQssFile.readQss('../resource/qss/situationInformation.qss'))

        self.log = logging.getLogger('StarCraftII')

        # font
        font = QFont()
        font.setWeight(50)
        font.setPixelSize(15)

        # set widget of layout
        self.frame = QFrame(self)
        self.frame.setGeometry(QDesktopWidget().screenGeometry())
        self.main_layout = QHBoxLayout(self)
        self.main_layout.setSpacing(20)
        self.setLayout(self.main_layout)

        # consumption action
        self.consumption = QPushButton()
        self.consumption.setObjectName('consumption')
        self.consumptionLabel = QLabel('consumption')
        self.consumptionLabel.setFont(font)
        self.consumption_layout = QVBoxLayout()
        self.consumption_layout.addWidget(self.consumption,
                                          alignment=Qt.AlignCenter)
        self.consumption_layout.addWidget(self.consumptionLabel,
                                          alignment=Qt.AlignCenter)
        self.main_layout.addLayout(self.consumption_layout)

        # resource action
        self.resource = QPushButton()
        self.resource.setObjectName('resource')
        self.resourceLabel = QLabel('resource')
        self.resourceLabel.setFont(font)
        self.resource_layout = QVBoxLayout()
        self.resource_layout.addWidget(self.resource, alignment=Qt.AlignCenter)
        self.resource_layout.addWidget(self.resourceLabel,
                                       alignment=Qt.AlignCenter)
        self.main_layout.addLayout(self.resource_layout)

        # score action
        self.score = QPushButton()
        self.score.setObjectName('score')
        self.scoreLabel = QLabel('score')
        self.scoreLabel.setFont(font)
        self.score_layout = QVBoxLayout()
        self.score_layout.addWidget(self.score, alignment=Qt.AlignCenter)
        self.score_layout.addWidget(self.scoreLabel, alignment=Qt.AlignCenter)
        self.main_layout.addLayout(self.score_layout)

        # output action
        self.output = QPushButton()
        self.output.setObjectName('output')
        self.outputLabel = QLabel('output')
        self.outputLabel.setFont(font)
        self.output_layout = QVBoxLayout()
        self.output_layout.addWidget(self.output, alignment=Qt.AlignCenter)
        self.output_layout.addWidget(self.outputLabel,
                                     alignment=Qt.AlignCenter)
        self.main_layout.addLayout(self.output_layout)

        # a description dialog
        self.dialog = None

        # add stretch
        self.main_layout.addStretch(1)

        # initialization
        self.initUI()
Exemple #50
0
def layout_text(prefs, img, title, subtitle, footer, max_height, style):
    width = img.width() - 2 * style.hmargin
    title, subtitle, footer = title, subtitle, footer
    title_font = QFont(prefs.title_font_family or 'Liberation Serif')
    title_font.setPixelSize(prefs.title_font_size)
    title_block = Block(title, width, title_font, img, max_height,
                        style.TITLE_ALIGN)
    title_block.position = style.hmargin, style.vmargin
    subtitle_block = Block()
    if subtitle:
        subtitle_font = QFont(prefs.subtitle_font_family or 'Liberation Sans')
        subtitle_font.setPixelSize(prefs.subtitle_font_size)
        gap = 2 * title_block.leading
        mh = max_height - title_block.height - gap
        subtitle_block = Block(subtitle, width, subtitle_font, img, mh,
                               style.SUBTITLE_ALIGN)
        subtitle_block.position = style.hmargin, title_block.position.y + title_block.height + gap

    footer_font = QFont(prefs.footer_font_family or 'Liberation Serif')
    footer_font.setPixelSize(prefs.footer_font_size)
    footer_block = Block(footer, width, footer_font, img, max_height,
                         style.FOOTER_ALIGN)
    footer_block.position = style.hmargin, img.height(
    ) - style.vmargin - footer_block.height

    return title_block, subtitle_block, footer_block
Exemple #51
0
 def __init__(self, *args, **kwargs):
     QStyledItemDelegate.__init__(self, *args, **kwargs)
     self.old_look = False
     self.rating_pat = re.compile(r'[%s]' % rating_to_stars(3, True))
     self.rating_font = QFont(rating_font())
     self.completion_data = None
class AnnotationsAppearance(SizePersistedDialog):
    '''
    Dialog for managing CSS rules, including Preview window
    '''
    if isosx:
        FONT = QFont('Monaco', 12)
    elif iswindows:
        FONT = QFont('Lucida Console', 9)
    elif islinux:
        FONT = QFont('Monospace', 9)
        FONT.setStyleHint(QFont.TypeWriter)

    def __init__(self, parent, icon, prefs):

        self.parent = parent
        self.prefs = prefs
        self.icon = icon
        super(AnnotationsAppearance, self).__init__(parent, 'appearance_dialog')
        self.setWindowTitle(_('Modify appearance'))
        self.setWindowIcon(icon)
        self.l = QVBoxLayout(self)
        self.setLayout(self.l)

        # Add a label for description
        #self.description_label = QLabel(_("Descriptive text here"))
        #self.l.addWidget(self.description_label)

        # Add a group box, vertical layout for preview window
        self.preview_gb = QGroupBox(self)
        self.preview_gb.setTitle(_("Preview"))
        self.preview_vl = QVBoxLayout(self.preview_gb)
        self.l.addWidget(self.preview_gb)

        self.wv = QWebView()
        self.wv.setHtml('<p></p>')
        self.wv.setMinimumHeight(100)
        self.wv.setMaximumHeight(16777215)
        self.wv.setGeometry(0, 0, 200, 100)
        self.wv.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.preview_vl.addWidget(self.wv)

        # Create a group box, horizontal layout for the table
        self.css_table_gb = QGroupBox(self)
        self.css_table_gb.setTitle(_("Annotation elements"))
        self.elements_hl = QHBoxLayout(self.css_table_gb)
        self.l.addWidget(self.css_table_gb)

        # Add the group box to the main layout
        self.elements_table = AnnotationElementsTable(self, 'annotation_elements_tw')
        self.elements_hl.addWidget(self.elements_table)
        self.elements_table.initialize()

        # Options
        self.options_gb = QGroupBox(self)
        self.options_gb.setTitle(_("Options"))
        self.options_gl = QGridLayout(self.options_gb)
        self.l.addWidget(self.options_gb)
        current_row = 0

        # <hr/> separator
        # addWidget(widget, row, col, rowspan, colspan)
        self.hr_checkbox = QCheckBox(_('Add horizontal rule between annotations'))
        self.hr_checkbox.stateChanged.connect(self.hr_checkbox_changed)
        self.hr_checkbox.setCheckState(
            JSONConfig('plugins/annotations').get('appearance_hr_checkbox', False))
        self.options_gl.addWidget(self.hr_checkbox, current_row, 0, 1, 4)
        current_row += 1

        # Timestamp
        self.timestamp_fmt_label = QLabel(_("Timestamp format:"))
        self.options_gl.addWidget(self.timestamp_fmt_label, current_row, 0)

        self.timestamp_fmt_le = QLineEdit(
            JSONConfig('plugins/annotations').get('appearance_timestamp_format', default_timestamp),
            parent=self)
        self.timestamp_fmt_le.textEdited.connect(self.timestamp_fmt_changed)
        self.timestamp_fmt_le.setFont(self.FONT)
        self.timestamp_fmt_le.setObjectName('timestamp_fmt_le')
        self.timestamp_fmt_le.setToolTip(_('Format string for timestamp'))
        self.timestamp_fmt_le.setMaximumWidth(16777215)
        self.timestamp_fmt_le.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.options_gl.addWidget(self.timestamp_fmt_le, current_row, 1)

        self.timestamp_fmt_reset_tb = QToolButton(self)
        self.timestamp_fmt_reset_tb.setToolTip(_("Reset to default"))
        self.timestamp_fmt_reset_tb.setIcon(QIcon(I('trash.png')))
        self.timestamp_fmt_reset_tb.clicked.connect(self.reset_timestamp_to_default)
        self.options_gl.addWidget(self.timestamp_fmt_reset_tb, current_row, 2)

        self.timestamp_fmt_help_tb = QToolButton(self)
        self.timestamp_fmt_help_tb.setToolTip(_("Format string reference"))
        self.timestamp_fmt_help_tb.setIcon(QIcon(I('help.png')))
        self.timestamp_fmt_help_tb.clicked.connect(self.show_help)
        self.options_gl.addWidget(self.timestamp_fmt_help_tb, current_row, 3)

        # Button box
        bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.l.addWidget(bb)

        # Spacer
        self.spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        self.l.addItem(self.spacerItem)

        # Sizing
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(sizePolicy)
        self.resize_dialog()

    def hr_checkbox_changed(self, state):
        self.prefs.set('appearance_hr_checkbox', state)
        self.elements_table.preview_css()

    def reset_timestamp_to_default(self):
        from calibre_plugins.annotations.appearance import default_timestamp
        self.timestamp_fmt_le.setText(default_timestamp)
        self.timestamp_fmt_changed()

    def show_help(self):
        '''
        Display strftime help file
        '''
        hv = HelpView(self, self.icon, self.prefs,
            html=get_resources('help/timestamp_formats.html'), title=_("Timestamp formats"))
        hv.show()

    def sizeHint(self):
        return QtCore.QSize(600, 200)

    def timestamp_fmt_changed(self):
        self.prefs.set('appearance_timestamp_format', str(self.timestamp_fmt_le.text()))
        self.elements_table.preview_css()
class AnnotationElementsTable(QTableWidget):
    '''
    QTableWidget managing CSS rules
    '''
    DEBUG = True
    #MAXIMUM_TABLE_HEIGHT = 113
    ELEMENT_FIELD_WIDTH = 250
    if isosx:
        FONT = QFont('Monaco', 11)
    elif iswindows:
        FONT = QFont('Lucida Console', 9)
    elif islinux:
        FONT = QFont('Monospace', 9)
        FONT.setStyleHint(QFont.TypeWriter)

    COLUMNS = {
                'ELEMENT_NAME': {'ordinal': 0, 'name': 'Element Name'},
                'ELEMENT':      {'ordinal': 1, 'name': _('Element')},
                'CSS':          {'ordinal': 2, 'name': _('CSS')},
                }

    sample_ann_1 = {
        'text': ['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean placerat condimentum semper. Aliquam hendrerit nisl mauris, nec laoreet orci. Donec rutrum consequat ultricies.',
                 'Curabitur sollicitudin euismod felis, vitae mollis magna vestibulum id.'],
        'note': [_('This is a note appended to the highlight.'),
                 _('And additional comments after a linebreak.')],
        'highlightcolor': 'Yellow',
        'timestamp': time.mktime(time.localtime()),
        'location': 'Chapter 4',
        'location_sort': 0
        }
    sample_ann_2 = {
        'text': ['Phasellus sit amet ipsum id velit commodo convallis. In dictum felis non tellus volutpat in tincidunt neque varius. Sed at mauris augue. Vestibulum ligula nunc, ullamcorper id suscipit sed, auctor quis erat. In hac habitasse platea dictumst. Aliquam sit amet nulla dolor, ut tempus libero. In hac habitasse platea dictumst. Etiam consectetur orci vel massa eleifend in vestibulum odio auctor. Praesent orci turpis, aliquet non eleifend sit amet, sollicitudin sit amet augue.'],
        'highlightcolor': 'Green',
        'timestamp': time.mktime(time.localtime()),
        'location': 'Chapter 12',
        'location_sort': 1
        }
    sample_ann_3 = {
        'text': ['Morbi massa tellus, laoreet id pretium sed, volutpat in felis.',
                 'Donec massa nulla, malesuada vitae volutpat quis, accumsan ut tellus.'],
        'note': [_('This is a note appended to the highlight.'),
                 _('And additional comments after a linebreak.')],
        'highlightcolor': 'Purple',
        'timestamp': time.mktime(time.localtime()),
        'location': 'Chapter 53',
        'location_sort': 2
        }


    def __init__(self, parent, object_name):
        self.parent = parent
        self.prefs = parent.prefs
        self.elements = self.prefs.get('appearance_css', None)
        debug_print("AnnotationElementsTable::__init__ - self.elements", self.elements)
        if not self.elements:
            self.elements = default_elements
            debug_print("AnnotationElementsTable::__init__ - self.elements", self.elements)

        QTableWidget.__init__(self)
        self.setObjectName(object_name)
        self.layout = parent.elements_hl.layout()

        # Add ourselves to the layout
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        #sizePolicy.setVerticalStretch(0)
        #sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(sizePolicy)
        #self.setMaximumSize(QSize(16777215, self.MAXIMUM_TABLE_HEIGHT))

        self.setColumnCount(0)
        self.setRowCount(0)
        self.layout.addWidget(self)

    def _init_controls(self):
        # Add the control set
        vbl = QVBoxLayout()
        self.move_element_up_tb = QToolButton()
        self.move_element_up_tb.setObjectName("move_element_up_tb")
        self.move_element_up_tb.setToolTip(_('Move element up'))
        self.move_element_up_tb.setIcon(QIcon(I('arrow-up.png')))
        self.move_element_up_tb.clicked.connect(self.move_row_up)
        vbl.addWidget(self.move_element_up_tb)

        self.undo_css_tb = QToolButton()
        self.undo_css_tb.setObjectName("undo_css_tb")
        self.undo_css_tb.setToolTip(_('Restore CSS to last saved'))
        self.undo_css_tb.setIcon(QIcon(I('edit-undo.png')))
        self.undo_css_tb.clicked.connect(partial(self.undo_reset_button_clicked, 'undo'))
        vbl.addWidget(self.undo_css_tb)

        self.reset_css_tb = QToolButton()
        self.reset_css_tb.setObjectName("reset_css_tb")
        self.reset_css_tb.setToolTip(_('Reset CSS to default'))
        self.reset_css_tb.setIcon(QIcon(I('trash.png')))
        self.reset_css_tb.clicked.connect(partial(self.undo_reset_button_clicked, 'reset'))
        vbl.addWidget(self.reset_css_tb)

        self.move_element_down_tb = QToolButton()
        self.move_element_down_tb.setObjectName("move_element_down_tb")
        self.move_element_down_tb.setToolTip(_('Move element down'))
        self.move_element_down_tb.setIcon(QIcon(I('arrow-down.png')))
        self.move_element_down_tb.clicked.connect(self.move_row_down)
        vbl.addWidget(self.move_element_down_tb)

        self.layout.addLayout(vbl)

    def _init_table_widget(self):
        header_labels = [self.COLUMNS[index]['name'] \
            for index in sorted(self.COLUMNS.keys(), key=lambda c: self.COLUMNS[c]['ordinal'])]
        self.setColumnCount(len(header_labels))
        self.setHorizontalHeaderLabels(header_labels)
        self.verticalHeader().setVisible(False)

        self.setSortingEnabled(False)

        # Select single rows
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setSelectionMode(QAbstractItemView.SingleSelection)

    def convert_row_to_data(self, row):
        data = {}
        data['ordinal'] = row
#         data['name'] = unicode(self.cellWidget(row, self.COLUMNS['ELEMENT']['ordinal']).text()).strip()
        data['name'] = unicode(self.cellWidget(row, self.COLUMNS['ELEMENT_NAME']['ordinal']).text()).strip()
        data['css'] = unicode(self.cellWidget(row, self.COLUMNS['CSS']['ordinal']).toPlainText()).strip()
        return data

    def css_edited(self, row):
        self.select_and_scroll_to_row(row)
        col = self.COLUMNS['CSS']['ordinal']
        widget = self.cellWidget(row, col)
        css = unicode(widget.toPlainText())
        lines = []
        for line in css.split('\n'):
            lines.append(re.sub('^\s*', '', line))
        self.resize_row_height(lines, row)
#         self.prefs.set('appearance_css', self.get_data())
        widget.setFocus()
        self.preview_css()

    def get_data(self):
        data_items = []
        for row in range(self.rowCount()):
            data = self.convert_row_to_data(row)
            data_items.append(
                               {'ordinal': data['ordinal'],
                                'name': data['name'],
#                                 'translatable_name': translatable_element_names[data['name']],
                                'css': data['css'],
                                })
        return data_items

    def initialize(self):
        self._init_table_widget()
        self._init_controls()
        self.populate_table()
        self.resizeColumnsToContents()
        self.horizontalHeader().setStretchLastSection(True)

        # Update preview window, select first row
        self.css_edited(0)

    def move_row(self, source, dest):

        self.blockSignals(True)
        # Save the contents of the destination row
        saved_data = self.convert_row_to_data(dest)
        debug_print("Annotations::appearance.py::move_row - saved_data", saved_data)

        # Remove the destination row
        self.removeRow(dest)

        # Insert a new row at the original location
        self.insertRow(source)

        # Populate it with the saved data
        self.populate_table_row(source, saved_data)

        self.select_and_scroll_to_row(dest)
        self.blockSignals(False)

        self.css_edited(dest)

    def move_row_down(self):
        src_row = self.currentRow()
        dest_row = src_row + 1
        if dest_row == self.rowCount():
            return
        self.move_row(src_row, dest_row)

    def move_row_up(self):
        src_row = self.currentRow()
        dest_row = src_row - 1
        if dest_row < 0:
            return
        self.move_row(src_row, dest_row)

    def populate_table(self):
        # Format of rules list is different if default values vs retrieved JSON
        # Hack to normalize list style
        elements = self.elements
        if elements and type(elements[0]) is list:
            elements = elements[0]
        self.setFocus()
        elements = sorted(elements, key=lambda k: k['ordinal'])
        for row, element in enumerate(elements):
            self.insertRow(row)
            self.select_and_scroll_to_row(row)
            self.populate_table_row(row, element)
        self.selectRow(0)
        self.setColumnHidden(0, True)

    def populate_table_row(self, row, data):
        self.blockSignals(True)
        self.setCellWidget(row, self.COLUMNS['ELEMENT_NAME']['ordinal'], QLabel(data['name']))
        translatable_name = translatable_element_names[data['name']]
        self.set_element_name_in_row(row, self.COLUMNS['ELEMENT']['ordinal'], translatable_name)
        self.set_css_in_row(row, self.COLUMNS['CSS']['ordinal'], data['css'])
        self.blockSignals(False)

    def preview_css(self):
        '''
        Construct a dummy annotation for preview purposes
        '''
        from calibre_plugins.annotations.annotations import Annotation, Annotations

        pas = Annotations(None, title=_("Preview"))
        pas.annotations.append(Annotation(self.sample_ann_1))
        pas.annotations.append(Annotation(self.sample_ann_2))
        pas.annotations.append(Annotation(self.sample_ann_3))
        self.parent.wv.setHtml(pas.to_HTML())

    def resize_row_height(self, lines, row):
        point_size = self.FONT.pointSize()
        if isosx:
            height = 30 + (len(lines) - 1) * (point_size + 4)
        elif iswindows:
            height = 26 + (len(lines) - 1) * (point_size + 3)
        elif islinux:
            height = 30 + (len(lines) - 1) * (point_size + 6)

        self.verticalHeader().resizeSection(row, height)

    def select_and_scroll_to_row(self, row):
        self.setFocus()
        self.selectRow(row)
        self.scrollToItem(self.currentItem())

    def set_element_name_in_row(self, row, col, name):
        rule_name = QLabel(" %s " % name)
        rule_name.setFont(self.FONT)
        self.setCellWidget(row, col, rule_name)

    def set_css_in_row(self, row, col, css):
        # Clean up multi-line css formatting
        # A single line is 30px tall, subsequent lines add 16px

        lines = []
        for line in css.split('\n'):
            lines.append(re.sub('^\s*', '', line))
        css_content = QPlainTextEdit('\n'.join(lines))
        css_content.setFont(self.FONT)
        css_content.textChanged.connect(partial(self.css_edited, row))
        self.setCellWidget(row, col, css_content)
        self.resize_row_height(lines, row)

    def undo_reset_button_clicked(self, mode):
        """
        Figure out which element is being reset
        Reset to last save or default
        """
        debug_print("undo_reset_button_clicked - mode=", mode)
        row = self.currentRow()
        data = self.convert_row_to_data(row)
        debug_print("undo_reset_button_clicked - data=", data)

        # Get default
        default_css = None
        for de in default_elements:
            if de['name'] == data['name']:
                default_css = de
                break

        # Get last saved
        last_saved_css = None
        saved_elements = self.prefs.get('appearance_css', None)
        last_saved_css = default_css
        debug_print("undo_reset_button_clicked - saved_elements=", saved_elements)
        debug_print("undo_reset_button_clicked - last_saved_css=", last_saved_css)
        if saved_elements:
            for se in saved_elements:
                if se['name'] == data['name']:
                    debug_print("undo_reset_button_clicked - se=", se)
                    last_saved_css = se
                    break
        debug_print("undo_reset_button_clicked - last_saved_css=", last_saved_css)

        # Restore css
        if mode == 'reset':
            self.populate_table_row(row, default_css)
        elif mode == 'undo':
            self.populate_table_row(row, last_saved_css)

        # Refresh the stored data
        #self.prefs.set('appearance_css', self.get_data())
        self.css_edited(row)
Exemple #54
0
 def __init__(self, right=False, parent=None, show_open_in_editor=False):
     PlainTextEdit.__init__(self, parent)
     self.setFrameStyle(0)
     self.show_open_in_editor = show_open_in_editor
     self.side_margin = 0
     self.setContextMenuPolicy(Qt.CustomContextMenu)
     self.customContextMenuRequested.connect(self.show_context_menu)
     self.setFocusPolicy(Qt.NoFocus)
     self.right = right
     self.setReadOnly(True)
     w = self.fontMetrics()
     self.number_width = max(map(lambda x: w.width(str(x)), xrange(10)))
     self.space_width = w.width(' ')
     self.setLineWrapMode(self.WidgetWidth)
     self.setTabStopWidth(tprefs['editor_tab_stop_width'] *
                          self.space_width)
     font = self.font()
     ff = tprefs['editor_font_family']
     if ff is None:
         ff = default_font_family()
     font.setFamily(ff)
     font.setPointSize(tprefs['editor_font_size'])
     self.setFont(font)
     font = self.heading_font = QFont(self.font())
     font.setPointSize(int(tprefs['editor_font_size'] * 1.5))
     font.setBold(True)
     theme = get_theme(tprefs['editor_theme'])
     pal = self.palette()
     pal.setColor(pal.Base, theme_color(theme, 'Normal', 'bg'))
     pal.setColor(pal.AlternateBase, theme_color(theme, 'CursorLine', 'bg'))
     pal.setColor(pal.Text, theme_color(theme, 'Normal', 'fg'))
     pal.setColor(pal.Highlight, theme_color(theme, 'Visual', 'bg'))
     pal.setColor(pal.HighlightedText, theme_color(theme, 'Visual', 'fg'))
     self.setPalette(pal)
     self.viewport().setCursor(Qt.ArrowCursor)
     self.line_number_area = LineNumbers(self)
     self.blockCountChanged[int].connect(self.update_line_number_area_width)
     self.updateRequest.connect(self.update_line_number_area)
     self.line_number_palette = pal = QPalette()
     pal.setColor(pal.Base, theme_color(theme, 'LineNr', 'bg'))
     pal.setColor(pal.Text, theme_color(theme, 'LineNr', 'fg'))
     pal.setColor(pal.BrightText, theme_color(theme, 'LineNrC', 'fg'))
     self.line_number_map = LineNumberMap()
     self.search_header_pos = 0
     self.changes, self.headers, self.images = [], [], OrderedDict()
     self.setVerticalScrollBarPolicy(
         Qt.ScrollBarAlwaysOff), self.setHorizontalScrollBarPolicy(
             Qt.ScrollBarAlwaysOff)
     self.diff_backgrounds = {
         'replace':
         theme_color(theme, 'DiffReplace', 'bg'),
         'insert':
         theme_color(theme, 'DiffInsert', 'bg'),
         'delete':
         theme_color(theme, 'DiffDelete', 'bg'),
         'replacereplace':
         theme_color(theme, 'DiffReplaceReplace', 'bg'),
         'boundary':
         QBrush(theme_color(theme, 'Normal', 'fg'), Qt.Dense7Pattern),
     }
     self.diff_foregrounds = {
         'replace': theme_color(theme, 'DiffReplace', 'fg'),
         'insert': theme_color(theme, 'DiffInsert', 'fg'),
         'delete': theme_color(theme, 'DiffDelete', 'fg'),
         'boundary': QColor(0, 0, 0, 0),
     }
     for x in ('replacereplace', 'insert', 'delete'):
         f = QTextCharFormat()
         f.setBackground(self.diff_backgrounds[x])
         setattr(self, '%s_format' % x, f)
Exemple #55
0
class TOCItem(QStandardItem):
    def __init__(self, spine, toc, depth, all_items, parent=None):
        text = toc.text
        if text:
            text = re.sub(r'\s', ' ', text)
        self.title = text
        self.parent = parent
        self.href = toc.href
        QStandardItem.__init__(self, text if text else '')
        self.abspath = toc.abspath if toc.href else None
        self.fragment = toc.fragment
        all_items.append(self)
        self.emphasis_font = QFont(self.font())
        self.emphasis_font.setBold(True), self.emphasis_font.setItalic(True)
        self.normal_font = self.font()
        for t in toc:
            self.appendRow(TOCItem(spine, t, depth + 1, all_items,
                                   parent=self))
        self.setFlags(Qt.ItemIsEnabled)
        self.is_current_search_result = False
        spos = 0
        for i, si in enumerate(spine):
            if si == self.abspath:
                spos = i
                break
        am = {}
        if self.abspath is not None:
            try:
                am = getattr(spine[i], 'anchor_map', {})
            except UnboundLocalError:
                # Spine was empty?
                pass
        frag = self.fragment if (self.fragment
                                 and self.fragment in am) else None
        self.starts_at = spos
        self.start_anchor = frag
        self.start_src_offset = am.get(frag, 0)
        self.depth = depth
        self.is_being_viewed = False

    @property
    def ancestors(self):
        parent = self.parent
        while parent is not None:
            yield parent
            parent = parent.parent

    @classmethod
    def type(cls):
        return QStandardItem.UserType + 10

    def update_indexing_state(self, spine_index, viewport_rect, anchor_map,
                              in_paged_mode):
        if in_paged_mode:
            self.update_indexing_state_paged(spine_index, viewport_rect,
                                             anchor_map)
        else:
            self.update_indexing_state_unpaged(spine_index, viewport_rect,
                                               anchor_map)

    def update_indexing_state_unpaged(self, spine_index, viewport_rect,
                                      anchor_map):
        is_being_viewed = False
        top, bottom = viewport_rect[1], viewport_rect[3]
        # We use bottom-25 in the checks below to account for the case where
        # the next entry has some invisible margin that just overlaps with the
        # bottom of the screen. In this case it will appear to the user that
        # the entry is not visible on the screen. Of course, the margin could
        # be larger than 25, but that's a decent compromise. Also we dont want
        # to count a partial line as being visible.

        # We only care about y position
        anchor_map = {k: v[1] for k, v in iteritems(anchor_map)}

        if spine_index >= self.starts_at and spine_index <= self.ends_at:
            # The position at which this anchor is present in the document
            start_pos = anchor_map.get(self.start_anchor, 0)
            psp = []
            if self.ends_at == spine_index:
                # Anchors that could possibly indicate the start of the next
                # section and therefore the end of this section.
                # self.possible_end_anchors is a set of anchors belonging to
                # toc entries with depth <= self.depth that are also not
                # ancestors of this entry.
                psp = [anchor_map.get(x, 0) for x in self.possible_end_anchors]
                psp = [x for x in psp if x >= start_pos]
            # The end position. The first anchor whose pos is >= start_pos
            # or if the end is not in this spine item, we set it to the bottom
            # of the window +1
            end_pos = min(psp) if psp else (
                bottom + 1 if self.ends_at >= spine_index else 0)
            if spine_index > self.starts_at and spine_index < self.ends_at:
                # The entire spine item is contained in this entry
                is_being_viewed = True
            elif (spine_index == self.starts_at and bottom - 25 >= start_pos
                  and
                  # This spine item contains the start
                  # The start position is before the end of the viewport
                  (spine_index != self.ends_at or top < end_pos)):
                # The end position is after the start of the viewport
                is_being_viewed = True
            elif (spine_index == self.ends_at and top < end_pos and
                  # This spine item contains the end
                  # The end position is after the start of the viewport
                  (spine_index != self.starts_at or bottom - 25 >= start_pos)):
                # The start position is before the end of the viewport
                is_being_viewed = True

        changed = is_being_viewed != self.is_being_viewed
        self.is_being_viewed = is_being_viewed
        if changed:
            self.setFont(
                self.emphasis_font if is_being_viewed else self.normal_font)

    def update_indexing_state_paged(self, spine_index, viewport_rect,
                                    anchor_map):
        is_being_viewed = False

        left, right = viewport_rect[0], viewport_rect[2]
        left, right = (left, 0), (right, -1)

        if spine_index >= self.starts_at and spine_index <= self.ends_at:
            # The position at which this anchor is present in the document
            start_pos = anchor_map.get(self.start_anchor, (0, 0))
            psp = []
            if self.ends_at == spine_index:
                # Anchors that could possibly indicate the start of the next
                # section and therefore the end of this section.
                # self.possible_end_anchors is a set of anchors belonging to
                # toc entries with depth <= self.depth that are also not
                # ancestors of this entry.
                psp = [
                    anchor_map.get(x, (0, 0))
                    for x in self.possible_end_anchors
                ]
                psp = [x for x in psp if x >= start_pos]
            # The end position. The first anchor whose pos is >= start_pos
            # or if the end is not in this spine item, we set it to the column
            # after the right edge of the viewport
            end_pos = min(psp) if psp else (
                right if self.ends_at >= spine_index else (0, 0))
            if spine_index > self.starts_at and spine_index < self.ends_at:
                # The entire spine item is contained in this entry
                is_being_viewed = True
            elif (spine_index == self.starts_at and right > start_pos and
                  # This spine item contains the start
                  # The start position is before the end of the viewport
                  (spine_index != self.ends_at or left < end_pos)):
                # The end position is after the start of the viewport
                is_being_viewed = True
            elif (spine_index == self.ends_at and left < end_pos and
                  # This spine item contains the end
                  # The end position is after the start of the viewport
                  (spine_index != self.starts_at or right > start_pos)):
                # The start position is before the end of the viewport
                is_being_viewed = True

        changed = is_being_viewed != self.is_being_viewed
        self.is_being_viewed = is_being_viewed
        if changed:
            self.setFont(
                self.emphasis_font if is_being_viewed else self.normal_font)

    def set_current_search_result(self, yes):
        if yes and not self.is_current_search_result:
            self.setText(self.text() + ' ◄')
            self.is_current_search_result = True
        elif not yes and self.is_current_search_result:
            self.setText(self.text()[:-2])
            self.is_current_search_result = False

    def __repr__(self):
        return 'TOC Item: %s %s#%s' % (self.title, self.abspath, self.fragment)

    def __str__(self):
        return repr(self)
Exemple #56
0
 def build_font_obj(self):
     font_info = qt_app.original_font if self.current_font is None else self.current_font
     font = QFont(*(font_info[:4]))
     font.setStretch(font_info[4])
     return font
Exemple #57
0
class CompareSingle(QWidget):
    def __init__(self,
                 field_metadata,
                 parent=None,
                 revert_tooltip=None,
                 datetime_fmt='MMMM yyyy',
                 blank_as_equal=True,
                 fields=('title', 'authors', 'series', 'tags', 'rating',
                         'publisher', 'pubdate', 'identifiers', 'languages',
                         'comments', 'cover'),
                 db=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout()
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)
        revert_tooltip = revert_tooltip or _('Revert %s')
        self.current_mi = None
        self.changed_font = QFont(QApplication.font())
        self.changed_font.setBold(True)
        self.changed_font.setItalic(True)
        self.blank_as_equal = blank_as_equal

        self.widgets = OrderedDict()
        row = 0

        for field in fields:
            m = field_metadata[field]
            dt = m['datatype']
            extra = None
            if 'series' in {field, dt}:
                cls = SeriesEdit
            elif field == 'identifiers':
                cls = IdentifiersEdit
            elif field == 'languages':
                cls = LanguagesEdit
            elif 'comments' in {field, dt}:
                cls = CommentsEdit
            elif 'rating' in {field, dt}:
                cls = RatingsEdit
            elif dt == 'datetime':
                extra = datetime_fmt
                cls = DateEdit
            elif field == 'cover':
                cls = CoverView
            elif dt in {'text', 'enum'}:
                cls = LineEdit
            else:
                continue
            neww = cls(field, True, self, m, extra)
            neww.changed.connect(partial(self.changed, field))
            if isinstance(neww, EditWithComplete):
                try:
                    neww.update_items_cache(db.new_api.all_field_names(field))
                except ValueError:
                    pass  # A one-one field like title
            if isinstance(neww, SeriesEdit):
                neww.set_db(db.new_api)
            oldw = cls(field, False, self, m, extra)
            newl = QLabel('&%s:' % m['name'])
            newl.setBuddy(neww)
            button = RightClickButton(self)
            button.setIcon(QIcon(I('back.png')))
            button.clicked.connect(partial(self.revert, field))
            button.setToolTip(revert_tooltip % m['name'])
            if field == 'identifiers':
                button.m = m = QMenu(button)
                button.setMenu(m)
                button.setPopupMode(QToolButton.DelayedPopup)
                m.addAction(button.toolTip()).triggered.connect(button.click)
                m.actions()[0].setIcon(button.icon())
                m.addAction(_('Merge identifiers')).triggered.connect(
                    self.merge_identifiers)
                m.actions()[1].setIcon(QIcon(I('merge.png')))
            elif field == 'tags':
                button.m = m = QMenu(button)
                button.setMenu(m)
                button.setPopupMode(QToolButton.DelayedPopup)
                m.addAction(button.toolTip()).triggered.connect(button.click)
                m.actions()[0].setIcon(button.icon())
                m.addAction(_('Merge tags')).triggered.connect(self.merge_tags)
                m.actions()[1].setIcon(QIcon(I('merge.png')))

            self.widgets[field] = Widgets(neww, oldw, newl, button)
            for i, w in enumerate((newl, neww, button, oldw)):
                c = i if i < 2 else i + 1
                if w is oldw:
                    c += 1
                l.addWidget(w, row, c)
            row += 1

        self.sep = f = QFrame(self)
        f.setFrameShape(f.VLine)
        l.addWidget(f, 0, 2, row, 1)
        self.sep2 = f = QFrame(self)
        f.setFrameShape(f.VLine)
        l.addWidget(f, 0, 4, row, 1)
        if 'comments' in self.widgets and not gprefs.get(
                'diff_widget_show_comments_controls', True):
            self.widgets['comments'].new.hide_toolbars()

    def save_comments_controls_state(self):
        if 'comments' in self.widgets:
            vis = self.widgets['comments'].new.toolbars_visible
            if vis != gprefs.get('diff_widget_show_comments_controls', True):
                gprefs.set('diff_widget_show_comments_controls', vis)

    def changed(self, field):
        w = self.widgets[field]
        if not w.new.same_as(w.old) and (not self.blank_as_equal
                                         or not w.new.is_blank):
            w.label.setFont(self.changed_font)
        else:
            w.label.setFont(QApplication.font())

    def revert(self, field):
        widgets = self.widgets[field]
        neww, oldw = widgets[:2]
        neww.current_val = oldw.current_val

    def merge_identifiers(self):
        widgets = self.widgets['identifiers']
        neww, oldw = widgets[:2]
        val = neww.as_dict
        val.update(oldw.as_dict)
        neww.as_dict = val

    def merge_tags(self):
        widgets = self.widgets['tags']
        neww, oldw = widgets[:2]
        val = oldw.value
        lval = {icu_lower(x) for x in val}
        extra = [x for x in neww.value if icu_lower(x) not in lval]
        if extra:
            neww.value = val + extra

    def __call__(self, oldmi, newmi):
        self.current_mi = newmi
        self.initial_vals = {}
        for field, widgets in self.widgets.iteritems():
            widgets.old.from_mi(oldmi)
            widgets.new.from_mi(newmi)
            self.initial_vals[field] = widgets.new.current_val

    def apply_changes(self):
        changed = False
        for field, widgets in self.widgets.iteritems():
            val = widgets.new.current_val
            if val != self.initial_vals[field]:
                widgets.new.to_mi(self.current_mi)
                changed = True
        return changed
Exemple #58
0
 def clear_button(self, which):
     b = getattr(self, 'button%d' % which)
     s = getattr(self, 'shortcut%d' % which, None)
     b.setText(
         _('None') if s is None else s.toString(QKeySequence.NativeText))
     b.setFont(QFont())
Exemple #59
0
 def __init__(self, parent=None, is_half_star=False):
     QAbstractListModel.__init__(self, parent)
     self.is_half_star = is_half_star
     self.rating_font = QFont(rating_font())
     self.null_text = _('Not rated')
Exemple #60
0
 def mark_item_as_current(self, item):
     font = QFont(self.font())
     font.setItalic(True)
     font.setBold(True)
     item.setData(0, Qt.FontRole, font)