Example #1
0
    def __init__(self, rootWidget):
        QWidget.__init__(self, ctx.mainScreen)
        self.ui = Ui_connectionWidget()
        self.ui.setupUi(self)
        self.setStyleSheet("""
                QFrame#mainFrame {
                    background-image: url(:/gui/pics/transBlack.png);
                    border: 1px solid #BBB;
                    border-radius:8px;
                }
                QWidget#autoPartQuestion {
                    background-image: url(:/gui/pics/trans.png);
                }
        """)

        self.rootWidget = rootWidget
        self.needsExecute = False
        self.ui.buttonCancel.clicked.connect(self.hide)
        self.ui.buttonConnect.clicked.connect(self.slotUseSelected)

        self.connections = getConnectionList()
        if self.connections:
            for package in self.connections.keys():
                for connection in self.connections[package]:
                    ci = ConnectionItem(self.ui.connectionList, unicode(str(connection)), package)

            self.ui.connectionList.setCurrentRow(0)
            self.resize(ctx.mainScreen.size())
    def make_widgets(self, parent, main_widget_class, extra_label_text=''):
        w = QWidget(parent)
        self.widgets = [QLabel('&'+self.col_metadata['name']+':', w), w]
        l = QHBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        w.setLayout(l)
        self.main_widget = main_widget_class(w)
        l.addWidget(self.main_widget)
        l.setStretchFactor(self.main_widget, 10)
        self.a_c_checkbox = QCheckBox(_('Apply changes'), w)
        l.addWidget(self.a_c_checkbox)
        self.ignore_change_signals = True

        # connect to the various changed signals so we can auto-update the
        # apply changes checkbox
        if hasattr(self.main_widget, 'editTextChanged'):
            # editable combobox widgets
            self.main_widget.editTextChanged.connect(self.a_c_checkbox_changed)
        if hasattr(self.main_widget, 'textChanged'):
            # lineEdit widgets
            self.main_widget.textChanged.connect(self.a_c_checkbox_changed)
        if hasattr(self.main_widget, 'currentIndexChanged'):
            # combobox widgets
            self.main_widget.currentIndexChanged[int].connect(self.a_c_checkbox_changed)
        if hasattr(self.main_widget, 'valueChanged'):
            # spinbox widgets
            self.main_widget.valueChanged.connect(self.a_c_checkbox_changed)
        if hasattr(self.main_widget, 'dateTimeChanged'):
            # dateEdit widgets
            self.main_widget.dateTimeChanged.connect(self.a_c_checkbox_changed)
Example #3
0
    def __init__(self, preview, parent=None):
        QWidget.__init__(self, parent)
        self.preview = preview
        self.preview_is_refreshing = False
        self.refresh_needed = False
        preview.refresh_starting.connect(self.preview_refresh_starting)
        preview.refreshed.connect(self.preview_refreshed)
        self.apply_theme()
        self.setAutoFillBackground(True)
        self.update_timer = QTimer(self)
        self.update_timer.timeout.connect(self.update_data)
        self.update_timer.setSingleShot(True)
        self.update_timer.setInterval(500)
        self.now_showing = (None, None, None)

        self.stack = s = QStackedLayout(self)
        self.setLayout(s)

        self.clear_label = la = QLabel('<h3>' + _(
            'No style information found') + '</h3><p>' + _(
                'Move the cursor inside a HTML tag to see what styles'
                ' apply to that tag.'))
        la.setWordWrap(True)
        la.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        s.addWidget(la)

        self.box = box = Box(self)
        box.hyperlink_activated.connect(self.goto_declaration, type=Qt.QueuedConnection)
        self.scroll = sc = QScrollArea(self)
        sc.setWidget(box)
        sc.setWidgetResizable(True)
        s.addWidget(sc)
Example #4
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     self.layout = QTextLayout()
     self.layout.setFont(self.font())
     self.layout.setCacheEnabled(True)
     self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
     self.last_layout_rect = None
Example #5
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout(self)

        def add_row(*args):
            r = l.rowCount()
            if len(args) == 1:
                l.addWidget(args[0], r, 0, 1, 2)
            else:
                la = QLabel(args[0])
                l.addWidget(la, r, 0, Qt.AlignRight), l.addWidget(args[1], r, 1)
                la.setBuddy(args[1])

        self.heading = la = QLabel('<h2>\xa0')
        add_row(la)
        self.helpl = la = QLabel(_('For help with snippets, see the <a href="%s">User Manual</a>') %
                                 localize_user_manual_link('https://manual.calibre-ebook.com/snippets.html'))
        la.setOpenExternalLinks(True)
        add_row(la)

        self.name = n = QLineEdit(self)
        n.setPlaceholderText(_('The name of this snippet'))
        add_row(_('&Name:'), n)

        self.trig = t = QLineEdit(self)
        t.setPlaceholderText(_('The text used to trigger this snippet'))
        add_row(_('Tri&gger:'), t)

        self.template = t = QPlainTextEdit(self)
        la.setBuddy(t)
        add_row(_('&Template:'), t)

        self.types = t = QListWidget(self)
        t.setFlow(t.LeftToRight)
        t.setWrapping(True), t.setResizeMode(t.Adjust), t.setSpacing(5)
        fm = t.fontMetrics()
        t.setMaximumHeight(2*(fm.ascent() + fm.descent()) + 25)
        add_row(_('&File types:'), t)
        t.setToolTip(_('Which file types this snippet should be active in'))

        self.frame = f = QFrame(self)
        f.setFrameShape(f.HLine)
        add_row(f)
        self.test = d = SnippetTextEdit('', self)
        d.snippet_manager.snip_func = self.snip_func
        d.setToolTip(_('You can test your snippet here'))
        d.setMaximumHeight(t.maximumHeight() + 15)
        add_row(_('T&est:'), d)

        i = QListWidgetItem(_('All'), t)
        i.setData(Qt.UserRole, '*')
        i.setCheckState(Qt.Checked)
        i.setFlags(i.flags() | Qt.ItemIsUserCheckable)
        for ftype in sorted(all_text_syntaxes):
            i = QListWidgetItem(ftype, t)
            i.setData(Qt.UserRole, ftype)
            i.setCheckState(Qt.Checked)
            i.setFlags(i.flags() | Qt.ItemIsUserCheckable)

        self.creating_snippet = False
Example #6
0
    def __init__(self, vertical, parent=None):
        QWidget.__init__(self, parent)
        self.last_data = {}
        self.setAcceptDrops(True)
        self._layout = DetailsLayout(vertical, self)
        self.setLayout(self._layout)
        self.current_path = ''

        self.cover_view = CoverView(vertical, self)
        self.cover_view.search_internet.connect(self.search_internet)
        self.cover_view.cover_changed.connect(self.cover_changed.emit)
        self.cover_view.open_cover_with.connect(self.open_cover_with.emit)
        self.cover_view.cover_removed.connect(self.cover_removed.emit)
        self._layout.addWidget(self.cover_view)
        self.book_info = BookInfo(vertical, self)
        self.book_info.search_internet = self.search_internet
        self.book_info.search_requested = self.search_requested.emit
        self._layout.addWidget(self.book_info)
        self.book_info.link_clicked.connect(self.handle_click)
        self.book_info.remove_format.connect(self.remove_specific_format)
        self.book_info.remove_item.connect(self.remove_metadata_item)
        self.book_info.open_fmt_with.connect(self.open_fmt_with)
        self.book_info.save_format.connect(self.save_specific_format)
        self.book_info.restore_format.connect(self.restore_specific_format)
        self.book_info.set_cover_format.connect(self.set_cover_from_format)
        self.book_info.compare_format.connect(self.compare_specific_format)
        self.book_info.copy_link.connect(self.copy_link)
        self.book_info.manage_category.connect(self.manage_category)
        self.setCursor(Qt.PointingHandCursor)
Example #7
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QVBoxLayout(self)
        self.h = h = QHBoxLayout()

        self.la = la = QLabel(_(
            'Create the rule below, the rule can be used to remove or replace tags'))
        la.setWordWrap(True)
        l.addWidget(la)
        l.addLayout(h)
        self.action = a = QComboBox(self)
        h.addWidget(a)
        for action, text in self.ACTION_MAP.iteritems():
            a.addItem(text, action)
        a.currentIndexChanged.connect(self.update_state)
        self.la1 = la = QLabel('\xa0' + _('the tag, if it') + '\xa0')
        h.addWidget(la)
        self.match_type = q = QComboBox(self)
        h.addWidget(q)
        for action, text in self.MATCH_TYPE_MAP.iteritems():
            q.addItem(text, action)
        self.la2 = la = QLabel(':\xa0')
        h.addWidget(la)
        self.query = q = QLineEdit(self)
        h.addWidget(q)
        self.h2 = h = QHBoxLayout()
        l.addLayout(h)
        self.la3 = la = QLabel(_('with the tag:') + '\xa0')
        h.addWidget(la)
        self.replace = r = QLineEdit(self)
        h.addWidget(r)
        l.addStretch(10)
        self.update_state()
 def define_section1(self):
     """defining section 1: choose file to upload and project
     """
     mywidget = QWidget(self)
     layout = QHBoxLayout()
     mywidget.setLayout(layout)
     
     mypath = self.settings["raw_files_path"]
     file_btn = FileButton("Choose .csv file with target allele fasta files", mypath, self)
     self.file_widget = ChoiceSection("Raw File:", [file_btn], self.tree)
     self.file_widget.choice.connect(self.get_file)
     if self.settings["modus"] == "debugging":
         self.file_widget.field.setText(r"H:\Projekte\Bioinformatik\Typeloader\example files\bulk_upload3.csv")
     layout.addWidget(self.file_widget)
     
     proj_btn = QueryButton("Choose a (different) existing project", "SELECT project_name FROM projects where project_status = 'Open' order by project_name desc") 
     new_proj_btn = NewProjectButton("Start a new project", self.log, self.mydb, self.settings)
     self.proj_widget = ChoiceSection("Project:", [proj_btn, new_proj_btn], self.tree)
     self.proj_widget.field.setText(self.current_project)
     proj_btn.change_to_normal(None)
     new_proj_btn.change_to_normal(None)
     
     self.proj_widget.choice.connect(self.get_project)
     layout.addWidget(self.proj_widget)
     
     self.upload_btn = ProceedButton("Upload", [self.file_widget.field, self.proj_widget.field], self.log, 0)
     layout.addWidget(self.upload_btn)
     self.file_widget.choice.connect(self.upload_btn.check_ready)
     self.proj_widget.choice.connect(self.upload_btn.check_ready)
     self.upload_btn.proceed.connect(self.perform_bulk_upload)
     
     self.sections.append(("(1) Upload bulk-submission file:", mywidget))
Example #9
0
    def __init__(self, store):
        QWidget.__init__(self)
        self.setupUi(self)

        self.store = store

        self.load_setings()
Example #10
0
    def setup_store_checks(self):
        first_run = self.config.get('first_run', True)

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

        self.store_checks = {}

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

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

        self.config['first_run'] = False
Example #11
0
 def __init__(self, parent=None, show_open_in_editor=False):
     QWidget.__init__(self, parent)
     self.changes = [[], [], []]
     self.delta = 0
     self.l = l = QHBoxLayout(self)
     self.setLayout(l)
     self.syncpos = 0
     l.setContentsMargins(0, 0, 0, 0), l.setSpacing(0)
     self.view = DiffSplit(self, show_open_in_editor=show_open_in_editor)
     l.addWidget(self.view)
     self.add_diff = self.view.add_diff
     self.scrollbar = QScrollBar(self)
     l.addWidget(self.scrollbar)
     self.syncing = False
     self.bars = []
     self.resize_timer = QTimer(self)
     self.resize_timer.setSingleShot(True)
     self.resize_timer.timeout.connect(self.resize_debounced)
     for i, bar in enumerate((self.scrollbar, self.view.left.verticalScrollBar(), self.view.right.verticalScrollBar())):
         self.bars.append(bar)
         bar.valueChanged[int].connect(partial(self.scrolled, i))
     self.view.left.resized.connect(self.resized)
     for i, v in enumerate((self.view.left, self.view.right, self.view.handle(1))):
         v.wheel_event.connect(self.scrollbar.wheelEvent)
         if i < 2:
             v.next_change.connect(self.next_change)
             v.line_activated.connect(self.line_activated)
             v.scrolled.connect(partial(self.scrolled, i + 1))
    def get_last_check_widget(self):
        """
        Return QWidget with last check data

        :return: widget with last check data
        :rtype: QWidget
        """

        widget = QWidget()
        layout = QGridLayout()
        widget.setLayout(layout)

        # Title
        check_title = QLabel(_('My last check'))
        check_title.setObjectName('itemtitle')
        check_title.setFixedHeight(25)
        layout.addWidget(check_title, 0, 0, 1, 2)

        # State
        state_title = QLabel(_("State:"))
        state_title.setObjectName('subtitle')
        layout.addWidget(state_title, 1, 0, 1, 1)

        layout.addWidget(self.labels['state_icon'], 1, 1, 1, 1)

        # When last check
        when_title = QLabel(_("When:"))
        when_title.setObjectName('subtitle')
        layout.addWidget(when_title, 2, 0, 1, 1)

        layout.addWidget(self.labels['ls_last_check'], 2, 1, 1, 1)

        return widget
Example #13
0
    def __init__(self, plugin):
        QWidget.__init__(self)
        self.plugin = plugin

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

        self.gb = QGroupBox(_('Downloaded metadata fields'), self)
        if plugin.config_help_message:
            self.pchm = QLabel(plugin.config_help_message)
            self.pchm.setWordWrap(True)
            self.pchm.setOpenExternalLinks(True)
            l.addWidget(self.pchm, 0, 0, 1, 2)
        l.addWidget(self.gb, l.rowCount(), 0, 1, 2)
        self.gb.l = QGridLayout()
        self.gb.setLayout(self.gb.l)
        self.fields_view = v = QListView(self)
        self.gb.l.addWidget(v, 0, 0)
        v.setFlow(v.LeftToRight)
        v.setWrapping(True)
        v.setResizeMode(v.Adjust)
        self.fields_model = FieldsModel(self.plugin)
        self.fields_model.initialize()
        v.setModel(self.fields_model)

        self.memory = []
        self.widgets = []
        for opt in plugin.options:
            self.create_widgets(opt)
    def initialize(self):
        """
        Initialize QWidget

        """

        layout = QHBoxLayout()
        self.setLayout(layout)

        self.services_title.setObjectName('itemtitle')
        layout.addWidget(self.services_title)
        layout.setAlignment(self.services_title, Qt.AlignLeft)

        icons_widget = QWidget()
        icons_layout = QHBoxLayout()
        icons_widget.setLayout(icons_layout)

        for icon in Service.get_available_icons():
            state = icon.replace('services_', '').upper()
            icon_pixmap = QIcon(settings.get_image(icon))
            self.states_btns[state].setIcon(icon_pixmap)
            self.states_btns[state].setFixedSize(20, 20)
            self.states_btns[state].setToolTip(state)
            self.states_btns[state].setCheckable(True)
            self.states_btns[state].setObjectName('services')
            icons_layout.addWidget(self.states_btns[state])
            self.nb_labels[state].setObjectName(get_icon_name_from_state('service', state))
            icons_layout.addWidget(self.nb_labels[state])

        layout.addWidget(icons_widget)
        layout.setAlignment(icons_widget, Qt.AlignRight)
Example #15
0
    def __init__(self, gui):
        QWidget.__init__(self, gui)
        self.setObjectName('jobs_pointer')
        self.setVisible(False)
        self.resize(100, 80)
        self.animation = QPropertyAnimation(self, "geometry", self)
        self.animation.setDuration(750)
        self.animation.setLoopCount(2)
        self.animation.setEasingCurve(QEasingCurve.Linear)
        self.animation.finished.connect(self.hide)

        taily, heady = 0, 55
        self.arrow_path = QPainterPath(QPointF(40, taily))
        self.arrow_path.lineTo(40, heady)
        self.arrow_path.lineTo(20, heady)
        self.arrow_path.lineTo(50, self.height())
        self.arrow_path.lineTo(80, heady)
        self.arrow_path.lineTo(60, heady)
        self.arrow_path.lineTo(60, taily)
        self.arrow_path.closeSubpath()

        c = self.palette().color(QPalette.Active, QPalette.WindowText)
        self.color = QColor(c)
        self.color.setAlpha(100)
        self.brush = QBrush(self.color, Qt.SolidPattern)
Example #16
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     l = QVBoxLayout(parent)
     l.addWidget(self)
     l.setContentsMargins(0, 0, 0, 0)
     l = QFormLayout(self)
     l.setContentsMargins(0, 0, 0, 0)
     l.setFieldGrowthPolicy(l.AllNonFixedFieldsGrow)
     self.choices = c = QComboBox()
     c.setMinimumContentsLength(30)
     for text, data in [
             (_('Search for the author on Goodreads'), 'search-goodreads'),
             (_('Search for the author on Amazon'), 'search-amzn'),
             (_('Search for the author in your calibre library'), 'search-calibre'),
             (_('Search for the author on Wikipedia'), 'search-wikipedia'),
             (_('Search for the author on Google Books'), 'search-google'),
             (_('Search for the book on Goodreads'), 'search-goodreads-book'),
             (_('Search for the book on Amazon'), 'search-amzn-book'),
             (_('Search for the book on Google Books'), 'search-google-book'),
             (_('Use a custom search URL'), 'url'),
     ]:
         c.addItem(text, data)
     l.addRow(_('Clicking on &author names should:'), c)
     self.custom_url = u = QLineEdit(self)
     u.textChanged.connect(self.changed_signal)
     u.setPlaceholderText(_('Enter the URL'))
     c.currentIndexChanged.connect(self.current_changed)
     l.addRow(u)
     self.current_changed()
     c.currentIndexChanged.connect(self.changed_signal)
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

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

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

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

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

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

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

        self.l.addWidget(self.book_types_to_create)
Example #18
0
    def __init__(self, parent):
        orientation = Qt.Vertical
        if config['gui_layout'] == 'narrow':
            orientation = Qt.Horizontal if is_widescreen() else Qt.Vertical
        idx = 0 if orientation == Qt.Vertical else 1
        size = 300 if orientation == Qt.Vertical else 550
        Splitter.__init__(self, 'cover_browser_splitter', _('Cover Browser'),
                I('cover_flow.png'),
                orientation=orientation, parent=parent,
                connect_button=not config['separate_cover_flow'],
                side_index=idx, initial_side_size=size, initial_show=False,
                shortcut='Shift+Alt+B')

        quickview_widget = QWidget()
        parent.quickview_splitter = QuickviewSplitter(
                parent=self, orientation=Qt.Vertical, qv_widget=quickview_widget)
        parent.library_view = BooksView(parent)
        parent.library_view.setObjectName('library_view')
        stack = QStackedWidget(self)
        av = parent.library_view.alternate_views
        av.set_stack(stack)
        parent.grid_view = GridView(parent)
        parent.grid_view.setObjectName('grid_view')
        av.add_view('grid', parent.grid_view)
        parent.quickview_splitter.addWidget(stack)

        quickview_widget.setLayout(QVBoxLayout())
        parent.quickview_splitter.addWidget(quickview_widget)
        parent.quickview_splitter.hide_quickview_widget()

        self.addWidget(parent.quickview_splitter)
Example #19
0
 def paintEvent(self, event):
     QWidget.paintEvent(self, event)
     pmap = self._pixmap
     if pmap.isNull():
         return
     w, h = pmap.width(), pmap.height()
     ow, oh = w, h
     cw, ch = self.rect().width(), self.rect().height()
     scaled, nw, nh = fit_image(w, h, cw, ch)
     if scaled:
         pmap = pmap.scaled(int(nw*pmap.devicePixelRatio()), int(nh*pmap.devicePixelRatio()), Qt.IgnoreAspectRatio,
                 Qt.SmoothTransformation)
     w, h = int(pmap.width()/pmap.devicePixelRatio()), int(pmap.height()/pmap.devicePixelRatio())
     x = int(abs(cw - w)/2.)
     y = int(abs(ch - h)/2.)
     target = QRect(x, y, w, h)
     p = QPainter(self)
     p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
     p.drawPixmap(target, pmap)
     if self.draw_border:
         pen = QPen()
         pen.setWidth(self.BORDER_WIDTH)
         p.setPen(pen)
         p.drawRect(target)
     if self.show_size:
         draw_size(p, target, ow, oh)
     p.end()
Example #20
0
 def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     self._layout = l = QGridLayout()
     self.setLayout(self._layout)
     self.header = QLabel(_('Double click on any entry to change the'
         ' keyboard shortcuts associated with it'))
     l.addWidget(self.header, 0, 0, 1, 3)
     self.view = QTreeView(self)
     self.view.setAlternatingRowColors(True)
     self.view.setHeaderHidden(True)
     self.view.setAnimated(True)
     l.addWidget(self.view, 1, 0, 1, 3)
     self.delegate = Delegate()
     self.view.setItemDelegate(self.delegate)
     self.delegate.sizeHintChanged.connect(self.editor_opened,
             type=Qt.QueuedConnection)
     self.delegate.changed_signal.connect(self.changed_signal)
     self.search = SearchBox2(self)
     self.search.initialize('shortcuts_search_history',
             help_text=_('Search for a shortcut by name'))
     self.search.search.connect(self.find)
     l.addWidget(self.search, 2, 0, 1, 1)
     self.nb = QPushButton(QIcon(I('arrow-down.png')), _('&Next'), self)
     self.pb = QPushButton(QIcon(I('arrow-up.png')), _('&Previous'), self)
     self.nb.clicked.connect(self.find_next)
     self.pb.clicked.connect(self.find_previous)
     l.addWidget(self.nb, 2, 1, 1, 1)
     l.addWidget(self.pb, 2, 2, 1, 1)
     l.setColumnStretch(0, 100)
Example #21
0
 def __init__(self, parent=None):
     self.loaded_ruleset = None
     QWidget.__init__(self, parent)
     self.PREFS_OBJECT = JSONConfig('style-transform-rules')
     l = QVBoxLayout(self)
     self.rules_widget = w = Rules(self)
     w.changed.connect(self.changed.emit)
     l.addWidget(w)
     self.h = h = QHBoxLayout()
     l.addLayout(h)
     self.export_button = b = QPushButton(_('E&xport'), self)
     b.setToolTip(_('Export these rules to a file'))
     b.clicked.connect(self.export_rules)
     h.addWidget(b)
     self.import_button = b = QPushButton(_('&Import'), self)
     b.setToolTip(_('Import previously exported rules'))
     b.clicked.connect(self.import_rules)
     h.addWidget(b)
     self.test_button = b = QPushButton(_('&Test rules'), self)
     b.clicked.connect(self.test_rules)
     h.addWidget(b)
     h.addStretch(10)
     self.save_button = b = QPushButton(_('&Save'), self)
     b.setToolTip(_('Save this ruleset for later re-use'))
     b.clicked.connect(self.save_ruleset)
     h.addWidget(b)
     self.export_button = b = QPushButton(_('&Load'), self)
     self.load_menu = QMenu(self)
     b.setMenu(self.load_menu)
     b.setToolTip(_('Load a previously saved ruleset'))
     b.clicked.connect(self.load_ruleset)
     h.addWidget(b)
     self.build_load_menu()
Example #22
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QVBoxLayout(self)
        self.h = h = QHBoxLayout()

        self.la = la = QLabel(self.MSG)
        la.setWordWrap(True)
        l.addWidget(la)
        l.addLayout(h)
        self.action = a = QComboBox(self)
        h.addWidget(a)
        for action, text in self.ACTION_MAP.iteritems():
            a.addItem(text, action)
        a.currentIndexChanged.connect(self.update_state)
        self.la1 = la = QLabel('\xa0' + self.SUBJECT + '\xa0')
        h.addWidget(la)
        self.match_type = q = QComboBox(self)
        h.addWidget(q)
        for action, text in self.MATCH_TYPE_MAP.iteritems():
            q.addItem(text, action)
        q.currentIndexChanged.connect(self.update_state)
        self.la2 = la = QLabel(':\xa0')
        h.addWidget(la)
        self.query = q = QLineEdit(self)
        h.addWidget(q)
        self.h2 = h = QHBoxLayout()
        l.addLayout(h)
        self.la3 = la = QLabel(_('with the tag:') + '\xa0')
        h.addWidget(la)
        self.replace = r = QLineEdit(self)
        h.addWidget(r)
        l.addStretch(10)
        self.la3.setVisible(False), self.replace.setVisible(False)
        self.update_state()
    def get_search_widget(self):
        """
        Create and return the search QWidget

        :return: search QWidget
        :rtype: QWidget
        """

        widget = QWidget()
        layout = QHBoxLayout()
        layout.setSpacing(0)
        widget.setLayout(layout)

        # Search label
        search_lbl = QLabel(_('Search Host'))
        search_lbl.setObjectName('bordertitle')
        search_lbl.setFixedHeight(25)
        search_lbl.setToolTip(_('Search Host'))
        layout.addWidget(search_lbl)

        # QLineEdit
        self.line_search.setFixedHeight(search_lbl.height())
        layout.addWidget(self.line_search)
        self.create_line_search([])

        return widget
    def get_text_widget(self):
        """
        Return text QWidget with QTextEdit

        :return: text QWidget
        :rtype: QWidget
        """

        text_widget = QWidget()
        text_widget.setObjectName('dialog')
        text_layout = QVBoxLayout()
        text_widget.setLayout(text_layout)

        self.text_edit.setPlaceholderText(_('type your text...'))
        self.text_edit.setText(self.old_text)
        text_layout.addWidget(self.text_edit)

        # Accept button
        accept_btn = QPushButton(_('Confirm'), self)
        accept_btn.clicked.connect(self.accept_text)
        accept_btn.setObjectName('valid')
        accept_btn.setMinimumHeight(30)
        text_layout.addWidget(accept_btn)

        return text_widget
Example #25
0
    def __init__(self, plugin, parent):
        QWidget.__init__(self, parent)

        self.plugin = plugin

        self.l = l = QVBoxLayout()
        self.setLayout(l)
        self.c = c = QLabel(_('<b>Configure %(name)s</b><br>%(desc)s') % dict(
            name=plugin.name, desc=plugin.description))
        c.setAlignment(Qt.AlignHCenter)
        l.addWidget(c)

        self.config_widget = plugin.config_widget()
        self.l.addWidget(self.config_widget)

        self.bb = QDialogButtonBox(
                QDialogButtonBox.Save|QDialogButtonBox.Cancel,
                parent=self)
        self.bb.accepted.connect(self.finished)
        self.bb.rejected.connect(self.finished)
        self.bb.accepted.connect(self.commit)
        l.addWidget(self.bb)

        self.f = QFrame(self)
        self.f.setFrameShape(QFrame.HLine)
        l.addWidget(self.f)
Example #26
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QVBoxLayout(self)

        self.filter_edit = e = QLineEdit(self)
        l.addWidget(e)
        self.splitter = s = QSplitter(Qt.Vertical, self)
        l.addWidget(s)
        e.setPlaceholderText(_('Filter'))
        self.model = m = LinksModel(self)
        self.links = f = FilesView(m, self)
        f.DELETE_POSSIBLE = False
        self.to_csv = f.to_csv
        f.double_clicked.connect(self.double_clicked)
        e.textChanged.connect(f.proxy.filter_text)
        s.addWidget(f)
        self.links.restore_table('links-table', sort_column=1)
        self.view = WebView(self)
        s.addWidget(self.view)
        self.ignore_current_change = False
        self.current_url = None
        f.current_changed.connect(self.current_changed)
        try:
            s.restoreState(read_state('links-view-splitter'))
        except TypeError:
            pass
        s.setCollapsible(0, False), s.setCollapsible(1, True)
        s.setStretchFactor(0, 10)
    def get_text_widget(self, regexp):
        """
        Return text QWidget with QTextEdit

        :return: text QWidget
        :rtype: QWidget
        """

        text_widget = QWidget()
        text_widget.setObjectName('dialog')
        text_layout = QVBoxLayout()
        text_widget.setLayout(text_layout)

        text_layout.addWidget(self.valid_text)

        qreg_exp = QRegExp(regexp)
        self.validator.setRegExp(qreg_exp)
        self.line_edit.setPlaceholderText(_('type your text...'))
        self.line_edit.setText(self.old_text)
        self.line_edit.setValidator(self.validator)
        self.line_edit.setFixedHeight(25)
        self.line_edit.textChanged.connect(self.check_text)
        text_layout.addWidget(self.line_edit)

        # Accept button
        accept_btn = QPushButton(_('Confirm'), self)
        accept_btn.clicked.connect(self.accept_text)
        accept_btn.setObjectName('valid')
        accept_btn.setMinimumHeight(30)
        text_layout.addWidget(accept_btn)

        return text_widget
Example #28
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.setVisible(False)
        parent.installEventFilter(self)

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

        self.questions = []

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

        self.checkbox = QCheckBox("", self)

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

        self.ask_question.connect(self.do_ask_question, type=Qt.QueuedConnection)
        self.setFocusPolicy(Qt.NoFocus)
        for child in self.findChildren(QWidget):
            child.setFocusPolicy(Qt.NoFocus)
        self.setFocusProxy(self.parent())
        self.resize_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(100), t.timeout.connect(self.parent_resized)
 def define_section2(self, initial = True):
     """defining section 2: choose alleles
     """
     self.log.debug("Setting up section2 of ENASubmissionForm...")
     mywidget = QWidget(self)
     layout = QHBoxLayout()
     mywidget.setLayout(layout)
     mywidget.setMinimumHeight(250)
     self.project_info = ProjectInfoTable(self.project, self.log, self)
     self.project_info.setMaximumWidth(300)
     self.project_info.setMinimumWidth(200)
     layout.addWidget(self.project_info)
     self.project_info.project_info.connect(self.catch_project_info)
     
     self.project_files = ENAFileChoiceTable(self.project, self.log, self)
     layout.addWidget(self.project_files)
     self.project_files.files_chosen.connect(self.project_info.update_files_chosen)
     self.project_files.files.connect(self.project_info.update_files)
     
     items = [self.project_info.item(3,0)]
     self.submit_btn = ProceedButton("Submit to ENA", items, self.log, 1, self)
     self.submit_btn.proceed.connect(self.submit_to_ENA)
     self.submit_btn.setMinimumWidth(100)
     layout.addWidget(self.submit_btn)
     self.project_info.updated.connect(self.submit_btn.check_ready)
     
     self.sections.append(("(2) Choose alleles to submit:", mywidget))
Example #30
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout(self)
        self.toc_title = None
        self.setLayout(l)
        l.setContentsMargins(0, 0, 0, 0)

        self.view = QTreeWidget(self)
        self.delegate = Delegate(self.view)
        self.view.setItemDelegate(self.delegate)
        self.view.setHeaderHidden(True)
        self.view.setAnimated(True)
        self.view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.show_context_menu, type=Qt.QueuedConnection)
        self.view.itemActivated.connect(self.emit_navigate)
        self.view.itemPressed.connect(self.item_pressed)
        pi = plugins['progress_indicator'][0]
        if hasattr(pi, 'set_no_activate_on_click'):
            pi.set_no_activate_on_click(self.view)
        self.view.itemDoubleClicked.connect(self.emit_navigate)
        l.addWidget(self.view)

        self.refresh_action = QAction(QIcon(I('view-refresh.png')), _('&Refresh'), self)
        self.refresh_action.triggered.connect(self.refresh)
        self.refresh_timer = t = QTimer(self)
        t.setInterval(1000), t.setSingleShot(True)
        t.timeout.connect(self.auto_refresh)
        self.toc_name = None
        self.currently_editing = None
Example #31
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.parent = parent
        self._layout = QVBoxLayout()
        self.setLayout(self._layout)
        self._layout.setContentsMargins(0,0,0,0)

        # Set up the find box & button
        search_layout = QHBoxLayout()
        self._layout.addLayout(search_layout)
        self.item_search = HistoryLineEdit(parent)
        self.item_search.setMinimumContentsLength(5)
        self.item_search.setSizeAdjustPolicy(self.item_search.AdjustToMinimumContentsLengthWithIcon)
        try:
            self.item_search.lineEdit().setPlaceholderText(
                                                _('Find item in Tag browser'))
        except:
            pass             # Using Qt < 4.7
        self.item_search.setToolTip(_(
        'Search for items. This is a "contains" search; items containing the\n'
        'text anywhere in the name will be found. You can limit the search\n'
        'to particular categories using syntax similar to search. For example,\n'
        'tags:foo will find foo in any tag, but not in authors etc. Entering\n'
        '*foo will filter all categories at once, showing only those items\n'
        'containing the text "foo"'))
        search_layout.addWidget(self.item_search)
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser find box',
                _('Find item'), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.set_focus_to_find_box)

        self.search_button = QToolButton()
        self.search_button.setText(_('Find'))
        self.search_button.setToolTip(_('Find the first/next matching item'))
        search_layout.addWidget(self.search_button)
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser find button',
                _('Find button'), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.search_button.click)

        self.expand_button = QToolButton()
        self.expand_button.setText('-')
        self.expand_button.setToolTip(_('Collapse all categories'))
        search_layout.addWidget(self.expand_button)
        search_layout.setStretch(0, 10)
        search_layout.setStretch(1, 1)
        search_layout.setStretch(2, 1)
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser collapse all',
                _('Collapse all'), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.expand_button.clicked)

        self.current_find_position = None
        self.search_button.clicked.connect(self.find)
        self.item_search.initialize('tag_browser_search')
        self.item_search.lineEdit().returnPressed.connect(self.do_find)
        self.item_search.lineEdit().textEdited.connect(self.find_text_changed)
        self.item_search.activated[str].connect(self.do_find)
        self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive)

        parent.tags_view = TagsView(parent)
        self.tags_view = parent.tags_view
        self.expand_button.clicked.connect(self.tags_view.collapseAll)
        self._layout.addWidget(parent.tags_view)

        # Now the floating 'not found' box
        l = QLabel(self.tags_view)
        self.not_found_label = l
        l.setFrameStyle(QFrame.StyledPanel)
        l.setAutoFillBackground(True)
        l.setText('<p><b>'+_('No More Matches.</b><p> Click Find again to go to first match'))
        l.setAlignment(Qt.AlignVCenter)
        l.setWordWrap(True)
        l.resize(l.sizeHint())
        l.move(10,20)
        l.setVisible(False)
        self.not_found_label_timer = QTimer()
        self.not_found_label_timer.setSingleShot(True)
        self.not_found_label_timer.timeout.connect(self.not_found_label_timer_event,
                                                   type=Qt.QueuedConnection)

        parent.alter_tb = l = QPushButton(parent)
        l.setText(_('Alter Tag browser'))
        l.setIcon(QIcon(I('tags.png')))
        l.m = QMenu()
        l.setMenu(l.m)
        self._layout.addWidget(l)
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser alter',
                _('Alter Tag browser'), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(l.showMenu)

        sb = l.m.addAction(_('Sort by'))
        sb.m = l.sort_menu = QMenu(l.m)
        sb.setMenu(sb.m)
        sb.bg = QActionGroup(sb)

        # Must be in the same order as db2.CATEGORY_SORTS
        for i, x in enumerate((_('Sort by name'), _('Sort by number of books'),
                  _('Sort by average rating'))):
            a = sb.m.addAction(x)
            sb.bg.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        sb.setToolTip(
                _('Set the sort order for entries in the Tag browser'))
        sb.setStatusTip(sb.toolTip())

        ma = l.m.addAction(_('Search type when selecting multiple items'))
        ma.m = l.match_menu = QMenu(l.m)
        ma.setMenu(ma.m)
        ma.ag = QActionGroup(ma)

        # Must be in the same order as db2.MATCH_TYPE
        for i, x in enumerate((_('Match any of the items'), _('Match all of the items'))):
            a = ma.m.addAction(x)
            ma.ag.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        ma.setToolTip(
                _('When selecting multiple entries in the Tag browser '
                    'match any or all of them'))
        ma.setStatusTip(ma.toolTip())

        mt = l.m.addAction(_('Manage authors, tags, etc.'))
        mt.setToolTip(_('All of these category_managers are available by right-clicking '
                       'on items in the tag browser above'))
        mt.m = l.manage_menu = QMenu(l.m)
        mt.setMenu(mt.m)

        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser toggle item',
                _("'Click' found item"), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.toggle_item)
Example #32
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

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

        self.enabled = c = QCheckBox(self)
        l.addWidget(c, l.rowCount(), 0, 1, 2)
        c.setVisible(False)
        c.stateChanged.connect(self.changed)

        self.l1 = l1 = QLabel('')
        l1.setWordWrap(True)
        l.addWidget(l1, l.rowCount(), 0, 1, 2)

        self.add_button = QPushButton(QIcon(I('plus.png')), _('&Add rule'),
                                      self)
        self.remove_button = QPushButton(QIcon(I('minus.png')),
                                         _('&Remove rule(s)'), self)
        self.add_button.clicked.connect(self.add_rule)
        self.remove_button.clicked.connect(self.remove_rule)
        l.addWidget(self.add_button, l.rowCount(), 0)
        l.addWidget(self.remove_button, l.rowCount() - 1, 1)

        self.g = g = QGridLayout()
        self.rules_view = QListView(self)
        self.rules_view.doubleClicked.connect(self.edit_rule)
        self.rules_view.setSelectionMode(
            QAbstractItemView.SelectionMode.ExtendedSelection)
        self.rules_view.setAlternatingRowColors(True)
        self.rtfd = RichTextDelegate(parent=self.rules_view, max_width=400)
        self.rules_view.setItemDelegate(self.rtfd)
        g.addWidget(self.rules_view, 0, 0, 2, 1)

        self.up_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        b.setToolTip(_('Move the selected rule up'))
        b.clicked.connect(self.move_up)
        g.addWidget(b, 0, 1, 1, 1, Qt.AlignmentFlag.AlignTop)
        self.down_button = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        b.setToolTip(_('Move the selected rule down'))
        b.clicked.connect(self.move_down)
        g.addWidget(b, 1, 1, 1, 1, Qt.AlignmentFlag.AlignBottom)

        l.addLayout(g, l.rowCount(), 0, 1, 2)
        l.setRowStretch(l.rowCount() - 1, 10)

        self.add_advanced_button = b = QPushButton(QIcon(I('plus.png')),
                                                   _('Add ad&vanced rule'),
                                                   self)
        b.clicked.connect(self.add_advanced)
        self.hb = hb = QHBoxLayout()
        l.addLayout(hb, l.rowCount(), 0, 1, 2)
        hb.addWidget(b)
        hb.addStretch(10)
        self.export_button = b = QPushButton(_('E&xport'), self)
        b.clicked.connect(self.export_rules)
        b.setToolTip(_('Export these rules to a file'))
        hb.addWidget(b)
        self.import_button = b = QPushButton(_('&Import'), self)
        b.setToolTip(_('Import rules from a file'))
        b.clicked.connect(self.import_rules)
        hb.addWidget(b)
Example #33
0
    def __init__(self, fm, pref_name, parent=None):
        QDialog.__init__(self, parent)
        self.fm = fm

        if pref_name == 'column_color_rules':
            self.rule_kind = 'color'
            rule_text = _('column coloring')
        elif pref_name == 'column_icon_rules':
            self.rule_kind = 'icon'
            rule_text = _('column icon')
        elif pref_name == 'cover_grid_icon_rules':
            self.rule_kind = 'emblem'
            rule_text = _('Cover grid emblem')

        self.setWindowIcon(QIcon(I('format-fill-color.png')))
        self.setWindowTitle(_('Create/edit a {0} rule').format(rule_text))

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

        self.l1 = l1 = QLabel(
            _('Create a {0} rule by'
              ' filling in the boxes below').format(rule_text))
        l.addWidget(l1, 0, 0, 1, 8)

        self.f1 = QFrame(self)
        self.f1.setFrameShape(QFrame.Shape.HLine)
        l.addWidget(self.f1, 1, 0, 1, 8)

        self.l2 = l2 = QLabel(
            _('Add the emblem:') if self.rule_kind ==
            'emblem' else _('Set the'))
        l.addWidget(l2, 2, 0)

        if self.rule_kind == 'color':
            l.addWidget(QLabel(_('color')))
        elif self.rule_kind == 'icon':
            self.kind_box = QComboBox(self)
            for tt, t in icon_rule_kinds:
                self.kind_box.addItem(tt, t)
            l.addWidget(self.kind_box, 2, 1)
            self.kind_box.setToolTip(
                textwrap.fill(
                    _('If you choose composed icons and multiple rules match, then all the'
                      ' matching icons will be combined, otherwise the icon from the'
                      ' first rule to match will be used.')))
        else:
            pass

        self.l3 = l3 = QLabel(_('of the column:'))
        l.addWidget(l3, 2, 2)

        self.column_box = QComboBox(self)
        l.addWidget(self.column_box, 2, 3)

        self.l4 = l4 = QLabel(_('to'))
        l.addWidget(l4, 2, 4)
        if self.rule_kind == 'emblem':
            l3.setVisible(False), self.column_box.setVisible(
                False), l4.setVisible(False)

        def create_filename_box():
            self.filename_box = f = QComboBox()
            self.filenamebox_view = v = QListView()
            v.setIconSize(QSize(32, 32))
            self.filename_box.setView(v)
            self.orig_filenamebox_view = f.view()
            f.setMinimumContentsLength(20), f.setSizeAdjustPolicy(
                f.AdjustToMinimumContentsLengthWithIcon)
            self.populate_icon_filenames()

        if self.rule_kind == 'color':
            self.color_box = ColorButton(parent=self)
            self.color_label = QLabel('Sample text Sample text')
            self.color_label.setTextFormat(Qt.TextFormat.RichText)
            l.addWidget(self.color_box, 2, 5)
            l.addWidget(self.color_label, 2, 6)
            l.addItem(QSpacerItem(10, 10, QSizePolicy.Policy.Expanding), 2, 7)
        elif self.rule_kind == 'emblem':
            create_filename_box()
            self.update_filename_box()
            self.filename_button = QPushButton(QIcon(I('document_open.png')),
                                               _('&Add new image'))
            l.addWidget(self.filename_box)
            l.addWidget(self.filename_button, 2, 6)
            l.addWidget(QLabel(_('(Images should be square-ish)')), 2, 7)
            l.setColumnStretch(7, 10)
        else:
            create_filename_box()

            vb = QVBoxLayout()
            self.multiple_icon_cb = QCheckBox(_('Choose &more than one icon'))
            vb.addWidget(self.multiple_icon_cb)
            self.update_filename_box()
            self.multiple_icon_cb.clicked.connect(self.multiple_box_clicked)
            vb.addWidget(self.filename_box)
            l.addLayout(vb, 2, 5)

            self.filename_button = QPushButton(QIcon(I('document_open.png')),
                                               _('&Add icon'))
            l.addWidget(self.filename_button, 2, 6)
            l.addWidget(QLabel(_('Icons should be square or landscape')), 2, 7)
            l.setColumnStretch(7, 10)

        self.l5 = l5 = QLabel(
            _('Only if the following conditions are all satisfied:'))
        l.addWidget(l5, 3, 0, 1, 7)

        self.scroll_area = sa = QScrollArea(self)
        sa.setMinimumHeight(300)
        sa.setMinimumWidth(950)
        sa.setWidgetResizable(True)
        l.addWidget(sa, 4, 0, 1, 8)

        self.add_button = b = QPushButton(QIcon(I('plus.png')),
                                          _('Add &another condition'))
        l.addWidget(b, 5, 0, 1, 8)
        b.clicked.connect(self.add_blank_condition)

        self.l6 = l6 = QLabel(
            _('You can disable a condition by'
              ' blanking all of its boxes'))
        l.addWidget(l6, 6, 0, 1, 8)

        self.bb = bb = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        l.addWidget(bb, 7, 0, 1, 8)
        if self.rule_kind != 'color':
            self.remove_button = b = bb.addButton(_('&Remove icon'),
                                                  bb.ActionRole)
            b.setIcon(QIcon(I('minus.png')))
            b.setMenu(QMenu(b))
            b.setToolTip('<p>' + _(
                'Remove a previously added icon. Note that doing so will cause rules that use it to stop working.'
            ))
            self.update_remove_button()

        self.conditions_widget = QWidget(self)
        sa.setWidget(self.conditions_widget)
        self.conditions_widget.setLayout(QVBoxLayout())
        self.conditions_widget.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
        self.conditions = []

        if self.rule_kind == 'color':
            for b in (self.column_box, ):
                b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
                b.setMinimumContentsLength(15)

        for key in sorted(displayable_columns(fm),
                          key=lambda k: sort_key(fm[k]['name'])
                          if k != color_row_key else b''):
            if key == color_row_key and self.rule_kind != 'color':
                continue
            name = all_columns_string if key == color_row_key else fm[key][
                'name']
            if name:
                self.column_box.addItem(name, key)
        self.column_box.setCurrentIndex(0)

        if self.rule_kind == 'color':
            self.color_box.color = '#000'
            self.update_color_label()
            self.color_box.color_changed.connect(self.update_color_label)
        else:
            self.rule_icon_files = []
            self.filename_button.clicked.connect(self.filename_button_clicked)

        self.resize(self.sizeHint())
Example #34
0
class RuleEditor(QDialog):  # {{{
    @property
    def doing_multiple(self):
        return hasattr(
            self, 'multiple_icon_cb') and self.multiple_icon_cb.isChecked()

    def __init__(self, fm, pref_name, parent=None):
        QDialog.__init__(self, parent)
        self.fm = fm

        if pref_name == 'column_color_rules':
            self.rule_kind = 'color'
            rule_text = _('column coloring')
        elif pref_name == 'column_icon_rules':
            self.rule_kind = 'icon'
            rule_text = _('column icon')
        elif pref_name == 'cover_grid_icon_rules':
            self.rule_kind = 'emblem'
            rule_text = _('Cover grid emblem')

        self.setWindowIcon(QIcon(I('format-fill-color.png')))
        self.setWindowTitle(_('Create/edit a {0} rule').format(rule_text))

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

        self.l1 = l1 = QLabel(
            _('Create a {0} rule by'
              ' filling in the boxes below').format(rule_text))
        l.addWidget(l1, 0, 0, 1, 8)

        self.f1 = QFrame(self)
        self.f1.setFrameShape(QFrame.Shape.HLine)
        l.addWidget(self.f1, 1, 0, 1, 8)

        self.l2 = l2 = QLabel(
            _('Add the emblem:') if self.rule_kind ==
            'emblem' else _('Set the'))
        l.addWidget(l2, 2, 0)

        if self.rule_kind == 'color':
            l.addWidget(QLabel(_('color')))
        elif self.rule_kind == 'icon':
            self.kind_box = QComboBox(self)
            for tt, t in icon_rule_kinds:
                self.kind_box.addItem(tt, t)
            l.addWidget(self.kind_box, 2, 1)
            self.kind_box.setToolTip(
                textwrap.fill(
                    _('If you choose composed icons and multiple rules match, then all the'
                      ' matching icons will be combined, otherwise the icon from the'
                      ' first rule to match will be used.')))
        else:
            pass

        self.l3 = l3 = QLabel(_('of the column:'))
        l.addWidget(l3, 2, 2)

        self.column_box = QComboBox(self)
        l.addWidget(self.column_box, 2, 3)

        self.l4 = l4 = QLabel(_('to'))
        l.addWidget(l4, 2, 4)
        if self.rule_kind == 'emblem':
            l3.setVisible(False), self.column_box.setVisible(
                False), l4.setVisible(False)

        def create_filename_box():
            self.filename_box = f = QComboBox()
            self.filenamebox_view = v = QListView()
            v.setIconSize(QSize(32, 32))
            self.filename_box.setView(v)
            self.orig_filenamebox_view = f.view()
            f.setMinimumContentsLength(20), f.setSizeAdjustPolicy(
                f.AdjustToMinimumContentsLengthWithIcon)
            self.populate_icon_filenames()

        if self.rule_kind == 'color':
            self.color_box = ColorButton(parent=self)
            self.color_label = QLabel('Sample text Sample text')
            self.color_label.setTextFormat(Qt.TextFormat.RichText)
            l.addWidget(self.color_box, 2, 5)
            l.addWidget(self.color_label, 2, 6)
            l.addItem(QSpacerItem(10, 10, QSizePolicy.Policy.Expanding), 2, 7)
        elif self.rule_kind == 'emblem':
            create_filename_box()
            self.update_filename_box()
            self.filename_button = QPushButton(QIcon(I('document_open.png')),
                                               _('&Add new image'))
            l.addWidget(self.filename_box)
            l.addWidget(self.filename_button, 2, 6)
            l.addWidget(QLabel(_('(Images should be square-ish)')), 2, 7)
            l.setColumnStretch(7, 10)
        else:
            create_filename_box()

            vb = QVBoxLayout()
            self.multiple_icon_cb = QCheckBox(_('Choose &more than one icon'))
            vb.addWidget(self.multiple_icon_cb)
            self.update_filename_box()
            self.multiple_icon_cb.clicked.connect(self.multiple_box_clicked)
            vb.addWidget(self.filename_box)
            l.addLayout(vb, 2, 5)

            self.filename_button = QPushButton(QIcon(I('document_open.png')),
                                               _('&Add icon'))
            l.addWidget(self.filename_button, 2, 6)
            l.addWidget(QLabel(_('Icons should be square or landscape')), 2, 7)
            l.setColumnStretch(7, 10)

        self.l5 = l5 = QLabel(
            _('Only if the following conditions are all satisfied:'))
        l.addWidget(l5, 3, 0, 1, 7)

        self.scroll_area = sa = QScrollArea(self)
        sa.setMinimumHeight(300)
        sa.setMinimumWidth(950)
        sa.setWidgetResizable(True)
        l.addWidget(sa, 4, 0, 1, 8)

        self.add_button = b = QPushButton(QIcon(I('plus.png')),
                                          _('Add &another condition'))
        l.addWidget(b, 5, 0, 1, 8)
        b.clicked.connect(self.add_blank_condition)

        self.l6 = l6 = QLabel(
            _('You can disable a condition by'
              ' blanking all of its boxes'))
        l.addWidget(l6, 6, 0, 1, 8)

        self.bb = bb = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        l.addWidget(bb, 7, 0, 1, 8)
        if self.rule_kind != 'color':
            self.remove_button = b = bb.addButton(_('&Remove icon'),
                                                  bb.ActionRole)
            b.setIcon(QIcon(I('minus.png')))
            b.setMenu(QMenu(b))
            b.setToolTip('<p>' + _(
                'Remove a previously added icon. Note that doing so will cause rules that use it to stop working.'
            ))
            self.update_remove_button()

        self.conditions_widget = QWidget(self)
        sa.setWidget(self.conditions_widget)
        self.conditions_widget.setLayout(QVBoxLayout())
        self.conditions_widget.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
        self.conditions = []

        if self.rule_kind == 'color':
            for b in (self.column_box, ):
                b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
                b.setMinimumContentsLength(15)

        for key in sorted(displayable_columns(fm),
                          key=lambda k: sort_key(fm[k]['name'])
                          if k != color_row_key else b''):
            if key == color_row_key and self.rule_kind != 'color':
                continue
            name = all_columns_string if key == color_row_key else fm[key][
                'name']
            if name:
                self.column_box.addItem(name, key)
        self.column_box.setCurrentIndex(0)

        if self.rule_kind == 'color':
            self.color_box.color = '#000'
            self.update_color_label()
            self.color_box.color_changed.connect(self.update_color_label)
        else:
            self.rule_icon_files = []
            self.filename_button.clicked.connect(self.filename_button_clicked)

        self.resize(self.sizeHint())

    def multiple_box_clicked(self):
        self.update_filename_box()
        self.update_icon_filenames_in_box()

    @property
    def icon_folder(self):
        return os.path.join(config_dir, 'cc_icons')

    def populate_icon_filenames(self):
        d = self.icon_folder
        self.icon_file_names = []
        if os.path.exists(d):
            for icon_file in os.listdir(d):
                icon_file = lower(icon_file)
                if os.path.exists(os.path.join(
                        d, icon_file)) and icon_file.endswith('.png'):
                    self.icon_file_names.append(icon_file)
        self.icon_file_names.sort(key=sort_key)

    def update_filename_box(self):
        doing_multiple = self.doing_multiple

        model = QStandardItemModel()
        self.filename_box.setModel(model)
        self.icon_file_names.sort(key=sort_key)
        if doing_multiple:
            item = QStandardItem(_('Open to see checkboxes'))
            item.setIcon(QIcon(I('blank.png')))
        else:
            item = QStandardItem('')
        item.setFlags(Qt.ItemFlag(0))
        model.appendRow(item)

        for i, filename in enumerate(self.icon_file_names):
            item = QStandardItem(filename)
            if doing_multiple:
                item.setFlags(Qt.ItemFlag.ItemIsUserCheckable
                              | Qt.ItemFlag.ItemIsEnabled)
                item.setData(Qt.CheckState.Unchecked,
                             Qt.ItemDataRole.CheckStateRole)
            else:
                item.setFlags(Qt.ItemFlag.ItemIsEnabled
                              | Qt.ItemFlag.ItemIsSelectable)
            icon = QIcon(os.path.join(self.icon_folder, filename))
            item.setIcon(icon)
            model.appendRow(item)

    def update_color_label(self):
        pal = QApplication.palette()
        bg1 = unicode_type(pal.color(pal.Base).name())
        bg2 = unicode_type(pal.color(pal.AlternateBase).name())
        c = self.color_box.color
        self.color_label.setText('''
            <span style="color: {c}; background-color: {bg1}">&nbsp;{st}&nbsp;</span>
            <span style="color: {c}; background-color: {bg2}">&nbsp;{st}&nbsp;</span>
            '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample text')))

    def sanitize_icon_file_name(self, icon_path):
        n = lower(
            sanitize_file_name(
                os.path.splitext(os.path.basename(icon_path))[0] + '.png'))
        return n.replace("'", '_')

    def filename_button_clicked(self):
        try:
            path = choose_files(self,
                                'choose_category_icon',
                                _('Select icon'),
                                filters=[(_('Images'),
                                          ['png', 'gif', 'jpg', 'jpeg'])],
                                all_files=False,
                                select_only_single_file=True)
            if path:
                icon_path = path[0]
                icon_name = self.sanitize_icon_file_name(icon_path)
                if icon_name not in self.icon_file_names:
                    self.icon_file_names.append(icon_name)
                    try:
                        p = QIcon(icon_path).pixmap(QSize(128, 128))
                        d = self.icon_folder
                        if not os.path.exists(os.path.join(d, icon_name)):
                            if not os.path.exists(d):
                                os.makedirs(d)
                            with open(os.path.join(d, icon_name), 'wb') as f:
                                f.write(pixmap_to_data(p, format='PNG'))
                    except:
                        import traceback
                        traceback.print_exc()
                    self.update_filename_box()
                    self.update_remove_button()
                if self.doing_multiple:
                    if icon_name not in self.rule_icon_files:
                        self.rule_icon_files.append(icon_name)
                    self.update_icon_filenames_in_box()
                else:
                    self.filename_box.setCurrentIndex(
                        self.filename_box.findText(icon_name))
                self.filename_box.adjustSize()
        except:
            import traceback
            traceback.print_exc()
        return

    def get_filenames_from_box(self):
        if self.doing_multiple:
            model = self.filename_box.model()
            fnames = []
            for i in range(1, model.rowCount()):
                item = model.item(i, 0)
                if item.checkState() == Qt.CheckState.Checked:
                    fnames.append(lower(unicode_type(item.text())))
            fname = ' : '.join(fnames)
        else:
            fname = lower(unicode_type(self.filename_box.currentText()))
        return fname

    def update_icon_filenames_in_box(self):
        if self.rule_icon_files:
            if not self.doing_multiple:
                idx = self.filename_box.findText(self.rule_icon_files[0])
                if idx >= 0:
                    self.filename_box.setCurrentIndex(idx)
                else:
                    self.filename_box.setCurrentIndex(0)
            else:
                model = self.filename_box.model()
                for icon in self.rule_icon_files:
                    idx = self.filename_box.findText(icon)
                    if idx >= 0:
                        item = model.item(idx)
                        item.setCheckState(Qt.CheckState.Checked)

    def update_remove_button(self):
        m = self.remove_button.menu()
        m.clear()
        for name in self.icon_file_names:
            ac = m.addAction(QIcon(os.path.join(self.icon_folder, name)), name)
            connect_lambda(
                ac.triggered, self,
                lambda self: self.remove_image(self.sender().text()))

    def remove_image(self, name):
        try:
            os.remove(os.path.join(self.icon_folder, name))
        except EnvironmentError:
            pass
        else:
            self.populate_icon_filenames()
            self.update_remove_button()
            self.update_filename_box()
            self.update_icon_filenames_in_box()

    def add_blank_condition(self):
        c = ConditionEditor(self.fm, parent=self.conditions_widget)
        self.conditions.append(c)
        self.conditions_widget.layout().addWidget(c)

    def apply_rule(self, kind, col, rule):
        if kind == 'color':
            if rule.color:
                self.color_box.color = rule.color
        else:
            if self.rule_kind == 'icon':
                for i, tup in enumerate(icon_rule_kinds):
                    if kind == tup[1]:
                        self.kind_box.setCurrentIndex(i)
                        break
            self.rule_icon_files = [ic.strip() for ic in rule.color.split(':')]
            if len(self.rule_icon_files) > 1:
                self.multiple_icon_cb.setChecked(True)
            self.update_filename_box()
            self.update_icon_filenames_in_box()

        for i in range(self.column_box.count()):
            c = unicode_type(self.column_box.itemData(i) or '')
            if col == c:
                self.column_box.setCurrentIndex(i)
                break

        for c in rule.conditions:
            ce = ConditionEditor(self.fm, parent=self.conditions_widget)
            self.conditions.append(ce)
            self.conditions_widget.layout().addWidget(ce)
            try:
                ce.condition = c
            except:
                import traceback
                traceback.print_exc()

    def accept(self):
        if self.rule_kind != 'color':
            fname = self.get_filenames_from_box()
            if not fname:
                error_dialog(self,
                             _('No icon selected'),
                             _('You must choose an icon for this rule'),
                             show=True)
                return
        if self.validate():
            QDialog.accept(self)

    def validate(self):
        r = Rule(self.fm)
        for c in self.conditions:
            condition = c.condition
            if condition is not None:
                try:
                    r.add_condition(*condition)
                except Exception as e:
                    import traceback
                    error_dialog(self,
                                 _('Invalid condition'),
                                 _('One of the conditions for this rule is'
                                   ' invalid: <b>%s</b>') % e,
                                 det_msg=traceback.format_exc(),
                                 show=True)
                    return False
        if len(r.conditions) < 1:
            error_dialog(self,
                         _('No conditions'),
                         _('You must specify at least one non-empty condition'
                           ' for this rule'),
                         show=True)
            return False
        return True

    @property
    def rule(self):
        r = Rule(self.fm)
        if self.rule_kind != 'color':
            r.color = self.get_filenames_from_box()
        else:
            r.color = self.color_box.color
        idx = self.column_box.currentIndex()
        col = unicode_type(self.column_box.itemData(idx) or '')
        for c in self.conditions:
            condition = c.condition
            if condition is not None:
                r.add_condition(*condition)
        if self.rule_kind == 'icon':
            kind = unicode_type(
                self.kind_box.itemData(self.kind_box.currentIndex()) or '')
        else:
            kind = self.rule_kind

        return kind, col, r
Example #35
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     self.bcol = QColor(*gprefs['cover_grid_color'])
     self.btex = gprefs['cover_grid_texture']
     self.update_brush()
     self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
Example #36
0
 def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     self.l = QGridLayout()
     self.setLayout(self.l)
     self.setToolTip(textwrap.dedent(self.HELP))
Example #37
0
    def __init__(self, recipe_model, parent=None):
        QDialog.__init__(self, parent)
        self.commit_on_change = True
        self.previous_urn = None

        self.setWindowIcon(QIcon(I('scheduler.png')))
        self.setWindowTitle(_("Schedule news download"))
        self.l = l = QGridLayout(self)

        # Left panel
        self.h = h = QHBoxLayout()
        l.addLayout(h, 0, 0, 1, 1)
        self.search = s = SearchBox2(self)
        self.search.initialize('scheduler_search_history')
        self.search.setMinimumContentsLength(15)
        self.go_button = b = QToolButton(self)
        b.setText(_("Go"))
        b.clicked.connect(self.search.do_search)
        self.clear_search_button = cb = QToolButton(self)
        self.clear_search_button.clicked.connect(self.search.clear_clicked)
        cb.setIcon(QIcon(I('clear_left.png')))
        h.addWidget(s), h.addWidget(b), h.addWidget(cb)
        self.recipes = RecipesView(self)
        l.addWidget(self.recipes, 1, 0, 1, 1)
        self.recipe_model = recipe_model
        self.recipe_model.do_refresh()
        self.recipes.setModel(self.recipe_model)
        self.recipes.setFocus(Qt.OtherFocusReason)
        self.count_label = la = QLabel(
            _('%s news sources') % self.recipe_model.showing_count)
        la.setAlignment(Qt.AlignCenter)
        l.addWidget(la, 2, 0, 1, 1)
        self.search.search.connect(self.recipe_model.search)
        self.recipe_model.searched.connect(self.search.search_done,
                                           type=Qt.QueuedConnection)
        self.recipe_model.searched.connect(self.search_done)

        # Right Panel
        self.scroll_area = sa = QScrollArea(self)
        self.l.addWidget(sa, 0, 1, 2, 1)
        sa.setFrameShape(QFrame.NoFrame)
        sa.setWidgetResizable(True)
        self.scroll_area_contents = sac = QWidget(self)
        sa.setWidget(sac)
        sac.v = v = QVBoxLayout(sac)
        v.setContentsMargins(0, 0, 0, 0)
        self.detail_box = QTabWidget(self)
        self.detail_box.setVisible(False)
        self.detail_box.setCurrentIndex(0)
        v.addWidget(self.detail_box)
        v.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

        # First Tab (scheduling)
        self.tab = QWidget()
        self.detail_box.addTab(self.tab, _("&Schedule"))
        self.tab.v = vt = QVBoxLayout(self.tab)
        vt.setContentsMargins(0, 0, 0, 0)
        self.blurb = la = QLabel('blurb')
        la.setWordWrap(True), la.setOpenExternalLinks(True)
        vt.addWidget(la)
        vt.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.frame = f = QFrame(self.tab)
        vt.addWidget(f)
        f.setFrameShape(f.StyledPanel)
        f.setFrameShadow(f.Raised)
        f.v = vf = QVBoxLayout(f)
        self.schedule = s = QCheckBox(_("&Schedule for download:"), f)
        self.schedule.stateChanged[int].connect(self.toggle_schedule_info)
        vf.addWidget(s)
        f.h = h = QHBoxLayout()
        vf.addLayout(h)
        self.days_of_week = QRadioButton(_("&Days of  week"), f)
        self.days_of_month = QRadioButton(_("Da&ys of month"), f)
        self.every_x_days = QRadioButton(_("Every &x days"), f)
        self.days_of_week.setChecked(True)
        h.addWidget(self.days_of_week), h.addWidget(
            self.days_of_month), h.addWidget(self.every_x_days)
        self.schedule_stack = ss = QStackedWidget(f)
        self.schedule_widgets = []
        for key in reversed(self.SCHEDULE_TYPES):
            self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self))
            self.schedule_stack.insertWidget(0, self.schedule_widgets[0])
        vf.addWidget(ss)
        self.last_downloaded = la = QLabel(f)
        la.setWordWrap(True)
        vf.addWidget(la)
        vt.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.account = acc = QGroupBox(self.tab)
        acc.setTitle(_("&Account"))
        vt.addWidget(acc)
        acc.g = g = QGridLayout(acc)
        acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account)
        spw.stateChanged[int].connect(self.set_pw_echo_mode)
        g.addWidget(spw, 2, 0, 1, 2)
        self.rla = la = QLabel(
            _("For the scheduling to work, you must leave calibre running."))
        vt.addWidget(la)
        for b, c in self.SCHEDULE_TYPES.iteritems():
            b = getattr(self, b)
            b.toggled.connect(self.schedule_type_selected)
            b.setToolTip(textwrap.dedent(c.HELP))

        # Second tab (advanced settings)
        self.tab2 = t2 = QWidget()
        self.detail_box.addTab(self.tab2, _("&Advanced"))
        self.tab2.g = g = QGridLayout(t2)
        g.setContentsMargins(0, 0, 0, 0)
        self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2)
        g.addWidget(tt, 0, 0, 1, 2)
        t2.la = la = QLabel(_("&Extra tags:"))
        self.custom_tags = ct = QLineEdit(self)
        la.setBuddy(ct)
        g.addWidget(la), g.addWidget(ct, 1, 1)
        t2.la2 = la = QLabel(_("&Keep at most:"))
        la.setToolTip(
            _("Maximum number of copies (issues) of this recipe to keep.  Set to 0 to keep all (disable)."
              ))
        self.keep_issues = ki = QSpinBox(t2)
        tt.toggled['bool'].connect(self.keep_issues.setEnabled)
        ki.setMaximum(100000), la.setBuddy(ki)
        ki.setToolTip(
            _("<p>When set, this option will cause calibre to keep, at most, the specified number of issues"
              " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the"
              " total is larger than this number.\n<p>Note that this feature only works if you have the"
              " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals"
              " older than a number of days, below, takes priority over this setting."
              ))
        ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues"))
        g.addWidget(la), g.addWidget(ki, 2, 1)
        si = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        g.addItem(si, 3, 1, 1, 1)

        # Bottom area
        self.hb = h = QHBoxLayout()
        self.l.addLayout(h, 2, 1, 1, 1)
        self.labt = la = QLabel(_("Delete downloaded &news older than:"))
        self.old_news = on = QSpinBox(self)
        on.setToolTip(
            _("<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n"
              "<p>You can also control the maximum number of issues of a specific periodical that are kept"
              " by clicking the Advanced tab for that periodical above."))
        on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days"))
        on.setMaximum(1000), la.setBuddy(on)
        on.setValue(gconf['oldest_news'])
        h.addWidget(la), h.addWidget(on)
        self.download_all_button = b = QPushButton(
            QIcon(I('news.png')), _("Download &all scheduled"), self)
        b.setToolTip(_("Download all scheduled news sources at once"))
        b.clicked.connect(self.download_all_clicked)
        self.l.addWidget(b, 3, 0, 1, 1)
        self.bb = bb = QDialogButtonBox(QDialogButtonBox.Save, self)
        bb.accepted.connect(self.accept), bb.rejected.connect(self.reject)
        self.download_button = b = bb.addButton(_('&Download now'),
                                                bb.ActionRole)
        b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False)
        b.clicked.connect(self.download_clicked)
        self.l.addWidget(bb, 3, 1, 1, 1)

        geom = gprefs.get('scheduler_dialog_geometry')
        if geom is not None:
            self.restoreGeometry(geom)
Example #38
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
        parent = parent.parent()
        self.l = l = QHBoxLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        self.alter_tb = parent.alter_tb = b = QToolButton(self)
        b.setAutoRaise(True)
        b.setText(_('Configure')), b.setToolButtonStyle(
            Qt.ToolButtonTextBesideIcon)
        b.setCursor(Qt.PointingHandCursor)
        b.setPopupMode(b.InstantPopup)
        b.setToolTip(
            textwrap.fill(
                _('Change how the Tag browser works, such as,'
                  ' how it is sorted, what happens when you click'
                  ' items, etc.')))
        b.setIcon(QIcon(I('config.png')))
        b.m = QMenu()
        b.setMenu(b.m)

        self.item_search = FindBox(parent)
        self.item_search.setMinimumContentsLength(5)
        self.item_search.setSizeAdjustPolicy(
            self.item_search.AdjustToMinimumContentsLengthWithIcon)
        self.item_search.initialize('tag_browser_search')
        self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive)
        self.item_search.setToolTip('<p>' + _(
            'Search for items. If the text begins with equals (=) the search is '
            'exact match, otherwise it is "contains" finding items containing '
            'the text anywhere in the item name. Both exact and contains '
            'searches ignore case. You can limit the search to particular '
            'categories using syntax similar to search. For example, '
            'tags:foo will find foo in any tag, but not in authors etc. Entering '
            '*foo will collapse all categories then showing only those categories '
            'with items containing the text "foo"') + '</p')
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser find box',
                                          _('Find next match'),
                                          default_keys=(),
                                          action=ac,
                                          group=_('Tag browser'))
        ac.triggered.connect(self.set_focus_to_find_box)

        self.search_button = QToolButton()
        self.search_button.setAutoRaise(True)
        self.search_button.setCursor(Qt.PointingHandCursor)
        self.search_button.setIcon(QIcon(I('search.png')))
        self.search_button.setToolTip(_('Find the first/next matching item'))
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser find button',
                                          _('Find in the Tag browser'),
                                          default_keys=(),
                                          action=ac,
                                          group=_('Tag browser'))
        ac.triggered.connect(self.search_button.click)

        self.toggle_search_button = b = QToolButton(self)
        le = self.item_search.lineEdit()
        le.addAction(QIcon(I('window-close.png')),
                     le.LeadingPosition).triggered.connect(self.close_find_box)
        b.setText(_('Find')), b.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        b.setCursor(Qt.PointingHandCursor)
        b.setIcon(QIcon(I('search.png')))
        b.setCheckable(True)
        b.setChecked(gprefs.get('tag browser search box visible', False))
        b.setToolTip(_('Search for items in the Tag browser'))
        b.setAutoRaise(True)
        b.toggled.connect(self.update_searchbar_state)
        self.update_searchbar_state()
Example #39
0
    def _setup_ui(self):
        self.setStyleSheet(self._default)
        shot = state.get('current_shot')
        self.setWindowTitle(f'Submit [{shot.name}]')

        layout = make_layout(horizon=False, margin=24, spacing=24)

        name_layout = make_layout(spacing=24)
        label = HeaderLabel('Job Name')
        label.setAlignment(Qt.AlignCenter)
        name_layout.addWidget(label)

        name = f'resolve {len(shot.jobs) + 1}'
        self._text_name = HeaderLineEdit()
        self._text_name.setAlignment(Qt.AlignRight)
        self._text_name.setText(name)
        self._text_name.setPlaceholderText('Submit Job Name')
        name_layout.addWidget(self._text_name)

        layout.addLayout(name_layout)

        # --------------
        layout.addWidget(make_split_line())

        label = HeaderLabel('Frame Range (seperate by comma, space or dash)')
        layout.addWidget(label)

        min_slider_value, max_slider_value = get_slider_range()
        self._text_frames = HeaderLineEdit()
        self._text_frames.setAlignment(Qt.AlignCenter)
        self._text_frames.setText(f'{min_slider_value}-{max_slider_value}')
        self._text_frames.setPlaceholderText(
            '1-101 or 1 2 3 or 1,2,3 or 1 3,4,6-9')
        layout.addWidget(self._text_frames)

        hlayout = make_layout(horizon=True, margin=0, spacing=24)
        label = HeaderLabel('Calibration')
        hlayout.addWidget(label)

        self._comboBox = CalibrationComboBox()
        hlayout.addWidget(self._comboBox)

        layout.addLayout(hlayout)

        # submit parameter
        submit_widget = QWidget()
        submit_control = QVBoxLayout()
        submit_meta = {
            'reference': 1,
            'clip_range': 1,
            'mesh_reduce_ratio': 0,
            'flows': 2
        }
        for parm_name, layer in submit_meta.items():
            parm_value = setting.resolve[parm_name]
            parm_widget = create_submit_parameter_widget(
                parm_name, parm_value, layer)
            if isinstance(parm_widget, ShotSubmitContainer):
                submit_control.addWidget(parm_widget)
            else:
                submit_control.addLayout(parm_widget)
            self._parms.append(parm_widget)
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        submit_widget.setLayout(submit_control)
        scroll.setWidget(submit_widget)
        layout.addWidget(scroll)

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

        self.setLayout(layout)

        self.setMinimumSize(580, 710)
        move_center(self)
Example #40
0
class Preferences(QDialog):

    run_wizard_requested = pyqtSignal()

    def __init__(self, gui, initial_plugin=None, close_after_initial=False):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.must_restart = False
        self.do_restart = False
        self.committed = False
        self.close_after_initial = close_after_initial

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

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

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

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

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

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

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

        if initial_plugin is not None:
            category, name = initial_plugin
            plugin = get_plugin(category, name)
            if plugin is not None:
                self.show_plugin(plugin)
        else:
            self.hide_plugin()

    def event(self, ev):
        if isinstance(ev, QStatusTipEvent):
            msg = re.sub(r'</?[a-z1-6]+>', ' ', ev.tip())
            self.title_bar.show_msg(msg)
        return QDialog.event(self, ev)

    def run_wizard(self):
        self.run_wizard_requested.emit()
        self.accept()

    def set_tooltips_for_labels(self):
        def process_child(child):
            for g in child.children():
                if isinstance(g, QLabel):
                    buddy = g.buddy()
                    if buddy is not None and hasattr(buddy, 'toolTip'):
                        htext = unicode(buddy.toolTip()).strip()
                        etext = unicode(g.toolTip()).strip()
                        if htext and not etext:
                            g.setToolTip(htext)
                            g.setWhatsThis(htext)
                else:
                    process_child(g)

        process_child(self.showing_widget)

    def show_plugin(self, plugin):
        self.showing_widget = plugin.create_widget(self.scroll_area)
        self.showing_widget.genesis(self.gui)
        self.showing_widget.initialize()
        self.set_tooltips_for_labels()
        self.scroll_area.setWidget(self.showing_widget)
        self.stack.setCurrentIndex(1)
        self.showing_widget.show()
        self.setWindowTitle(__appname__ + ' - ' + _('Preferences') + ' - ' +
                            plugin.gui_name)
        self.showing_widget.restart_now.connect(self.restart_now)
        self.title_bar.show_plugin(plugin)
        self.setWindowIcon(QIcon(plugin.icon))

        self.bb.button(self.bb.Close).setVisible(False)
        self.wizard_button.setVisible(False)
        for button in (self.bb.Apply, self.bb.RestoreDefaults,
                       self.bb.Discard):
            button = self.bb.button(button)
            button.setVisible(True)

        self.bb.button(self.bb.Apply).setEnabled(False)
        self.bb.button(self.bb.Apply).setDefault(False), self.bb.button(
            self.bb.Apply).setDefault(True)
        self.bb.button(self.bb.RestoreDefaults).setEnabled(
            self.showing_widget.supports_restoring_to_defaults)
        self.bb.button(self.bb.RestoreDefaults).setToolTip(
            self.showing_widget.restore_defaults_desc if self.showing_widget.
            supports_restoring_to_defaults else (
                _('Restoring to defaults not supported for') + ' ' +
                plugin.gui_name))
        self.showing_widget.changed_signal.connect(self.changed_signal)

    def changed_signal(self):
        b = self.bb.button(self.bb.Apply)
        b.setEnabled(True)

    def hide_plugin(self):
        for sig in 'changed_signal restart_now'.split():
            try:
                getattr(self.showing_widget,
                        sig).disconnect(getattr(self, sig))
            except Exception:
                pass
        self.showing_widget = QWidget(self.scroll_area)
        self.scroll_area.setWidget(self.showing_widget)
        self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
        self.stack.setCurrentIndex(0)
        self.title_bar.show_plugin()
        self.setWindowIcon(QIcon(I('config.png')))

        for button in (self.bb.Apply, self.bb.RestoreDefaults,
                       self.bb.Discard):
            button = self.bb.button(button)
            button.setVisible(False)

        self.bb.button(self.bb.Close).setVisible(True)
        self.bb.button(self.bb.Close).setDefault(False), self.bb.button(
            self.bb.Close).setDefault(True)
        self.wizard_button.setVisible(True)

    def restart_now(self):
        try:
            self.showing_widget.commit()
        except AbortCommit:
            return
        self.do_restart = True
        self.hide_plugin()
        self.accept()

    def commit(self, *args):
        must_restart = self.showing_widget.commit()
        rc = self.showing_widget.restart_critical
        self.committed = True
        do_restart = False
        if must_restart:
            self.must_restart = True
            msg = _('Some of the changes you made require a restart.'
                    ' Please restart calibre as soon as possible.')
            if rc:
                msg = _('The changes you have made require calibre be '
                        'restarted immediately. You will not be allowed to '
                        'set any more preferences, until you restart.')

            do_restart = show_restart_warning(msg, parent=self)

        self.showing_widget.refresh_gui(self.gui)
        if do_restart:
            self.do_restart = True
        return self.close_after_initial or (must_restart and rc) or do_restart

    def restore_defaults(self, *args):
        self.showing_widget.restore_defaults()

    def on_shutdown(self):
        gprefs.set('preferences dialog geometry',
                   bytearray(self.saveGeometry()))
        if self.committed:
            self.gui.must_restart_before_config = self.must_restart
            self.gui.tags_view.recount()
            self.gui.create_device_menu()
            self.gui.set_device_menu_items_state(
                bool(self.gui.device_connected))
            self.gui.bars_manager.apply_settings()
            self.gui.bars_manager.update_bars()
            self.gui.build_context_menus()

    def accept(self):
        if self.stack.currentIndex() == 0:
            self.on_shutdown()
            return QDialog.accept(self)
        try:
            close = self.commit()
        except AbortCommit:
            return
        if close:
            self.on_shutdown()
            return QDialog.accept(self)
        self.hide_plugin()

    def reject(self):
        if self.stack.currentIndex() == 0 or self.close_after_initial:
            self.on_shutdown()
            return QDialog.reject(self)
        self.hide_plugin()
Example #41
0
    def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.GlobalColor.white)
        self.marked_brush = QBrush(Qt.GlobalColor.lightGray)
        self.marked = None
        self.gui = parent
        self.splitter = QSplitter(self)
        self._l = l = QVBoxLayout(self)
        self.setLayout(l)
        l.addWidget(self.splitter)

        self.cover = Cover(self, show_size=gprefs['bd_overlay_cover_size'])
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover.open_with_requested.connect(self.open_with)
        self.cover.choose_open_with_requested.connect(self.choose_open_with)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

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

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

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

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

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                QApplication.instance().safe_restore_geometry(
                    self, saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
        from calibre.gui2.ui import get_gui
        ema = get_gui().iactions['Edit Metadata'].menuless_qaction
        a = self.ema = QAction('edit metadata', self)
        a.setShortcut(ema.shortcut())
        self.addAction(a)
        a.triggered.connect(self.edit_metadata)
Example #42
0
 def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     self.current_pixmap_size = QSize(0, 0)
     self.pixmap = QPixmap()
     self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
Example #43
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QVBoxLayout()
        self.setLayout(l)
        l.setContentsMargins(0, 0, 0, 0)
        self.view = WebView(self)
        self.view.page().sync_requested.connect(self.request_sync)
        self.view.page().split_requested.connect(self.request_split)
        self.view.page().loadFinished.connect(self.load_finished)
        self.inspector = self.view.inspector
        self.inspector.setPage(self.view.page())
        l.addWidget(self.view)
        self.bar = QToolBar(self)
        l.addWidget(self.bar)

        ac = actions['auto-reload-preview']
        ac.setCheckable(True)
        ac.setChecked(True)
        ac.toggled.connect(self.auto_reload_toggled)
        self.auto_reload_toggled(ac.isChecked())
        self.bar.addAction(ac)

        ac = actions['sync-preview-to-editor']
        ac.setCheckable(True)
        ac.setChecked(True)
        ac.toggled.connect(self.sync_toggled)
        self.sync_toggled(ac.isChecked())
        self.bar.addAction(ac)

        self.bar.addSeparator()

        ac = actions['split-in-preview']
        ac.setCheckable(True)
        ac.setChecked(False)
        ac.toggled.connect(self.split_toggled)
        self.split_toggled(ac.isChecked())
        self.bar.addAction(ac)

        ac = actions['reload-preview']
        ac.triggered.connect(self.refresh)
        self.bar.addAction(ac)

        actions['preview-dock'].toggled.connect(self.visibility_changed)

        self.current_name = None
        self.last_sync_request = None
        self.refresh_timer = QTimer(self)
        self.refresh_timer.timeout.connect(self.refresh)
        parse_worker.start()
        self.current_sync_request = None

        self.search = HistoryLineEdit2(self)
        self.search.initialize('tweak_book_preview_search')
        self.search.setPlaceholderText(_('Search in preview'))
        connect_lambda(self.search.returnPressed, self, lambda self: self.find('next'))
        self.bar.addSeparator()
        self.bar.addWidget(self.search)
        for d in ('next', 'prev'):
            ac = actions['find-%s-preview' % d]
            ac.triggered.connect(getattr(self, 'find_' + d))
            self.bar.addAction(ac)
Example #44
0
 def sizeHint(self):
     a = QWidget.sizeHint(self)
     a.setHeight(a.height() + 75)
     a.setWidth(a.width() + 100)
     return a
Example #45
0
class MTPConfig(QTabWidget):

    def __init__(self, device, parent=None, highlight_ignored_folders=False):
        QTabWidget.__init__(self, parent)
        self._device = weakref.ref(device)

        cd = msg = None
        if device.current_friendly_name is not None:
            if device.current_serial_num is None:
                msg = '<p>' + (_('The <b>%s</b> device has no serial number, '
                    'it cannot be configured')%device.current_friendly_name)
            else:
                cd = 'device-'+device.current_serial_num
        else:
            msg = '<p>' + _('<b>No MTP device connected.</b><p>'
                ' You can only configure the MTP device plugin when a device'
                ' is connected.')

        self.current_device_key = cd

        if msg:
            msg += '<p>' + _('If you want to un-ignore a previously'
                ' ignored MTP device, use the "Ignored devices" tab.')
            l = QLabel(msg)
            l.setWordWrap(True)
            l.setStyleSheet('QLabel { margin-left: 2em }')
            l.setMinimumWidth(500)
            l.setMinimumHeight(400)
            self.insertTab(0, l, _('Cannot configure'))
        else:
            self.base = QWidget(self)
            self.insertTab(0, self.base, _('Configure %s')%self.device.current_friendly_name)
            l = self.base.l = QGridLayout(self.base)
            self.base.setLayout(l)

            self.rules = r = FormatRules(self.device, self.get_pref('rules'))
            self.formats = FormatsConfig(set(BOOK_EXTENSIONS),
                    self.get_pref('format_map'))
            self.send_to = SendToConfig(self.get_pref('send_to'), self.device)
            self.template = TemplateConfig(self.get_pref('send_template'))
            self.base.la = la = QLabel(_(
                'Choose the formats to send to the %s')%self.device.current_friendly_name)
            la.setWordWrap(True)
            self.base.b = b = QPushButton(QIcon(I('list_remove.png')),
                _('&Ignore the %s in calibre')%device.current_friendly_name,
                self.base)
            b.clicked.connect(self.ignore_device)
            self.config_ign_folders_button = cif = QPushButton(
                QIcon(I('tb_folder.png')), _('Change scanned &folders'))
            cif.setStyleSheet(
                    'QPushButton { font-weight: bold; }')
            if highlight_ignored_folders:
                cif.setIconSize(QSize(64, 64))
            self.show_debug_button = bd = QPushButton(QIcon(I('debug.png')),
                    _('Show device information'))
            bd.clicked.connect(self.show_debug_info)
            cif.clicked.connect(self.change_ignored_folders)

            l.addWidget(b, 0, 0, 1, 2)
            l.addWidget(la, 1, 0, 1, 1)
            l.addWidget(self.formats, 2, 0, 5, 1)
            l.addWidget(cif, 2, 1, 1, 1)
            l.addWidget(self.template, 3, 1, 1, 1)
            l.addWidget(self.send_to, 4, 1, 1, 1)
            l.addWidget(self.show_debug_button, 5, 1, 1, 1)
            l.setRowStretch(6, 10)
            l.addWidget(r, 7, 0, 1, 2)
            l.setRowStretch(7, 100)

        self.igntab = IgnoredDevices(self.device.prefs['history'],
                self.device.prefs['blacklist'])
        self.addTab(self.igntab, _('Ignored devices'))
        self.current_ignored_folders = self.get_pref('ignored_folders')
        self.initial_ignored_folders = self.current_ignored_folders

        self.setCurrentIndex(1 if msg else 0)

    def show_debug_info(self):
        info = self.device.device_debug_info()
        d = QDialog(self)
        d.l = l = QVBoxLayout()
        d.setLayout(l)
        d.v = v = QPlainTextEdit()
        d.setWindowTitle(self.device.get_gui_name())
        v.setPlainText(info)
        v.setMinimumWidth(400)
        v.setMinimumHeight(350)
        l.addWidget(v)
        bb = d.bb = QDialogButtonBox(QDialogButtonBox.Close)
        bb.accepted.connect(d.accept)
        bb.rejected.connect(d.reject)
        l.addWidget(bb)
        bb.addButton(_('Copy to clipboard'), bb.ActionRole)
        bb.clicked.connect(lambda :
                QApplication.clipboard().setText(v.toPlainText()))
        d.exec_()

    def change_ignored_folders(self):
        d = IgnoredFolders(self.device,
                     self.current_ignored_folders, parent=self)
        if d.exec_() == d.Accepted:
            self.current_ignored_folders = d.ignored_folders

    def ignore_device(self):
        self.igntab.ignore_device(self.device.current_serial_num)
        self.base.b.setEnabled(False)
        self.base.b.setText(_('The %s will be ignored in calibre')%
                self.device.current_friendly_name)
        self.base.b.setStyleSheet('QPushButton { font-weight: bold }')
        self.base.setEnabled(False)

    def get_pref(self, key):
        p = self.device.prefs.get(self.current_device_key, {})
        if not p:
            self.device.prefs[self.current_device_key] = p
        return self.device.get_pref(key)

    @property
    def device(self):
        return self._device()

    def validate(self):
        if hasattr(self, 'formats'):
            if not self.formats.validate():
                return False
            if not self.template.validate():
                return False
        return True

    def commit(self):
        self.device.prefs['blacklist'] = self.igntab.blacklist
        p = self.device.prefs.get(self.current_device_key, {})

        if hasattr(self, 'formats'):
            p.pop('format_map', None)
            f = self.formats.format_map
            if f and f != self.device.prefs['format_map']:
                p['format_map'] = f

            p.pop('send_template', None)
            t = self.template.template
            if t and t != self.device.prefs['send_template']:
                p['send_template'] = t

            p.pop('send_to', None)
            s = self.send_to.value
            if s and s != self.device.prefs['send_to']:
                p['send_to'] = s

            p.pop('rules', None)
            r = list(self.rules.rules)
            if r and r != self.device.prefs['rules']:
                p['rules'] = r

            if self.current_ignored_folders != self.initial_ignored_folders:
                p['ignored_folders'] = self.current_ignored_folders

            self.device.prefs[self.current_device_key] = p
Example #46
0
class BookInfo(QDialog):

    closed = pyqtSignal(object)
    open_cover_with = pyqtSignal(object, object)

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

        self.cover = Cover(self, show_size=gprefs['bd_overlay_cover_size'])
        self.cover.resizeEvent = self.cover_view_resized
        self.cover.cover_changed.connect(self.cover_changed)
        self.cover.open_with_requested.connect(self.open_with)
        self.cover.choose_open_with_requested.connect(self.choose_open_with)
        self.cover_pixmap = None
        self.cover.sizeHint = self.details_size_hint
        self.splitter.addWidget(self.cover)

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

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

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

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

        geom = QCoreApplication.instance().desktop().availableGeometry(self)
        screen_height = geom.height() - 100
        screen_width = geom.width() - 100
        self.resize(max(int(screen_width / 2), 700), screen_height)
        saved_layout = gprefs.get('book_info_dialog_layout', None)
        if saved_layout is not None:
            try:
                QApplication.instance().safe_restore_geometry(
                    self, saved_layout[0])
                self.splitter.restoreState(saved_layout[1])
            except Exception:
                pass
        from calibre.gui2.ui import get_gui
        ema = get_gui().iactions['Edit Metadata'].menuless_qaction
        a = self.ema = QAction('edit metadata', self)
        a.setShortcut(ema.shortcut())
        self.addAction(a)
        a.triggered.connect(self.edit_metadata)

    def edit_metadata(self):
        if self.current_row is not None:
            book_id = self.view.model().id(self.current_row)
            get_gui().iactions['Edit Metadata'].edit_metadata_for(
                [self.current_row], [book_id], bulk=False)

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

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

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

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

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

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

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

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

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

    def next(self):
        self.move()

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

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

    def update_cover_tooltip(self):
        tt = ''
        if self.marked:
            tt += _('This book is marked') if self.marked in {
                True, 'true'
            } else _('This book is marked as: %s') % self.marked
            tt += '\n\n'

        if self.path_to_book is not None:
            tt += textwrap.fill(_('Path: {}').format(self.path_to_book))
            tt += '\n\n'

        if self.cover_pixmap is not None:
            sz = self.cover_pixmap.size()
            tt += _('Cover size: %(width)d x %(height)d pixels') % dict(
                width=sz.width(), height=sz.height())
        self.cover.setToolTip(tt)
        self.cover.pixmap_size = sz.width(), sz.height()

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

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

    def open_with(self, entry):
        id_ = self.view.model().id(self.current_row)
        self.open_cover_with.emit(id_, entry)

    def choose_open_with(self):
        from calibre.gui2.open_with import choose_program
        entry = choose_program('cover_image', self)
        if entry is not None:
            self.open_with(entry)
Example #47
0
    def __init__(self,
                 open_at=None,
                 continue_reading=None,
                 force_reload=False,
                 calibre_book_data=None):
        MainWindow.__init__(self, None)
        self.annotations_saver = None
        self.calibre_book_data_for_first_book = calibre_book_data
        self.shutting_down = self.close_forced = self.shutdown_done = False
        self.force_reload = force_reload
        connect_lambda(self.book_preparation_started,
                       self,
                       lambda self: self.loading_overlay(
                           _('Preparing book for first read, please wait')),
                       type=Qt.ConnectionType.QueuedConnection)
        self.maximized_at_last_fullscreen = False
        self.save_pos_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(3000), t.setTimerType(
            Qt.TimerType.VeryCoarseTimer)
        connect_lambda(t.timeout, self,
                       lambda self: self.save_annotations(in_book_file=False))
        self.pending_open_at = open_at
        self.base_window_title = _('E-book viewer')
        self.setDockOptions(MainWindow.AnimatedDocks
                            | MainWindow.AllowTabbedDocks
                            | MainWindow.AllowNestedDocks)
        self.setWindowTitle(self.base_window_title)
        self.in_full_screen_mode = None
        self.image_popup = ImagePopup(self)
        self.actions_toolbar = at = ActionsToolBar(self)
        at.open_book_at_path.connect(self.ask_for_open)
        self.addToolBar(Qt.ToolBarArea.LeftToolBarArea, at)
        try:
            os.makedirs(annotations_dir)
        except EnvironmentError:
            pass
        self.current_book_data = {}
        self.book_prepared.connect(self.load_finished,
                                   type=Qt.ConnectionType.QueuedConnection)
        self.dock_defs = dock_defs()

        def create_dock(title,
                        name,
                        area,
                        areas=Qt.DockWidgetArea.LeftDockWidgetArea
                        | Qt.DockWidgetArea.RightDockWidgetArea):
            ans = QDockWidget(title, self)
            ans.setObjectName(name)
            self.addDockWidget(area, ans)
            ans.setVisible(False)
            ans.visibilityChanged.connect(self.dock_visibility_changed)
            return ans

        for dock_def in itervalues(self.dock_defs):
            setattr(
                self, '{}_dock'.format(dock_def.name.partition('-')[0]),
                create_dock(dock_def.title, dock_def.name,
                            dock_def.initial_area, dock_def.allowed_areas))

        self.toc_container = w = QWidget(self)
        w.l = QVBoxLayout(w)
        self.toc = TOCView(w)
        self.toc.clicked[QModelIndex].connect(self.toc_clicked)
        self.toc.searched.connect(self.toc_searched)
        self.toc_search = TOCSearch(self.toc, parent=w)
        w.l.addWidget(self.toc), w.l.addWidget(
            self.toc_search), w.l.setContentsMargins(0, 0, 0, 0)
        self.toc_dock.setWidget(w)

        self.search_widget = w = SearchPanel(self)
        w.search_requested.connect(self.start_search)
        w.hide_search_panel.connect(self.search_dock.close)
        w.count_changed.connect(self.search_results_count_changed)
        w.goto_cfi.connect(self.goto_cfi)
        self.search_dock.setWidget(w)
        self.search_dock.visibilityChanged.connect(
            self.search_widget.visibility_changed)

        self.lookup_widget = w = Lookup(self)
        self.lookup_dock.visibilityChanged.connect(
            self.lookup_widget.visibility_changed)
        self.lookup_dock.setWidget(w)

        self.bookmarks_widget = w = BookmarkManager(self)
        connect_lambda(
            w.create_requested, self,
            lambda self: self.web_view.trigger_shortcut('new_bookmark'))
        w.edited.connect(self.bookmarks_edited)
        w.activated.connect(self.bookmark_activated)
        w.toggle_requested.connect(self.toggle_bookmarks)
        self.bookmarks_dock.setWidget(w)

        self.highlights_widget = w = HighlightsPanel(self)
        self.highlights_dock.setWidget(w)
        w.toggle_requested.connect(self.toggle_highlights)

        self.web_view = WebView(self)
        self.web_view.cfi_changed.connect(self.cfi_changed)
        self.web_view.reload_book.connect(self.reload_book)
        self.web_view.toggle_toc.connect(self.toggle_toc)
        self.web_view.show_search.connect(self.show_search)
        self.web_view.find_next.connect(self.search_widget.find_next_requested)
        self.search_widget.show_search_result.connect(
            self.web_view.show_search_result)
        self.web_view.search_result_not_found.connect(
            self.search_widget.search_result_not_found)
        self.web_view.toggle_bookmarks.connect(self.toggle_bookmarks)
        self.web_view.toggle_highlights.connect(self.toggle_highlights)
        self.web_view.new_bookmark.connect(
            self.bookmarks_widget.create_new_bookmark)
        self.web_view.toggle_inspector.connect(self.toggle_inspector)
        self.web_view.toggle_lookup.connect(self.toggle_lookup)
        self.web_view.quit.connect(self.quit)
        self.web_view.update_current_toc_nodes.connect(
            self.toc.update_current_toc_nodes)
        self.web_view.toggle_full_screen.connect(self.toggle_full_screen)
        self.web_view.ask_for_open.connect(
            self.ask_for_open, type=Qt.ConnectionType.QueuedConnection)
        self.web_view.selection_changed.connect(
            self.lookup_widget.selected_text_changed,
            type=Qt.ConnectionType.QueuedConnection)
        self.web_view.selection_changed.connect(
            self.highlights_widget.selected_text_changed,
            type=Qt.ConnectionType.QueuedConnection)
        self.web_view.view_image.connect(
            self.view_image, type=Qt.ConnectionType.QueuedConnection)
        self.web_view.copy_image.connect(
            self.copy_image, type=Qt.ConnectionType.QueuedConnection)
        self.web_view.show_loading_message.connect(self.show_loading_message)
        self.web_view.show_error.connect(self.show_error)
        self.web_view.print_book.connect(
            self.print_book, type=Qt.ConnectionType.QueuedConnection)
        self.web_view.reset_interface.connect(
            self.reset_interface, type=Qt.ConnectionType.QueuedConnection)
        self.web_view.quit.connect(self.quit,
                                   type=Qt.ConnectionType.QueuedConnection)
        self.web_view.shortcuts_changed.connect(self.shortcuts_changed)
        self.web_view.scrollbar_context_menu.connect(
            self.scrollbar_context_menu)
        self.web_view.close_prep_finished.connect(self.close_prep_finished)
        self.web_view.highlights_changed.connect(self.highlights_changed)
        self.actions_toolbar.initialize(self.web_view,
                                        self.search_dock.toggleViewAction())
        self.setCentralWidget(self.web_view)
        self.loading_overlay = LoadingOverlay(self)
        self.restore_state()
        self.actions_toolbar.update_visibility()
        self.dock_visibility_changed()
        self.highlights_widget.request_highlight_action.connect(
            self.web_view.highlight_action)
        self.highlights_widget.web_action.connect(self.web_view.generic_action)
        if continue_reading:
            self.continue_reading()
        self.setup_mouse_auto_hide()
Example #48
0
    def __init__(self, device, parent=None, highlight_ignored_folders=False):
        QTabWidget.__init__(self, parent)
        self._device = weakref.ref(device)

        cd = msg = None
        if device.current_friendly_name is not None:
            if device.current_serial_num is None:
                msg = '<p>' + (_('The <b>%s</b> device has no serial number, '
                    'it cannot be configured')%device.current_friendly_name)
            else:
                cd = 'device-'+device.current_serial_num
        else:
            msg = '<p>' + _('<b>No MTP device connected.</b><p>'
                ' You can only configure the MTP device plugin when a device'
                ' is connected.')

        self.current_device_key = cd

        if msg:
            msg += '<p>' + _('If you want to un-ignore a previously'
                ' ignored MTP device, use the "Ignored devices" tab.')
            l = QLabel(msg)
            l.setWordWrap(True)
            l.setStyleSheet('QLabel { margin-left: 2em }')
            l.setMinimumWidth(500)
            l.setMinimumHeight(400)
            self.insertTab(0, l, _('Cannot configure'))
        else:
            self.base = QWidget(self)
            self.insertTab(0, self.base, _('Configure %s')%self.device.current_friendly_name)
            l = self.base.l = QGridLayout(self.base)
            self.base.setLayout(l)

            self.rules = r = FormatRules(self.device, self.get_pref('rules'))
            self.formats = FormatsConfig(set(BOOK_EXTENSIONS),
                    self.get_pref('format_map'))
            self.send_to = SendToConfig(self.get_pref('send_to'), self.device)
            self.template = TemplateConfig(self.get_pref('send_template'))
            self.base.la = la = QLabel(_(
                'Choose the formats to send to the %s')%self.device.current_friendly_name)
            la.setWordWrap(True)
            self.base.b = b = QPushButton(QIcon(I('list_remove.png')),
                _('&Ignore the %s in calibre')%device.current_friendly_name,
                self.base)
            b.clicked.connect(self.ignore_device)
            self.config_ign_folders_button = cif = QPushButton(
                QIcon(I('tb_folder.png')), _('Change scanned &folders'))
            cif.setStyleSheet(
                    'QPushButton { font-weight: bold; }')
            if highlight_ignored_folders:
                cif.setIconSize(QSize(64, 64))
            self.show_debug_button = bd = QPushButton(QIcon(I('debug.png')),
                    _('Show device information'))
            bd.clicked.connect(self.show_debug_info)
            cif.clicked.connect(self.change_ignored_folders)

            l.addWidget(b, 0, 0, 1, 2)
            l.addWidget(la, 1, 0, 1, 1)
            l.addWidget(self.formats, 2, 0, 5, 1)
            l.addWidget(cif, 2, 1, 1, 1)
            l.addWidget(self.template, 3, 1, 1, 1)
            l.addWidget(self.send_to, 4, 1, 1, 1)
            l.addWidget(self.show_debug_button, 5, 1, 1, 1)
            l.setRowStretch(6, 10)
            l.addWidget(r, 7, 0, 1, 2)
            l.setRowStretch(7, 100)

        self.igntab = IgnoredDevices(self.device.prefs['history'],
                self.device.prefs['blacklist'])
        self.addTab(self.igntab, _('Ignored devices'))
        self.current_ignored_folders = self.get_pref('ignored_folders')
        self.initial_ignored_folders = self.current_ignored_folders

        self.setCurrentIndex(1 if msg else 0)
Example #49
0
    def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None):
        QWidget.__init__(self, parent)
        self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name
        self.toolbar1 = QToolBar(self)
        self.toolbar2 = QToolBar(self)
        self.toolbar3 = QToolBar(self)
        for i in range(1, 4):
            t = getattr(self, 'toolbar%d'%i)
            t.setIconSize(QSize(18, 18))
        self.editor = EditorWidget(self)
        self.editor.data_changed.connect(self.data_changed)
        self.set_base_url = self.editor.set_base_url
        self.set_html = self.editor.set_html
        self.tabs = QTabWidget(self)
        self.tabs.setTabPosition(self.tabs.South)
        self.wyswyg = QWidget(self.tabs)
        self.code_edit = QPlainTextEdit(self.tabs)
        self.source_dirty = False
        self.wyswyg_dirty = True

        self._layout = QVBoxLayout(self)
        self.wyswyg.layout = l = QVBoxLayout(self.wyswyg)
        self.setLayout(self._layout)
        l.setContentsMargins(0, 0, 0, 0)
        if one_line_toolbar:
            tb = QHBoxLayout()
            l.addLayout(tb)
        else:
            tb = l
        tb.addWidget(self.toolbar1)
        tb.addWidget(self.toolbar2)
        tb.addWidget(self.toolbar3)
        l.addWidget(self.editor)
        self._layout.addWidget(self.tabs)
        self.tabs.addTab(self.wyswyg, _('N&ormal view'))
        self.tabs.addTab(self.code_edit, _('&HTML source'))
        self.tabs.currentChanged[int].connect(self.change_tab)
        self.highlighter = Highlighter(self.code_edit.document())
        self.layout().setContentsMargins(0, 0, 0, 0)
        if self.toolbar_prefs_name is not None:
            hidden = gprefs.get(self.toolbar_prefs_name)
            if hidden:
                self.hide_toolbars()

        # toolbar1 {{{
        self.toolbar1.addAction(self.editor.action_undo)
        self.toolbar1.addAction(self.editor.action_redo)
        self.toolbar1.addAction(self.editor.action_select_all)
        self.toolbar1.addAction(self.editor.action_remove_format)
        self.toolbar1.addAction(self.editor.action_clear)
        self.toolbar1.addSeparator()

        for x in ('copy', 'cut', 'paste'):
            ac = getattr(self.editor, 'action_'+x)
            self.toolbar1.addAction(ac)

        self.toolbar1.addSeparator()
        self.toolbar1.addAction(self.editor.action_background)
        # }}}

        # toolbar2 {{{
        for x in ('', 'un'):
            ac = getattr(self.editor, 'action_%sordered_list'%x)
            self.toolbar2.addAction(ac)
        self.toolbar2.addSeparator()
        for x in ('superscript', 'subscript', 'indent', 'outdent'):
            self.toolbar2.addAction(getattr(self.editor, 'action_' + x))
            if x in ('subscript', 'outdent'):
                self.toolbar2.addSeparator()

        self.toolbar2.addAction(self.editor.action_block_style)
        w = self.toolbar2.widgetForAction(self.editor.action_block_style)
        if hasattr(w, 'setPopupMode'):
            w.setPopupMode(w.InstantPopup)
        self.toolbar2.addAction(self.editor.action_insert_link)
        self.toolbar2.addAction(self.editor.action_insert_hr)
        # }}}

        # toolbar3 {{{
        for x in ('bold', 'italic', 'underline', 'strikethrough'):
            ac = getattr(self.editor, 'action_'+x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()

        for x in ('left', 'center', 'right', 'justified'):
            ac = getattr(self.editor, 'action_align_'+x)
            self.toolbar3.addAction(ac)
        self.toolbar3.addSeparator()
        self.toolbar3.addAction(self.editor.action_color)
        # }}}

        self.code_edit.textChanged.connect(self.code_dirtied)
        self.editor.data_changed.connect(self.wyswyg_dirtied)
    def __init__(self, parent_dialog, plugin_action):
        QWidget.__init__(self)
        self.parent_dialog = parent_dialog
        self.plugin_action = plugin_action

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

        label = QLabel(_('When Summing Columns, Calculate:'))
        label.setWordWrap(True)
        self.l.addWidget(label)
        #self.l.addSpacing(5)

        scrollable = QScrollArea()
        scrollcontent = QWidget()
        scrollable.setWidget(scrollcontent)
        scrollable.setWidgetResizable(True)
        self.l.addWidget(scrollable)

        self.sl = QVBoxLayout()
        scrollcontent.setLayout(self.sl)

        self.showsums = QCheckBox(_('Sum'), self)
        self.showsums.setToolTip(
            _('Sum of numeric columns for selected books.'))
        self.showsums.setChecked(prefs['showsums'])
        self.sl.addWidget(self.showsums)
        if 'Reading List' not in plugin_action.gui.iactions:
            self.showsums.setEnabled(False)

        self.showaverages = QCheckBox(_('Average'), self)
        self.showaverages.setToolTip(
            _('Average of numeric columns for selected books.'))
        self.showaverages.setChecked(prefs['showaverages'])
        self.sl.addWidget(self.showaverages)

        self.showstds = QCheckBox(_('Standard Deviation'), self)
        self.showstds.setToolTip(
            _('Standard Deviation of numeric columns for selected books.'))
        self.showstds.setChecked(prefs['showstds'])
        self.sl.addWidget(self.showstds)

        self.sl.insertStretch(-1)

        self.l.addSpacing(15)

        label = QLabel(
            _("These controls aren't plugin settings as such, but convenience buttons for setting Keyboard shortcuts and viewing all plugins settings."
              ))
        label.setWordWrap(True)
        self.l.addWidget(label)
        self.l.addSpacing(5)

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

        view_prefs_button = QPushButton(_('&View library preferences...'),
                                        self)
        view_prefs_button.setToolTip(
            _('View data stored in the library database for this plugin'))
        view_prefs_button.clicked.connect(self.view_prefs)
        self.l.addWidget(view_prefs_button)
Example #51
0
 def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     if hasattr(self, 'setupUi'):
         self.setupUi(self)
     self.settings = {}
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = 'ipetrash'

from PyQt5.Qt import QApplication, QLabel, QVBoxLayout, QWidget

app = QApplication([])

label_1 = QLabel()
label_1.setText('Hello World!!!')
label_1.setStyleSheet("""
    font: bold italic;
    color: green;
    background-color: black;
""")

label_2 = QLabel()
label_2.setText('nothing...')

layout = QVBoxLayout()
layout.addWidget(label_1)
layout.addWidget(label_2)

mw = QWidget()
mw.setLayout(layout)
mw.show()

app.exec()
Example #53
0
    def __init__(self, parent, db):
        QDialog.__init__(self, parent)
        self.db = db

        self.setWindowTitle(_('Check Library -- Problems Found'))
        self.setWindowIcon(QIcon(I('debug.png')))

        self._tl = QHBoxLayout()
        self.setLayout(self._tl)
        self.splitter = QSplitter(self)
        self.left = QWidget(self)
        self.splitter.addWidget(self.left)
        self.helpw = QTextEdit(self)
        self.splitter.addWidget(self.helpw)
        self._tl.addWidget(self.splitter)
        self._layout = QVBoxLayout()
        self.left.setLayout(self._layout)
        self.helpw.setReadOnly(True)
        self.helpw.setText(_('''\
        <h1>Help</h1>

        <p>calibre stores the list of your books and their metadata in a
        database. The actual book files and covers are stored as normal
        files in the calibre library folder. The database contains a list of the files
        and covers belonging to each book entry. This tool checks that the
        actual files in the library folder on your computer match the
        information in the database.</p>

        <p>The result of each type of check is shown to the left. The various
        checks are:
        </p>
        <ul>
        <li><b>Invalid titles</b>: These are files and folders appearing
        in the library where books titles should, but that do not have the
        correct form to be a book title.</li>
        <li><b>Extra titles</b>: These are extra files in your calibre
        library that appear to be correctly-formed titles, but have no corresponding
        entries in the database</li>
        <li><b>Invalid authors</b>: These are files appearing
        in the library where only author folders should be.</li>
        <li><b>Extra authors</b>: These are folders in the
        calibre library that appear to be authors but that do not have entries
        in the database</li>
        <li><b>Missing book formats</b>: These are book formats that are in
        the database but have no corresponding format file in the book's folder.
        <li><b>Extra book formats</b>: These are book format files found in
        the book's folder but not in the database.
        <li><b>Unknown files in books</b>: These are extra files in the
        folder of each book that do not correspond to a known format or cover
        file.</li>
        <li><b>Missing cover files</b>: These represent books that are marked
        in the database as having covers but the actual cover files are
        missing.</li>
        <li><b>Cover files not in database</b>: These are books that have
        cover files but are marked as not having covers in the database.</li>
        <li><b>Folder raising exception</b>: These represent folders in the
        calibre library that could not be processed/understood by this
        tool.</li>
        </ul>

        <p>There are two kinds of automatic fixes possible: <i>Delete
        marked</i> and <i>Fix marked</i>.</p>
        <p><i>Delete marked</i> is used to remove extra files/folders/covers that
        have no entries in the database. Check the box next to the item you want
        to delete. Use with caution.</p>

        <p><i>Fix marked</i> is applicable only to covers and missing formats
        (the three lines marked 'fixable'). In the case of missing cover files,
        checking the fixable box and pushing this button will tell calibre that
        there is no cover for all of the books listed. Use this option if you
        are not going to restore the covers from a backup. In the case of extra
        cover files, checking the fixable box and pushing this button will tell
        calibre that the cover files it found are correct for all the books
        listed. Use this when you are not going to delete the file(s). In the
        case of missing formats, checking the fixable box and pushing this
        button will tell calibre that the formats are really gone. Use this if
        you are not going to restore the formats from a backup.</p>

        '''))

        self.log = QTreeWidget(self)
        self.log.itemChanged.connect(self.item_changed)
        self.log.itemExpanded.connect(self.item_expanded_or_collapsed)
        self.log.itemCollapsed.connect(self.item_expanded_or_collapsed)
        self._layout.addWidget(self.log)

        self.check_button = QPushButton(_('&Run the check again'))
        self.check_button.setDefault(False)
        self.check_button.clicked.connect(self.run_the_check)
        self.copy_button = QPushButton(_('Copy &to clipboard'))
        self.copy_button.setDefault(False)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.ok_button = QPushButton(_('&Done'))
        self.ok_button.setDefault(True)
        self.ok_button.clicked.connect(self.accept)
        self.mark_delete_button = QPushButton(_('Mark &all for delete'))
        self.mark_delete_button.setToolTip(_('Mark all deletable subitems'))
        self.mark_delete_button.setDefault(False)
        self.mark_delete_button.clicked.connect(self.mark_for_delete)
        self.delete_button = QPushButton(_('Delete &marked'))
        self.delete_button.setToolTip(_('Delete marked files (checked subitems)'))
        self.delete_button.setDefault(False)
        self.delete_button.clicked.connect(self.delete_marked)
        self.mark_fix_button = QPushButton(_('Mar&k all for fix'))
        self.mark_fix_button.setToolTip(_('Mark all fixable items'))
        self.mark_fix_button.setDefault(False)
        self.mark_fix_button.clicked.connect(self.mark_for_fix)
        self.fix_button = QPushButton(_('&Fix marked'))
        self.fix_button.setDefault(False)
        self.fix_button.setEnabled(False)
        self.fix_button.setToolTip(_('Fix marked sections (checked fixable items)'))
        self.fix_button.clicked.connect(self.fix_items)
        self.bbox = QGridLayout()
        self.bbox.addWidget(self.check_button, 0, 0)
        self.bbox.addWidget(self.copy_button, 0, 1)
        self.bbox.addWidget(self.ok_button, 0, 2)
        self.bbox.addWidget(self.mark_delete_button, 1, 0)
        self.bbox.addWidget(self.delete_button, 1, 1)
        self.bbox.addWidget(self.mark_fix_button, 2, 0)
        self.bbox.addWidget(self.fix_button, 2, 1)

        h = QHBoxLayout()
        ln = QLabel(_('Names to ignore:'))
        h.addWidget(ln)
        self.name_ignores = QLineEdit()
        self.name_ignores.setText(db.prefs.get('check_library_ignore_names', ''))
        self.name_ignores.setToolTip(
            _('Enter comma-separated standard file name wildcards, such as synctoy*.dat'))
        ln.setBuddy(self.name_ignores)
        h.addWidget(self.name_ignores)
        le = QLabel(_('Extensions to ignore:'))
        h.addWidget(le)
        self.ext_ignores = QLineEdit()
        self.ext_ignores.setText(db.prefs.get('check_library_ignore_extensions', ''))
        self.ext_ignores.setToolTip(
            _('Enter comma-separated extensions without a leading dot. Used only in book folders'))
        le.setBuddy(self.ext_ignores)
        h.addWidget(self.ext_ignores)
        self._layout.addLayout(h)

        self._layout.addLayout(self.bbox)
        self.resize(950, 500)
Example #54
0
    def __init__(self,
                 field_metadata,
                 parent=None,
                 revert_tooltip=None,
                 datetime_fmt='MMMM yyyy',
                 blank_as_equal=True,
                 fields=('title', 'authors', 'series', 'tags', 'rating',
                         'publisher', 'pubdate', 'identifiers', 'languages',
                         'comments', 'cover'),
                 db=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout()
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)
        revert_tooltip = revert_tooltip or _('Revert %s')
        self.current_mi = None
        self.changed_font = QFont(QApplication.font())
        self.changed_font.setBold(True)
        self.changed_font.setItalic(True)
        self.blank_as_equal = blank_as_equal

        self.widgets = OrderedDict()
        row = 0

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

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

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

        self.h = h = QHBoxLayout()
        self.filter_text = ft = QLineEdit(self)
        ft.textChanged.connect(self.do_filter)
        ft.setPlaceholderText(_('Filter displayed searches'))
        h.addWidget(ft)
        self.cft = cft = QToolButton(self)
        cft.setToolTip(_('Clear filter')), cft.setIcon(QIcon(I('clear_left.png')))
        cft.clicked.connect(ft.clear)
        h.addWidget(cft)
        l.addLayout(h)

        self.h2 = h = QHBoxLayout()
        self.searches = searches = QListView(self)
        self.stack = stack = QStackedLayout()
        self.main_widget = mw = QWidget(self)
        stack.addWidget(mw)
        self.edit_search_widget = es = EditSearch(mw)
        stack.addWidget(es)
        es.done.connect(self.search_editing_done)
        mw.v = QVBoxLayout(mw)
        mw.v.setContentsMargins(0, 0, 0, 0)
        mw.v.addWidget(searches)
        searches.doubleClicked.connect(self.edit_search)
        self.model = SearchesModel(self.searches)
        self.model.dataChanged.connect(self.show_details)
        searches.setModel(self.model)
        searches.selectionModel().currentChanged.connect(self.show_details)
        searches.setSelectionMode(searches.ExtendedSelection)
        self.delegate = SearchDelegate(searches)
        searches.setItemDelegate(self.delegate)
        searches.setAlternatingRowColors(True)
        h.addLayout(stack, stretch=10)
        self.v = v = QVBoxLayout()
        h.addLayout(v)
        l.addLayout(h)
        stack.currentChanged.connect(self.stack_current_changed)

        def pb(text, tooltip=None):
            b = AnimatablePushButton(text, self)
            b.setToolTip(tooltip or '')
            b.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
            return b

        mulmsg = '\n\n' + _('The entries are tried in order until the first one matches.')
        self.action_button_map = {}

        for text, action, tooltip in [
                (_('&Find'), 'find', _('Run the search using the selected entries.') + mulmsg),
                (_('&Replace'), 'replace', _('Run replace using the selected entries.') + mulmsg),
                (_('Replace a&nd Find'), 'replace-find', _('Run replace and then find using the selected entries.') + mulmsg),
                (_('Replace &all'), 'replace-all', _('Run Replace All for all selected entries in the order selected')),
                (_('&Count all'), 'count', _('Run Count All for all selected entries')),
        ]:
            self.action_button_map[action] = b = pb(text, tooltip)
            v.addWidget(b)
            b.clicked.connect(partial(self.run_search, action))

        self.d1 = d = QFrame(self)
        d.setFrameStyle(QFrame.HLine)
        v.addWidget(d)

        self.h3 = h = QHBoxLayout()
        self.upb = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png'))), b.setToolTip(_('Move selected entries up'))
        b.clicked.connect(partial(self.move_entry, -1))
        self.dnb = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png'))), b.setToolTip(_('Move selected entries down'))
        b.clicked.connect(partial(self.move_entry, 1))
        h.addWidget(self.upb), h.addWidget(self.dnb)
        v.addLayout(h)

        self.eb = b = pb(_('&Edit search'), _('Edit the currently selected search'))
        b.clicked.connect(self.edit_search)
        v.addWidget(b)

        self.rb = b = pb(_('Re&move search'), _('Remove the currently selected searches'))
        b.clicked.connect(self.remove_search)
        v.addWidget(b)

        self.ab = b = pb(_('&Add search'), _('Add a new saved search'))
        b.clicked.connect(self.add_search)
        v.addWidget(b)

        self.d2 = d = QFrame(self)
        d.setFrameStyle(QFrame.HLine)
        v.addWidget(d)

        self.where_box = wb = WhereBox(self, emphasize=True)
        self.where = SearchWidget.DEFAULT_STATE['where']
        v.addWidget(wb)
        self.direction_box = db = DirectionBox(self)
        self.direction = SearchWidget.DEFAULT_STATE['direction']
        v.addWidget(db)

        self.wr = wr = QCheckBox(_('&Wrap'))
        wr.setToolTip('<p>'+_('When searching reaches the end, wrap around to the beginning and continue the search'))
        self.wr.setChecked(SearchWidget.DEFAULT_STATE['wrap'])
        v.addWidget(wr)

        self.d3 = d = QFrame(self)
        d.setFrameStyle(QFrame.HLine)
        v.addWidget(d)

        self.description = d = QLabel(' \n \n ')
        d.setTextFormat(Qt.PlainText)
        d.setWordWrap(True)
        mw.v.addWidget(d)

        self.ib = b = pb(_('&Import'), _('Import saved searches'))
        b.clicked.connect(self.import_searches)
        v.addWidget(b)

        self.eb2 = b = pb(_('E&xport'), _('Export saved searches'))
        v.addWidget(b)
        self.em = m = QMenu(_('Export'))
        m.addAction(_('Export All'), lambda : QTimer.singleShot(0, partial(self.export_searches, all=True)))
        m.addAction(_('Export Selected'), lambda : QTimer.singleShot(0, partial(self.export_searches, all=False)))
        b.setMenu(m)

        self.searches.setFocus(Qt.OtherFocusReason)
    def setup_ui(self, parent):
        cm = self.col_metadata
        self.make_widgets(parent, DateTimeEdit)
        self.widgets.append(QLabel(''))
        w = QWidget(parent)
        self.widgets.append(w)
        l = QHBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        w.setLayout(l)
        l.addStretch(1)
        self.today_button = QPushButton(
            _('Set \'%s\' to today') % cm['name'], parent)
        l.addWidget(self.today_button)
        self.clear_button = QPushButton(_('Clear \'%s\'') % cm['name'], parent)
        l.addWidget(self.clear_button)
        l.addStretch(2)

        w = self.main_widget
        format = cm['display'].get('date_format', '')
        if not format:
            format = 'dd MMM yyyy'
        w.setDisplayFormat(format)
        w.setCalendarPopup(True)
        w.setMinimumDateTime(UNDEFINED_QDATETIME)
        w.setSpecialValueText(_('Undefined'))
        self.today_button.clicked.connect(w.set_to_today)
        self.clear_button.clicked.connect(w.set_to_clear)
Example #57
0
 def keyPressEvent(self, ev):
     if ev.key() == Qt.Key_Escape:
         self.hide_panel()
         ev.accept()
     else:
         return QWidget.keyPressEvent(self, ev)
Example #58
0
class CheckLibraryDialog(QDialog):

    def __init__(self, parent, db):
        QDialog.__init__(self, parent)
        self.db = db

        self.setWindowTitle(_('Check Library -- Problems Found'))
        self.setWindowIcon(QIcon(I('debug.png')))

        self._tl = QHBoxLayout()
        self.setLayout(self._tl)
        self.splitter = QSplitter(self)
        self.left = QWidget(self)
        self.splitter.addWidget(self.left)
        self.helpw = QTextEdit(self)
        self.splitter.addWidget(self.helpw)
        self._tl.addWidget(self.splitter)
        self._layout = QVBoxLayout()
        self.left.setLayout(self._layout)
        self.helpw.setReadOnly(True)
        self.helpw.setText(_('''\
        <h1>Help</h1>

        <p>calibre stores the list of your books and their metadata in a
        database. The actual book files and covers are stored as normal
        files in the calibre library folder. The database contains a list of the files
        and covers belonging to each book entry. This tool checks that the
        actual files in the library folder on your computer match the
        information in the database.</p>

        <p>The result of each type of check is shown to the left. The various
        checks are:
        </p>
        <ul>
        <li><b>Invalid titles</b>: These are files and folders appearing
        in the library where books titles should, but that do not have the
        correct form to be a book title.</li>
        <li><b>Extra titles</b>: These are extra files in your calibre
        library that appear to be correctly-formed titles, but have no corresponding
        entries in the database</li>
        <li><b>Invalid authors</b>: These are files appearing
        in the library where only author folders should be.</li>
        <li><b>Extra authors</b>: These are folders in the
        calibre library that appear to be authors but that do not have entries
        in the database</li>
        <li><b>Missing book formats</b>: These are book formats that are in
        the database but have no corresponding format file in the book's folder.
        <li><b>Extra book formats</b>: These are book format files found in
        the book's folder but not in the database.
        <li><b>Unknown files in books</b>: These are extra files in the
        folder of each book that do not correspond to a known format or cover
        file.</li>
        <li><b>Missing cover files</b>: These represent books that are marked
        in the database as having covers but the actual cover files are
        missing.</li>
        <li><b>Cover files not in database</b>: These are books that have
        cover files but are marked as not having covers in the database.</li>
        <li><b>Folder raising exception</b>: These represent folders in the
        calibre library that could not be processed/understood by this
        tool.</li>
        </ul>

        <p>There are two kinds of automatic fixes possible: <i>Delete
        marked</i> and <i>Fix marked</i>.</p>
        <p><i>Delete marked</i> is used to remove extra files/folders/covers that
        have no entries in the database. Check the box next to the item you want
        to delete. Use with caution.</p>

        <p><i>Fix marked</i> is applicable only to covers and missing formats
        (the three lines marked 'fixable'). In the case of missing cover files,
        checking the fixable box and pushing this button will tell calibre that
        there is no cover for all of the books listed. Use this option if you
        are not going to restore the covers from a backup. In the case of extra
        cover files, checking the fixable box and pushing this button will tell
        calibre that the cover files it found are correct for all the books
        listed. Use this when you are not going to delete the file(s). In the
        case of missing formats, checking the fixable box and pushing this
        button will tell calibre that the formats are really gone. Use this if
        you are not going to restore the formats from a backup.</p>

        '''))

        self.log = QTreeWidget(self)
        self.log.itemChanged.connect(self.item_changed)
        self.log.itemExpanded.connect(self.item_expanded_or_collapsed)
        self.log.itemCollapsed.connect(self.item_expanded_or_collapsed)
        self._layout.addWidget(self.log)

        self.check_button = QPushButton(_('&Run the check again'))
        self.check_button.setDefault(False)
        self.check_button.clicked.connect(self.run_the_check)
        self.copy_button = QPushButton(_('Copy &to clipboard'))
        self.copy_button.setDefault(False)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.ok_button = QPushButton(_('&Done'))
        self.ok_button.setDefault(True)
        self.ok_button.clicked.connect(self.accept)
        self.mark_delete_button = QPushButton(_('Mark &all for delete'))
        self.mark_delete_button.setToolTip(_('Mark all deletable subitems'))
        self.mark_delete_button.setDefault(False)
        self.mark_delete_button.clicked.connect(self.mark_for_delete)
        self.delete_button = QPushButton(_('Delete &marked'))
        self.delete_button.setToolTip(_('Delete marked files (checked subitems)'))
        self.delete_button.setDefault(False)
        self.delete_button.clicked.connect(self.delete_marked)
        self.mark_fix_button = QPushButton(_('Mar&k all for fix'))
        self.mark_fix_button.setToolTip(_('Mark all fixable items'))
        self.mark_fix_button.setDefault(False)
        self.mark_fix_button.clicked.connect(self.mark_for_fix)
        self.fix_button = QPushButton(_('&Fix marked'))
        self.fix_button.setDefault(False)
        self.fix_button.setEnabled(False)
        self.fix_button.setToolTip(_('Fix marked sections (checked fixable items)'))
        self.fix_button.clicked.connect(self.fix_items)
        self.bbox = QGridLayout()
        self.bbox.addWidget(self.check_button, 0, 0)
        self.bbox.addWidget(self.copy_button, 0, 1)
        self.bbox.addWidget(self.ok_button, 0, 2)
        self.bbox.addWidget(self.mark_delete_button, 1, 0)
        self.bbox.addWidget(self.delete_button, 1, 1)
        self.bbox.addWidget(self.mark_fix_button, 2, 0)
        self.bbox.addWidget(self.fix_button, 2, 1)

        h = QHBoxLayout()
        ln = QLabel(_('Names to ignore:'))
        h.addWidget(ln)
        self.name_ignores = QLineEdit()
        self.name_ignores.setText(db.prefs.get('check_library_ignore_names', ''))
        self.name_ignores.setToolTip(
            _('Enter comma-separated standard file name wildcards, such as synctoy*.dat'))
        ln.setBuddy(self.name_ignores)
        h.addWidget(self.name_ignores)
        le = QLabel(_('Extensions to ignore:'))
        h.addWidget(le)
        self.ext_ignores = QLineEdit()
        self.ext_ignores.setText(db.prefs.get('check_library_ignore_extensions', ''))
        self.ext_ignores.setToolTip(
            _('Enter comma-separated extensions without a leading dot. Used only in book folders'))
        le.setBuddy(self.ext_ignores)
        h.addWidget(self.ext_ignores)
        self._layout.addLayout(h)

        self._layout.addLayout(self.bbox)
        self.resize(950, 500)

    def do_exec(self):
        self.run_the_check()

        probs = 0
        for c in self.problem_count:
            probs += self.problem_count[c]
        if probs == 0:
            return False
        self.exec_()
        return True

    def accept(self):
        self.db.new_api.set_pref('check_library_ignore_extensions', unicode(self.ext_ignores.text()))
        self.db.new_api.set_pref('check_library_ignore_names', unicode(self.name_ignores.text()))
        QDialog.accept(self)

    def box_to_list(self, txt):
        return [f.strip() for f in txt.split(',') if f.strip()]

    def run_the_check(self):
        checker = CheckLibrary(self.db.library_path, self.db)
        checker.scan_library(self.box_to_list(unicode(self.name_ignores.text())),
                             self.box_to_list(unicode(self.ext_ignores.text())))

        plaintext = []

        def builder(tree, checker, check):
            attr, h, checkable, fixable = check
            list = getattr(checker, attr, None)
            if list is None:
                self.problem_count[attr] = 0
                return
            else:
                self.problem_count[attr] = len(list)

            tl = Item()
            tl.setText(0, h)
            if fixable and list:
                tl.setText(1, _('(fixable)'))
                tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
                tl.setCheckState(1, False)
            else:
                tl.setFlags(Qt.ItemIsEnabled)
            self.top_level_items[attr] = tl

            for problem in list:
                it = Item()
                if checkable:
                    it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
                    it.setCheckState(1, False)
                else:
                    it.setFlags(Qt.ItemIsEnabled)
                it.setText(0, problem[0])
                it.setData(0, Qt.UserRole, problem[2])
                it.setText(1, problem[1])
                tl.addChild(it)
                self.all_items.append(it)
                plaintext.append(','.join([h, problem[0], problem[1]]))
            tree.addTopLevelItem(tl)

        t = self.log
        t.clear()
        t.setColumnCount(2)
        t.setHeaderLabels([_('Name'), _('Path from library')])
        self.all_items = []
        self.top_level_items = {}
        self.problem_count = {}
        for check in CHECKS:
            builder(t, checker, check)

        t.resizeColumnToContents(0)
        t.resizeColumnToContents(1)
        self.delete_button.setEnabled(False)
        self.fix_button.setEnabled(False)
        self.text_results = '\n'.join(plaintext)

    def item_expanded_or_collapsed(self, item):
        self.log.resizeColumnToContents(0)
        self.log.resizeColumnToContents(1)

    def item_changed(self, item, column):
        self.fix_button.setEnabled(False)
        for it in self.top_level_items.values():
            if it.checkState(1):
                self.fix_button.setEnabled(True)

        self.delete_button.setEnabled(False)
        for it in self.all_items:
            if it.checkState(1):
                self.delete_button.setEnabled(True)
                return

    def mark_for_fix(self):
        for it in self.top_level_items.values():
            if it.flags() & Qt.ItemIsUserCheckable:
                it.setCheckState(1, Qt.Checked)

    def mark_for_delete(self):
        for it in self.all_items:
            if it.flags() & Qt.ItemIsUserCheckable:
                it.setCheckState(1, Qt.Checked)

    def delete_marked(self):
        if not confirm('<p>'+_('The marked files and folders will be '
               '<b>permanently deleted</b>. Are you sure?') + '</p>', 'check_library_editor_delete', self):
            return

        # Sort the paths in reverse length order so that we can be sure that
        # if an item is in another item, the sub-item will be deleted first.
        items = sorted(self.all_items,
                       key=lambda x: len(x.text(1)),
                       reverse=True)
        for it in items:
            if it.checkState(1):
                try:
                    p = os.path.join(self.db.library_path ,unicode(it.text(1)))
                    if os.path.isdir(p):
                        delete_tree(p)
                    else:
                        delete_file(p)
                except:
                    prints('failed to delete',
                            os.path.join(self.db.library_path,
                                unicode(it.text(1))))
        self.run_the_check()

    def fix_missing_formats(self):
        tl = self.top_level_items['missing_formats']
        child_count = tl.childCount()
        for i in range(0, child_count):
            item = tl.child(i)
            id = int(item.data(0, Qt.UserRole))
            all = self.db.formats(id, index_is_id=True, verify_formats=False)
            all = set([f.strip() for f in all.split(',')]) if all else set()
            valid = self.db.formats(id, index_is_id=True, verify_formats=True)
            valid = set([f.strip() for f in valid.split(',')]) if valid else set()
            for fmt in all-valid:
                self.db.remove_format(id, fmt, index_is_id=True, db_only=True)

    def fix_missing_covers(self):
        tl = self.top_level_items['missing_covers']
        child_count = tl.childCount()
        for i in range(0, child_count):
            item = tl.child(i)
            id = int(item.data(0, Qt.UserRole))
            self.db.set_has_cover(id, False)

    def fix_extra_covers(self):
        tl = self.top_level_items['extra_covers']
        child_count = tl.childCount()
        for i in range(0, child_count):
            item = tl.child(i)
            id = int(item.data(0, Qt.UserRole))
            self.db.set_has_cover(id, True)

    def fix_items(self):
        for check in CHECKS:
            attr = check[0]
            fixable = check[3]
            tl = self.top_level_items[attr]
            if fixable and tl.checkState(1):
                func = getattr(self, 'fix_' + attr, None)
                if func is not None and callable(func):
                    func()
        self.run_the_check()

    def copy_to_clipboard(self):
        QApplication.clipboard().setText(self.text_results)
Example #59
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.l = l = QGridLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)

        self.fl = fl = QLabel(_('&Find:'))
        fl.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        self.find_text = ft = HistoryBox(self, _('Clear search history'))
        ft.save_search.connect(self.save_search)
        ft.show_saved_searches.connect(self.show_saved_searches)
        ft.initialize('tweak_book_find_edit')
        ft.lineEdit().returnPressed.connect(lambda : self.search_triggered.emit('find'))
        fl.setBuddy(ft)
        l.addWidget(fl, 0, 0)
        l.addWidget(ft, 0, 1)

        self.rl = rl = QLabel(_('&Replace:'))
        rl.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        self.replace_text = rt = HistoryBox(self, _('Clear replace history'))
        rt.save_search.connect(self.save_search)
        rt.show_saved_searches.connect(self.show_saved_searches)
        rt.initialize('tweak_book_replace_edit')
        rl.setBuddy(rt)
        l.addWidget(rl, 1, 0)
        l.addWidget(rt, 1, 1)
        l.setColumnStretch(1, 10)

        self.fb = fb = PushButton(_('&Find'), 'find', self)
        self.rfb = rfb = PushButton(_('Replace a&nd Find'), 'replace-find', self)
        self.rb = rb = PushButton(_('&Replace'), 'replace', self)
        self.rab = rab = PushButton(_('Replace &all'), 'replace-all', self)
        l.addWidget(fb, 0, 2)
        l.addWidget(rfb, 0, 3)
        l.addWidget(rb, 1, 2)
        l.addWidget(rab, 1, 3)

        self.ml = ml = QLabel(_('&Mode:'))
        self.ol = ol = QHBoxLayout()
        ml.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        l.addWidget(ml, 2, 0)
        l.addLayout(ol, 2, 1, 1, 3)
        self.mode_box = mb = ModeBox(self)
        mb.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        ml.setBuddy(mb)
        ol.addWidget(mb)

        self.where_box = wb = WhereBox(self)
        wb.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
        ol.addWidget(wb)

        self.direction_box = db = DirectionBox(self)
        db.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        ol.addWidget(db)

        self.cs = cs = QCheckBox(_('&Case sensitive'))
        cs.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        ol.addWidget(cs)

        self.wr = wr = QCheckBox(_('&Wrap'))
        wr.setToolTip('<p>'+_('When searching reaches the end, wrap around to the beginning and continue the search'))
        wr.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        ol.addWidget(wr)

        self.da = da = QCheckBox(_('&Dot all'))
        da.setToolTip('<p>'+_("Make the '.' special character match any character at all, including a newline"))
        da.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        ol.addWidget(da)

        self.mode_box.currentIndexChanged[int].connect(self.da.setVisible)

        ol.addStretch(10)
Example #60
0
 def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     self.setup_ui()