Exemple #1
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 #2
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 #3
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 #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)
        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 #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)
        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 #6
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 #7
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 #8
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 #9
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 #10
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 #11
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 #12
0
class Category(QWidget):  # {{{

    plugin_activated = pyqtSignal(object)

    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 }')
        lh = QApplication.instance().line_height
        self.bar.setIconSize(QSize(2*lh, 2*lh))
        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.replace('&', '&&'), 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)
            if hasattr(w, 'setAutoRaise'):
                w.setAutoRaise(True)
            w.setMinimumWidth(100)

    def triggered(self, plugin, *args):
        self.plugin_activated.emit(plugin)
Exemple #13
0
    def process_duplicates(self, db, duplicates):
        ta = _('%(title)s by %(author)s [%(formats)s]')
        bf = QFont(self.dup_list.font())
        bf.setBold(True)
        itf = QFont(self.dup_list.font())
        itf.setItalic(True)

        for mi, cover, formats in duplicates:
            # formats is a list of file paths
            # Grab just the extension and display to the user
            # Based only off the file name, no file type tests are done.
            incoming_formats = ', '.join(os.path.splitext(path)[-1].replace('.', '').upper() for path in formats)
            item = QTreeWidgetItem([ta%dict(
                title=mi.title, author=mi.format_field('authors')[1],
                formats=incoming_formats)] , 0)
            item.setCheckState(0, Qt.Checked)
            item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
            item.setData(0, Qt.FontRole, bf)
            item.setData(0, Qt.UserRole, (mi, cover, formats))
            matching_books = db.books_with_same_title(mi)

            def add_child(text):
                c = QTreeWidgetItem([text], 1)
                c.setFlags(Qt.ItemIsEnabled)
                item.addChild(c)
                return c

            add_child(_('Already in calibre:')).setData(0, Qt.FontRole, itf)

            for book_id in matching_books:
                aut = [a.replace('|', ',') for a in (db.authors(book_id,
                    index_is_id=True) or '').split(',')]
                add_child(ta%dict(
                    title=db.title(book_id, index_is_id=True),
                    author=authors_to_string(aut),
                    formats=db.formats(book_id, index_is_id=True,
                                       verify_formats=False)))
            add_child('')

            yield item
Exemple #14
0
 def data(self, index, role):
     row = index.row()
     try:
         tweak = self.tweaks[row]
     except:
         return None
     if role == Qt.DisplayRole:
         return textwrap.fill(tweak.name, 40)
     if role == Qt.FontRole and tweak.is_customized:
         ans = QFont()
         ans.setBold(True)
         return ans
     if role == Qt.ToolTipRole:
         tt = _('This tweak has it default value')
         if tweak.is_customized:
             tt = '<p>'+_('This tweak has been customized')
             tt += '<pre>'
             for varn, val in tweak.custom_values.iteritems():
                 tt += '%s = %r\n\n'%(varn, val)
         return textwrap.fill(tt)
     if role == Qt.UserRole:
         return tweak
     return None
Exemple #15
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())
        painter.setPen(self.line_number_palette.color(QPalette.Text))
        change_starts = {x[0] for x in self.changes}

        while block.isValid() and top <= ev.rect().bottom():
            r = ev.rect()
            if block.isVisible() and bottom >= r.top():
                text = unicode(self.line_number_map.get(num, ''))
                is_start = text != '-' and num in change_starts
                if is_start:
                    painter.save()
                    f = QFont(self.font())
                    f.setBold(True)
                    painter.setFont(f)
                    painter.setPen(self.line_number_palette.color(QPalette.BrightText))
                if text == '-':
                    painter.drawLine(r.left() + 2, (top + bottom)//2, r.right() - 2, (top + bottom)//2)
                else:
                    if self.right:
                        painter.drawText(r.left() + 3, top, r.right(), self.fontMetrics().height(),
                                Qt.AlignLeft, text)
                    else:
                        painter.drawText(r.left() + 2, top, r.right() - 5, self.fontMetrics().height(),
                                Qt.AlignRight, text)
                if is_start:
                    painter.restore()
            block = block.next()
            top = bottom
            bottom = top + int(self.blockBoundingRect(block).height())
            num += 1
Exemple #16
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 #17
0
 def mark_item_as_current(self, item):
     font = QFont(self.font())
     font.setItalic(True)
     font.setBold(True)
     item.setData(0, Qt.FontRole, font)
Exemple #18
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
        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 anchor_map.iteritems()}

        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 #19
0
    def __init__(self, gui, icon, guidb, plugin_path, ui_exit, action_type):
        parent = gui
        unique_pref_name = 'library_codes:gui_parameters_dialog'
        SizePersistedDialog.__init__(self, parent, unique_pref_name)
        #-----------------------------------------------------
        self.gui = gui
        self.guidb = guidb
        #-----------------------------------------------------
        self.icon = icon
        #-----------------------------------------------------
        self.plugin_path = plugin_path
        #-----------------------------------------------------
        self.ui_exit = ui_exit
        #-----------------------------------------------------
        self.action_type = action_type
        #-----------------------------------------------------
        self.myparentprefs = collections.OrderedDict([])
        prefsdefaults = deepcopy(prefs.defaults)
        tmp_list = []
        #~ for k,v in prefs.iteritems():
        for k, v in iteritems(prefs):
            tmp_list.append(k)
        #END FOR
        #~ for k,v in prefsdefaults.iteritems():
        for k, v in iteritems(prefsdefaults):
            tmp_list.append(k)
        #END FOR
        tmp_set = set(tmp_list)
        tmp_list = list(tmp_set)  #no duplicates
        del tmp_set
        tmp_list.sort()
        for k in tmp_list:
            self.myparentprefs[k] = " "  # ordered by key
        #END FOR
        del tmp_list
        #~ for k,v in prefs.iteritems():
        for k, v in iteritems(prefs):
            self.myparentprefs[k] = v
        #END FOR
        #~ for k,v in prefsdefaults.iteritems():
        for k, v in iteritems(prefsdefaults):
            if not k in prefs:
                prefs[k] = v
            else:
                if not prefs[k] > " ":
                    prefs[k] = v
            if not k in self.myparentprefs:
                self.myparentprefs[k] = v
            else:
                if not self.myparentprefs[k] > " ":
                    self.myparentprefs[k] = v
        #END FOR
        #~ for k,v in self.myparentprefs.iteritems():
        for k, v in iteritems(self.myparentprefs):
            prefs[k] = v
        #END FOR
        prefs  #prefs now synched
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.param_dict = collections.OrderedDict([])
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.init_tooltips_for_parent()
        self.setToolTip(self.parent_tooltip)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        # Tab 0: LibraryCodesTab
        #-----------------------------------------------------
        #-----------------------------------------------------
        from calibre_plugins.library_codes.library_codes_dialog import LibraryCodesTab
        self.LibraryCodesTab = LibraryCodesTab(self.gui, self.guidb,
                                               self.myparentprefs,
                                               self.param_dict, self.ui_exit,
                                               self.save_dialog_geometry)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #    Parent             LibraryCodesDialog
        #-----------------------------------------------------
        font = QFont()
        font.setBold(False)
        font.setPointSize(10)

        tablabel_font = QFont()
        tablabel_font.setBold(False)
        tablabel_font.setPointSize(10)

        #-----------------------------------------------------
        self.setWindowTitle('Library Codes')
        self.setWindowIcon(icon)
        #-----------------------------------------------------
        self.layout_frame = QVBoxLayout()
        self.layout_frame.setAlignment(Qt.AlignLeft)
        self.setLayout(self.layout_frame)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        n_width = 600

        self.LCtabWidget = QTabWidget()
        self.LCtabWidget.setMaximumWidth(n_width)
        self.LCtabWidget.setFont(tablabel_font)

        self.LCtabWidget.addTab(
            self.LibraryCodesTab,
            "Derivation from ISBN or ISSN or Author/Title")
        self.LibraryCodesTab.setToolTip(
            "<p style='white-space:wrap'>Derive Library Codes DDC and/or LCC and/or OCLC-OWI from ISBN or ISSN or Author/Title.  Visit: http://classify.oclc.org/classify2/ "
        )
        self.LibraryCodesTab.setMaximumWidth(n_width)

        #-----------------------------------------------------
        self.layout_frame.addWidget(self.LCtabWidget)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.resize_dialog()  # inherited from SizePersistedDialog
        #-----------------------------------------------------
        self.LCtabWidget.setCurrentIndex(0)
Exemple #20
0
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 ', '.join(x.strip() for x in (self.accounts[account][0] or '').split(','))
            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] = re.sub(',+', ',', re.sub(r'\s+', ',', 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()
Exemple #21
0
class StatusBar(QStatusBar):  # {{{

    def __init__(self, parent=None):
        QStatusBar.__init__(self, parent)
        self.version = get_version()
        self.base_msg = '%s %s' % (__appname__, self.version)
        self.device_string = ''
        self.update_label = UpdateLabel('')
        self.total = self.current = self.selected = self.library_total = 0
        self.addPermanentWidget(self.update_label)
        self.update_label.setVisible(False)
        self._font = QFont()
        self._font.setBold(True)
        self.setFont(self._font)
        self.defmsg = QLabel('')
        self.defmsg.setFont(self._font)
        self.addWidget(self.defmsg)
        self.set_label()

    def initialize(self, systray=None):
        self.systray = systray
        self.notifier = get_notifier(systray)

    def device_connected(self, devname):
        self.device_string = _('Connected ') + devname
        self.set_label()

    def update_state(self, library_total, total, current, selected):
        self.library_total = library_total
        self.total, self.current, self.selected = total, current, selected
        self.set_label()

    def set_label(self):
        try:
            self._set_label()
        except:
            import traceback
            traceback.print_exc()

    def _set_label(self):
        msg = self.base_msg
        if self.device_string:
            msg += ' ..::.. ' + self.device_string
        else:
            msg += _(' %(created)s %(name)s') % dict(created=_('created by'), name='Kovid Goyal')

        if self.total != self.current:
            base = _('%(num)d of %(total)d books') % dict(num=self.current, total=self.total)
        else:
            base = _('%d books') % self.total
        if self.selected > 0:
            base = _('%(num)s, %(sel)d selected') % dict(num=base, sel=self.selected)
        if self.library_total != self.total:
            base = _('{0}, {1} total').format(base, self.library_total)

        self.defmsg.setText(u'%s\xa0\xa0\xa0\xa0[%s]' % (msg, base))
        self.clearMessage()

    def device_disconnected(self):
        self.device_string = ''
        self.set_label()

    def show_message(self, msg, timeout=0, show_notification=True):
        self.showMessage(msg, timeout)
        if self.notifier is not None and not config['disable_tray_notification'] and show_notification:
            if isosx and isinstance(msg, unicode):
                try:
                    msg = msg.encode(preferred_encoding)
                except UnicodeEncodeError:
                    msg = msg.encode('utf-8')
            self.notifier(msg)

    def clear_message(self):
        self.clearMessage()
Exemple #22
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
        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 anchor_map.items()}

        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 #23
0
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 = list(self.accounts)
        self.do_sort()
        self.headers = [
            _('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(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(
                    as_unicode(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.SortOrder.AscendingOrder):
        nsort = (column, order == Qt.SortOrder.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.ItemDataRole.DisplayRole and orientation == Qt.Orientation.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.ItemDataRole.UserRole:
            return (account, self.accounts[account])
        if role == Qt.ItemDataRole.ToolTipRole:
            return self.tooltips[col]
        if role in [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole]:
            if col == 0:
                return (account)
            if col == 1:
                return ', '.join(
                    x.strip()
                    for x in (self.accounts[account][0] or '').split(','))
            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.ItemDataRole.FontRole and self.accounts[account][2]:
            return self.default_font
        if role == Qt.ItemDataRole.CheckStateRole and col == 3:
            return (Qt.CheckState.Checked
                    if self.accounts[account][1] else Qt.CheckState.Unchecked)
        return None

    def flags(self, index):
        if index.column() == 3:
            return QAbstractTableModel.flags(
                self, index) | Qt.ItemFlag.ItemIsUserCheckable
        else:
            return QAbstractTableModel.flags(
                self, index) | Qt.ItemFlag.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] = as_unicode(value or '')
        elif col == 4:
            self.aliases.pop(account, None)
            aval = as_unicode(value or '').strip()
            if aval:
                self.aliases[account] = aval
        elif col == 5:
            self.tags.pop(account, None)
            aval = as_unicode(value or '').strip()
            if aval:
                self.tags[account] = aval
        elif col == 1:
            self.accounts[account][0] = re.sub(
                ',+', ',', re.sub(r'\s+', ',',
                                  as_unicode(value or '').upper()))
        elif col == 0:
            na = as_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 + unicode_type(c)
        auto_send = len(self.accounts) < 1
        self.beginResetModel()
        self.accounts[y] = [
            'MOBI, EPUB', auto_send,
            len(self.account_order) == 0
        ]
        self.account_order = list(self.accounts)
        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)
            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()
Exemple #24
0
class StatusBar(QStatusBar):  # {{{
    def __init__(self, parent=None):
        QStatusBar.__init__(self, parent)
        self.version = get_version()
        self.base_msg = '%s %s' % (__appname__, self.version)
        self.device_string = ''
        self.update_label = UpdateLabel('')
        self.total = self.current = self.selected = self.library_total = 0
        self.addPermanentWidget(self.update_label)
        self.update_label.setVisible(False)
        self._font = QFont()
        self._font.setBold(True)
        self.setFont(self._font)
        self.defmsg = VersionLabel(self)
        self.defmsg.setFont(self._font)
        self.addWidget(self.defmsg)
        self.set_label()

    def initialize(self, systray=None):
        self.systray = systray
        self.notifier = get_notifier(systray)

    def device_connected(self, devname):
        self.device_string = _('Connected ') + devname
        self.set_label()

    def update_state(self, library_total, total, current, selected):
        self.library_total = library_total
        self.total, self.current, self.selected = total, current, selected
        self.set_label()

    def set_label(self):
        try:
            self._set_label()
        except:
            import traceback
            traceback.print_exc()

    def _set_label(self):
        msg = self.base_msg
        if self.device_string:
            msg += ' ..::.. ' + self.device_string
        else:
            msg += _(' %(created)s %(name)s') % dict(created=_('created by'),
                                                     name='Kovid Goyal')

        if self.total != self.current:
            base = _('%(num)d of %(total)d books') % dict(num=self.current,
                                                          total=self.total)
        else:
            base = ngettext('one book', '{} books',
                            self.total).format(self.total)
        if self.selected > 0:
            base = ngettext('%(num)s, %(sel)d selected',
                            '%(num)s, %(sel)d selected', self.selected) % dict(
                                num=base, sel=self.selected)
        if self.library_total != self.total:
            base = _('{0}, {1} total').format(base, self.library_total)

        self.defmsg.setText(u'\xa0%s\xa0\xa0\xa0\xa0[%s]' % (msg, base))
        self.clearMessage()

    def device_disconnected(self):
        self.device_string = ''
        self.set_label()

    def show_message(self, msg, timeout=0, show_notification=True):
        self.showMessage(msg, timeout)
        if self.notifier is not None and not config[
                'disable_tray_notification'] and show_notification:
            if isosx and isinstance(msg, unicode):
                try:
                    msg = msg.encode(preferred_encoding)
                except UnicodeEncodeError:
                    msg = msg.encode('utf-8')
            self.notifier(msg)

    def clear_message(self):
        self.clearMessage()
Exemple #25
0
 def getFont(self):
     font = QFont()
     font.setBold(True)
     font.setUnderline(True)
     return font
class WheelScene(QGraphicsScene):
    def __init__(self,
                 radius=200,
                 parent=None,
                 categories=[],
                 loglevel=logging.DEBUG):
        super(WheelScene, self).__init__(parent)
        self.logger = logs.build_logger(__name__, loglevel)
        self.loglevel = loglevel
        #super(TestWheelScene, self).__init__(parent)
        families = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        if len(categories) == 0:
            sector_names = [
                "freespin", "bankruptcy", "dogs", "cats", "PC", "OP",
                "loseturn", "colors", "numbers", "states", "countries",
                "people"
            ]
        else:
            sector_names = categories
        self.radius = radius
        total = 0
        set_angle = 0
        count1 = 0
        colours = []
        total = sum(families)

        for count in range(len(families)):
            number = []
            for count in range(3):
                number.append(random.randrange(0, 255))
            colours.append(QColor(number[0], number[1], number[2]))

        for i, family in enumerate(families):
            # Max span is 5760, so we have to calculate corresponding span angle
            angle = round(float(family * 5760) / total)
            subangle = round(float((family * 5760) / total / 2))
            subangle += 120
            # ellipse = QGraphicsEllipseItem(0,0,400,400)
            ellipse = QGraphicsEllipseItem(0, 0, self.radius * 2,
                                           self.radius * 2)
            #ellipse.setPos(QPointF(0, 0))
            # ellipse.setPos(ellipse.boundingRect().center())
            #print(ellipse.rect().center())
            #ellipse.setTransformOriginPoint(200, 200)
            # ellipse.setRect(-200,200,400,400)
            ellipse.setStartAngle(set_angle)
            ellipse.setSpanAngle(angle)
            ellipse.setBrush(colours[count1])
            # https://stackoverflow.com/questions/3312016/text-in-a-qgraphicsscene
            text = QGraphicsTextItem()

            #text.setFont(QFont("Helvetica", 65))
            #text.setTextWidth(20)
            # print("angle=%s, set_angle=%s, sector_name=%s" % (angle, set_angle, sector_names[i]))

            document = QtGui.QTextDocument()
            document.setDocumentMargin(0)
            text.setDocument(document)
            self.font = QFont()
            self.default_font_size = 14
            self.font.setPointSize(self.default_font_size)
            self.font.setBold(True)
            self.font.setFamily("Helvetica")
            self.font.setCapitalization(True)
            text.setPlainText(textwrap.fill(sector_names[i], width=1))
            text.setFont(self.font)

            # print("render_piece label=%s, textangle=%s sub_angle=%s, set_angle=%s, angle=%s" %
            #                         (sector_names[i],
            #                          ((set_angle+subangle)/5760)*360,
            #                          subangle,
            #                          set_angle,
            #                          angle))
            #print("textpos=%s" % ellipse.rect().center())

            reduction_factor = 0
            while text.boundingRect().height() > self.radius - (self.radius *
                                                                .01):

                # print("category=%s, real_height=%s, radius=%s" % (sector_names[i],
                #                                                   text.boundingRect().height(),
                #                                                   self.radius))
                # print("trying changing reduction factor from %s to %s" % (reduction_factor,
                #                                                           reduction_factor + 1))
                reduction_factor += 1
                self.font.setPointSize(self.default_font_size -
                                       reduction_factor)
                text.deleteLater()
                text = None
                text = QGraphicsTextItem()
                text.setDocument(document)
                #text.setFont(QFont("Helvetica", 65- reduction_factor))
                text.setPlainText(textwrap.fill(sector_names[i], width=1))
                text.setFont(self.font)

            text.setZValue(2)

            if sector_names[i] == False:
                #scrap this part for now until we can figure out how to safely offset titles.
                # print("ellipse center=%s" % ellipse.rect().center())
                hypotenuse = self.radius * .01
                degree_subangle = (((set_angle + subangle) / 5760) * 360)
                degree_subangle += 90
                degree_subangle = degree_subangle % 360
                doTranslate = True
                if doTranslate:
                    #math.cos(degree_subangle) = adjacent/hypotenuse
                    x = math.cos(degree_subangle) * hypotenuse
                    y = math.sin(degree_subangle) * hypotenuse
                    extra = True
                    if extra:
                        if degree_subangle > 0. and degree_subangle < 90.:
                            pass
                        elif degree_subangle > 90 and degree_subangle < 180:
                            pass
                        elif degree_subangle > 180 and degree_subangle < 270:
                            pass
                            #y = -y
                        elif degree_subangle > 270:
                            pass
                    target = ellipse.rect().center()
                    target.setX(x + target.x())
                    target.setY(y + target.y())
                    # print("target=%s" % target)
                    print(
                        "do_move_text_offset cat=%s, offset=%s degree_subangle=%s, x=%s, y=%s"
                        % (sector_names[i], target, degree_subangle, x, y))
                    text.setPos(target)
                else:
                    text.setPos(ellipse.rect().center())
            text.setPos(ellipse.rect().center())
            self.logger.debug("ellipse rect: %s" % ellipse.rect())

            text.setRotation((((set_angle + subangle) / 5760) * 360))
            #text.setRotation(30)
            # set_angle+=1
            set_angle += angle
            count1 += 1
            self.addItem(ellipse)
            self.addItem(text)
        self.setSceneRect(0, 0, self.radius * 2, self.radius * 2)
        self.logger.debug("scenesize= %s" % self.sceneRect())
Exemple #27
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)
        self.fm = QFontMetrics(self.current_font)

    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 sectionSizeFromContents(self, logical_index):
        self.ensurePolished()
        opt = QStyleOptionHeader()
        self.initStyleOption(opt)
        opt.section = logical_index
        opt.orientation = self.orientation()
        opt.fontMetrics = self.fm
        model = self.parent().model()
        opt.text = unicode(model.headerData(logical_index, opt.orientation, Qt.DisplayRole) or '')
        if opt.orientation == Qt.Vertical:
            try:
                val = model.headerData(logical_index, opt.orientation, Qt.DecorationRole)
                if val is not None:
                    opt.icon = val
                opt.iconAlignment = Qt.AlignVCenter
            except (IndexError, ValueError, TypeError):
                pass
        if self.isSortIndicatorShown():
            opt.sortIndicator = QStyleOptionHeader.SortDown
        return self.style().sizeFromContents(QStyle.CT_HeaderSection, opt, QSize(), self)

    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
        opt.fontMetrics = self.fm
        model = self.parent().model()
        style = self.style()
        margin = 2 * style.pixelMetric(style.PM_HeaderMargin, None, self)
        if self.isSortIndicatorShown() and self.sortIndicatorSection() == logical_index:
            opt.sortIndicator = QStyleOptionHeader.SortDown if self.sortIndicatorOrder() == Qt.AscendingOrder else QStyleOptionHeader.SortUp
            margin += style.pixelMetric(style.PM_HeaderMarkSize, None, self)
        opt.text = unicode(model.headerData(logical_index, opt.orientation, Qt.DisplayRole) or '')
        if self.textElideMode() != Qt.ElideNone:
            opt.text = opt.fontMetrics.elidedText(opt.text, Qt.ElideRight, rect.width() - margin)
        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:
                val = model.headerData(logical_index, opt.orientation, Qt.DecorationRole)
                if val is not None:
                    opt.icon = val
                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 #28
0
    def drawGridX(self, painter):
        rect = self.getRectPlotter()
        if not rect.isValid():
            return
        painter.save()

        painter.setFont(self._fontGrid)
        painter.setPen(QPen(Qt.black))
        painter.setBrush(Qt.NoBrush)

        # Axis ticks
        dxmsec = rect.width() / self._plotterScale.Scale.X.span()
        fontMetricsF = QFontMetricsF(self._fontGrid)
        index = findIndex(fontMetricsF.width('   00:00   ') / dxmsec, BasePlotter._mSecs_for_grid)
        msec0 = self._plotterScale.Scale.X.Min
        offset = findOffset(msec0, BasePlotter._mSecs_for_grid[index])
        dx = dxmsec * BasePlotter._mSecs_for_grid[index]
        step = BasePlotter._mSecs_for_grid[index]

        for x in numpy.arange(rect.left() - dxmsec * offset, rect.right(), dx):
            if x < rect.left():
                continue

            painter.save()

            heightTick = 3
            datetimelabel = QDateTime.fromMSecsSinceEpoch(msec0, Qt.UTC)

            if step >= 60000:  # больше минуты
                if step >= 86400000:  # больше суток
                    label = datetimelabel.toString('dd.MM.yy')
                    if datetimelabel.time().minute() == 0:
                        heightTick = 8
                        painter.setPen(Qt.SolidLine)
                else:
                    t0 = QDateTime.fromMSecsSinceEpoch(self._plotterScale.Scale.X.Min, Qt.UTC)
                    t1 = QDateTime.fromMSecsSinceEpoch(self._plotterScale.Scale.X.Max, Qt.UTC)
                    if (datetimelabel.time().hour() == 0 and datetimelabel.time().minute() == 0) and (
                                t1.date() > t0.date()):  # Метка даты. Появляется,если листаем график между днями
                        font = QFont(painter.font().family(), painter.font().pointSize())
                        font.setBold(True)
                        painter.setFont(font)
                        label = datetimelabel.toString('dd.MM.yy')
                    else:
                        label = datetimelabel.toString('hh:mm')
                        if datetimelabel.time().minute() == 0:
                            heightTick = 8
                            painter.setPen(Qt.SolidLine)
                        if datetimelabel.time().minute() == 30:
                            heightTick = 6
                            painter.setPen(Qt.DashLine)
                        if datetimelabel.time().minute() == 15 or datetimelabel.time().minute() == 45:
                            heightTick = 4
                            painter.setPen(Qt.DashLine)
            else:
                label = datetimelabel.time().toString('hh:mm:ss')

            painter.drawLine(x, rect.bottom(), x, rect.top())
            rect_label = QRectF(x - fontMetricsF.width(label) / 2, rect.bottom() + heightTick,
                                fontMetricsF.width(label), 2 * fontMetricsF.height())
            painter.drawLine(x, rect.bottom() - heightTick, x, rect.bottom() + heightTick)
            painter.drawText(rect_label, label)

            msec0 += step

            painter.restore()

        painter.restore()
Exemple #29
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 #30
0
 def mark_item_as_current(self, item):
     font = QFont(self.font())
     font.setItalic(True)
     font.setBold(True)
     item.setData(0, Qt.FontRole, font)
Exemple #31
0
class EmailAccounts(QAbstractTableModel):  # {{{
    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"),
                    ],
                ),
            )
        )

    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 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 == 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 = sorted(self.accounts.keys())
        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()
Exemple #32
0
    def __init__(self, mygui, myguidb, mymainprefs, myparam_dict, myuiexit,
                 mysavedialoggeometry):
        super(LibraryCodesTab, self).__init__()
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.gui = mygui
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.guidb = myguidb
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.lib_path = self.gui.library_view.model().db.library_path
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.mytabprefs = mymainprefs
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.param_dict = myparam_dict
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.ui_exit = myuiexit
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.save_dialog_geometry = mysavedialoggeometry
        #-----------------------------------------------------
        #-----------------------------------------------------
        font = QFont()
        font.setBold(False)
        font.setPointSize(10)
        #-----------------------------------------------------
        self.layout_top = QVBoxLayout()
        self.layout_top.setSpacing(0)
        self.layout_top.setAlignment(Qt.AlignLeft)
        self.setLayout(self.layout_top)
        #-----------------------------------------------------
        self.scroll_area_frame = QScrollArea()
        self.scroll_area_frame.setAlignment(Qt.AlignLeft)
        self.scroll_area_frame.setWidgetResizable(True)
        self.scroll_area_frame.ensureVisible(400, 400)

        self.layout_top.addWidget(
            self.scroll_area_frame
        )  # the scroll area is now the child of the parent of self.layout_top

        # NOTE: the self.scroll_area_frame.setWidget(self.scroll_widget) is at the end of the init() AFTER all children have been created and assigned to a layout...

        #-----------------------------------------------------
        self.scroll_widget = QWidget()
        self.layout_top.addWidget(
            self.scroll_widget
        )  # causes automatic reparenting of QWidget to the parent of self.layout_top, which is:  self .
        #-----------------------------------------------------
        self.layout_frame = QVBoxLayout()
        self.layout_frame.setSpacing(0)
        self.layout_frame.setAlignment(Qt.AlignLeft)

        self.scroll_widget.setLayout(
            self.layout_frame
        )  # causes automatic reparenting of any widget later added to self.layout_frame to the parent of self.layout_frame, which is:  QWidget .

        #-----------------------------------------------------
        self.lc_groupbox = QGroupBox('Settings:')
        self.lc_groupbox.setMaximumWidth(400)
        self.lc_groupbox.setToolTip(
            "<p style='white-space:wrap'>The settings that control 'Library Codes'.  Using only ISBN or ISSN or Author/Title, Library Codes for selected books will be derived using the Current Settings."
        )
        self.layout_frame.addWidget(self.lc_groupbox)

        self.lc_layout = QGridLayout()
        self.lc_groupbox.setLayout(self.lc_layout)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.spacing0 = QLabel()
        self.layout_frame.addWidget(self.spacing0)
        self.spacing0.setMaximumHeight(20)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.button_box = QDialogButtonBox()
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.setCenterButtons(True)

        self.layout_frame.addWidget(self.button_box)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.push_button_save_only = QPushButton("Save")
        self.push_button_save_only.clicked.connect(self.save_settings)
        self.push_button_save_only.setDefault(True)
        self.push_button_save_only.setFont(font)
        self.push_button_save_only.setToolTip(
            "<p style='white-space:wrap'>Save all user settings.")
        self.button_box.addButton(self.push_button_save_only, 0)

        self.push_button_exit_only = QPushButton("Exit")
        self.push_button_exit_only.clicked.connect(self.exit_only)
        self.push_button_exit_only.setDefault(False)
        self.push_button_exit_only.setFont(font)
        self.push_button_exit_only.setToolTip(
            "<p style='white-space:wrap'>Exit immediately without saving anything."
        )
        self.button_box.addButton(self.push_button_exit_only, 0)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------

        r = 4

        self.ddc_labelname = QLineEdit(self)
        self.ddc_labelname.setText(self.mytabprefs['DDC'])
        self.ddc_labelname.setFont(font)
        self.ddc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for DDC.<br><br>See:  https://www.oclc.org/dewey/features/summaries.en.html"
        )
        self.ddc_labelname.setMaximumWidth(100)
        self.lc_layout.addWidget(self.ddc_labelname, r, 0)

        self.ddc_activate_checkbox = QCheckBox(
            "Activate 'Dewey Decimal Code' Classification?")
        self.ddc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive DDC?")
        r = r + 1
        self.lc_layout.addWidget(self.ddc_activate_checkbox, r, 0)
        if prefs['DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.ddc_activate_checkbox.setChecked(True)
        else:
            self.ddc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing1 = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.spacing1, r, 0)
        self.spacing1.setMaximumHeight(10)
        #-----------------------------------------------------
        self.lcc_labelname = QLineEdit(self)
        self.lcc_labelname.setText(self.mytabprefs['LCC'])
        self.lcc_labelname.setFont(font)
        self.lcc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for LCC.<br><br>See: http://www.loc.gov/catdir/cpso/lcco/ "
        )
        self.lcc_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.lcc_labelname, r, 0)

        self.lcc_activate_checkbox = QCheckBox(
            "Activate 'Library of Congress Code' Classification?")
        self.lcc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive LCC?")
        r = r + 1
        self.lc_layout.addWidget(self.lcc_activate_checkbox, r, 0)
        if prefs['LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lcc_activate_checkbox.setChecked(True)
        else:
            self.lcc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing2 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing2, r, 0)
        self.spacing2.setMaximumHeight(10)
        #-----------------------------------------------------

        self.fast_labelname = QLineEdit(self)
        self.fast_labelname.setText(self.mytabprefs['FAST'])
        self.fast_labelname.setFont(font)
        self.fast_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for FAST Tag Values. "
        )
        self.fast_labelname.setMinimumWidth(100)
        self.fast_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.fast_labelname, r, 0)

        self.fast_activate_checkbox = QCheckBox("Activate 'FAST' Tags?")
        self.fast_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive FAST Tags?\
                                                                                                                    <br><br>Text.  Behaves like Tags. Not Names.<br><br>"
        )
        r = r + 1
        self.lc_layout.addWidget(self.fast_activate_checkbox, r, 0)
        if prefs['FAST_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.fast_activate_checkbox.setChecked(True)
        else:
            self.fast_activate_checkbox.setChecked(False)

        #-----------------------------------------------------
        self.spacing6 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing6, r, 0)
        self.spacing6.setMaximumHeight(10)
        #-----------------------------------------------------

        self.oclc_labelname = QLineEdit(self)
        self.oclc_labelname.setText(self.mytabprefs['OCLC'])
        self.oclc_labelname.setFont(font)
        self.oclc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for OCLC-OWI.<br><br>See: #http://classify.oclc.org/classify2/   "
        )
        self.oclc_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.oclc_labelname, r, 0)

        self.oclc_activate_checkbox = QCheckBox(
            "Activate 'Online Computer Library Center' Work ID Code?")
        self.oclc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive OCLC-OWI?")
        r = r + 1
        self.lc_layout.addWidget(self.oclc_activate_checkbox, r, 0)
        if self.mytabprefs['OCLC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.oclc_activate_checkbox.setChecked(True)
        else:
            self.oclc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing5 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing5, r, 0)
        self.spacing5.setMaximumHeight(10)
        #-----------------------------------------------------
        self.lc_author_details_labelname = QLineEdit(self)
        self.lc_author_details_labelname.setText(
            self.mytabprefs['EXTRA_AUTHOR_DETAILS'])
        self.lc_author_details_labelname.setFont(font)
        self.lc_author_details_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for 'LC Extra Author Details'.\
                                                                                                                              <br><br>Text.  Behaves like Tags. Not Names.<br><br>"
        )
        self.lc_author_details_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.lc_author_details_labelname, r, 0)

        self.lc_author_details_checkbox = QCheckBox(
            "Activate 'Library Codes Extra Author Details'?")
        self.lc_author_details_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to add (never delete or replace) any available Tag-like values to this Custom Column if they are associated with the OCLC-OWI Identifier?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_author_details_checkbox, r, 0)
        if self.mytabprefs['EXTRA_AUTHOR_DETAILS_IS_ACTIVE'] == unicode_type(
                S_TRUE):
            self.lc_author_details_checkbox.setChecked(True)
        else:
            self.lc_author_details_checkbox.setChecked(False)
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.spacing4 = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.spacing4, r, 0)
        self.spacing4.setMaximumHeight(10)
        #-----------------------------------------------------
        font.setBold(False)
        font.setPointSize(7)
        #-----------------------------------------------------
        self.push_button_autoadd_custom_columns = QPushButton(
            "Automatically Add Activated Custom Columns?")
        self.push_button_autoadd_custom_columns.clicked.connect(
            self.autoadd_custom_columns)
        self.push_button_autoadd_custom_columns.setDefault(False)
        self.push_button_autoadd_custom_columns.setFont(font)
        self.push_button_autoadd_custom_columns.setToolTip(
            "<p style='white-space:wrap'>Do you want to automatically add the Custom Columns selected above?<br><br>If you have any issues, please add them manually."
        )
        r = r + 4
        self.lc_layout.addWidget(self.push_button_autoadd_custom_columns, r, 0)
        self.push_button_autoadd_custom_columns.setMaximumWidth(250)
        #-----------------------------------------------------
        self.lc_custom_columns_generation_label = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.lc_custom_columns_generation_label, r, 0)
        self.lc_custom_columns_generation_label.setText(
            "                                                              ")
        self.lc_custom_columns_generation_label.setMaximumHeight(10)
        self.lc_custom_columns_generation_label.setFont(font)

        self.oclc_identifier_only_checkbox = QCheckBox(
            "Always Create OCLC-OWI as an 'Identifier' (à la ISBN)?")
        self.oclc_identifier_only_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to update Calibre's Identifiers for an Identifier of 'OCLC-OWI',\
                                                                                                                                 regardless of whether you want its own Custom Column updated?\
                                                                                                                                <br><br>REQUIRED to derive DDC/LCC using Author/Title."
        )
        r = r + 2
        self.lc_layout.addWidget(self.oclc_identifier_only_checkbox, r, 0)
        if prefs['OCLC_IDENTIFIER'] == unicode_type(S_TRUE):
            self.oclc_identifier_only_checkbox.setChecked(True)
        else:
            self.oclc_identifier_only_checkbox.setChecked(False)

        #-----------------------------------------------------
        self.spacing3 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing3, r, 0)
        self.spacing3.setMaximumHeight(10)
        #-----------------------------------------------------
        font.setBold(False)
        font.setPointSize(10)
        #-----------------------------------------------------
        self.lc_genre_labelname = QLineEdit(self)
        self.lc_genre_labelname.setText(self.mytabprefs['GENRE'])
        self.lc_genre_labelname.setFont(font)
        self.lc_genre_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for 'Genre'.\
                                                                                                                              <br><br>Text.  Behaves like Tags.<br><br>"
        )
        self.lc_genre_labelname.setMaximumWidth(100)
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_labelname, r, 0)

        self.lc_checkbox_buttongroup = QButtonGroup()
        self.lc_checkbox_buttongroup.setExclusive(True)

        self.lc_genre_ddc_checkbox = QCheckBox(
            "Update 'Genre' using DDC-to-Genre Mappings?")
        self.lc_genre_ddc_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want LC to update 'Genre' using the DDC-to-Genre mapping in Table _lc_genre_mapping?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_ddc_checkbox, r, 0)

        self.lc_genre_lcc_checkbox = QCheckBox(
            "Update 'Genre' using LCC-to-Genre Mappings?")
        self.lc_genre_lcc_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want LC to update 'Genre' using the LCC-to-Genre mapping in Table _lc_genre_mapping?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_lcc_checkbox, r, 0)

        self.lc_genre_inactive_checkbox = QCheckBox(
            "Do not update 'Genre' at all")
        self.lc_genre_inactive_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do no 'Genre' processing at all?")
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_inactive_checkbox, r, 0)

        self.lc_checkbox_buttongroup.addButton(self.lc_genre_ddc_checkbox)
        self.lc_checkbox_buttongroup.addButton(self.lc_genre_lcc_checkbox)
        self.lc_checkbox_buttongroup.addButton(self.lc_genre_inactive_checkbox)

        if self.mytabprefs['GENRE_DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_ddc_checkbox.setChecked(True)
        elif self.mytabprefs['GENRE_LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_lcc_checkbox.setChecked(True)
        elif self.mytabprefs['GENRE_IS_INACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_inactive_checkbox.setChecked(True)

        self.lc_exact_match_checkbox = QCheckBox(
            "DDC: Require an 'Exact Match', not a 'Best Match'?")
        self.lc_exact_match_checkbox.setToolTip(
            "<p style='white-space:wrap'>Check this checkbox if you want an exact DDC match to be required in Table _lc_genre_mapping.  Otherwise, a 'best match' will be used via progressive shortening from right to left, but not past any decimal point.  If there is no decimal point in a book's DDC, then no progressive shortening will be performed at all."
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_exact_match_checkbox, r, 0)

        if self.mytabprefs['GENRE_EXACT_MATCH'] == unicode_type(S_TRUE):
            self.lc_exact_match_checkbox.setChecked(True)

        self.spin_lcc = QSpinBox(self)
        self.spin_lcc.setMinimum(1)
        self.spin_lcc.setMaximum(50)
        self.spin_lcc.setProperty('value', prefs['GENRE_LCC_MATCH_LENGTH'])
        self.spin_lcc.setMaximumWidth(250)
        self.spin_lcc.setSuffix("    LCC: Maximum Length to Match")
        self.spin_lcc.setToolTip(
            "<p style='white-space:nowrap'>Maximum number of characters in the LCC that should be used to map to the 'Genre', starting from the left.  A maximum of 1 guarantees a (broad) match.\
                                                                                                   <br><br>LCCs are structured with either 1 or 2 beginning letters, so 2-character LCCs have special matching logic.\
                                                                                                   <br><br>Example:   Assume maximum = 2 for a LCC of 'Q1':  Q1 would be attempted.  If it failed, because the 2nd digit is a number, 'Q' would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 2 for a LCC of 'PN1969.C65':  PN would be attempted.  If it failed, nothing else would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'PN1969.C65':  PN19 would be attempted.  If it failed, nothing else would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'Q1':  Q1 would be attempted.  If it failed, because the 2nd digit is a number, 'Q' would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'Q389':  Q389 would be attempted.  If it failed, nothing else would be attempted."
        )
        r = r + 2
        self.lc_layout.addWidget(self.spin_lcc, r, 0)

        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_widget.resize(self.sizeHint())
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_area_frame.setWidget(
            self.scroll_widget
        )  # now that all widgets have been created and assigned to a layout...
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_area_frame.resize(self.sizeHint())
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.resize(self.sizeHint())
Exemple #33
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')):
        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))
            oldw = cls(field, False, self, m, extra)
            newl = QLabel('&%s:' % m['name'])
            newl.setBuddy(neww)
            button = QToolButton(self)
            button.setIcon(QIcon(I('back.png')))
            button.clicked.connect(partial(self.revert, field))
            button.setToolTip(revert_tooltip % m['name'])
            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 __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 #34
0
class EmailAccounts(QAbstractTableModel):  # {{{
    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')
                ])))

    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 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 == 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 = sorted(self.accounts.keys())
        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()
Exemple #35
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