Example #1
1
class PrincePDFDialog(QDialog):
    prince_log = ''

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

        self.setAttribute(Qt.WA_DeleteOnClose)

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

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

        self.image = QLabel()
        self.image.setPixmap(icon.pixmap(120, 120))
        self.l.addWidget(self.image, 1, 1, 4, 1, Qt.AlignVCenter)

        self.convert_to_PDF_button = QPushButton(_('Convert to &PDF'), self)
        self.convert_to_PDF_button.clicked.connect(self.convert_to_PDF)
        self.convert_to_PDF_button.setDefault(True)
        self.convert_to_PDF_button.setToolTip(_('<qt>Start the conversion process</qt>'))
        self.l.addWidget(self.convert_to_PDF_button, 1, 2, Qt.AlignVCenter)

        self.view_log = QPushButton(_('&View log'), self)
        self.view_log.clicked.connect(self.show_log)
        self.view_log.setToolTip(_('<qt>Display the log from the last Prince run</qt>'))
        self.l.addWidget(self.view_log, 2, 2, Qt.AlignVCenter)
        self.view_log.hide()

        self.conf_button = QPushButton(_('Con&figure'), self)
        self.conf_button.clicked.connect(self.config)
        self.conf_button.setToolTip(_('<qt>Configure this plugin</qt>'))
        self.l.addWidget(self.conf_button, 4, 2, Qt.AlignVCenter)

        self.info = QLabel()
        self.l.addWidget(self.info, 5, 1, 1, -1)

        self.suggestion = QLabel()
        self.suggestion.setAlignment(Qt.AlignCenter)
        self.l.addWidget(self.suggestion, 6, 1, 1, -1)

        self.l.setColumnStretch(1, 1)
        self.l.setColumnStretch(2, 10)
        self.l.setRowStretch(1, 1)
        self.l.setRowStretch(2, 1)
        self.l.setRowStretch(3, 10)
        self.l.setRowStretch(4, 1)
        self.l.setRowStretch(5, 1)
        self.l.setRowStretch(6, 1)
        self.l.setRowMinimumHeight(1, 1)
        self.l.setRowMinimumHeight(2, 1)
        self.l.setRowMinimumHeight(3, 1)
        self.l.setRowMinimumHeight(4, 1)
        self.l.setRowMinimumHeight(5, 1)
        self.l.setRowMinimumHeight(6, 1)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Close | QDialogButtonBox.Help)
        self.l.addWidget(self.buttons, 7, 1, 1, -1)
        self.buttons.rejected.connect(self.reject)
        self.buttons.helpRequested.connect(self.about)

        self.adjustSize()

        # Update the info now and every time the selection or the data changes
        self.gui.library_view.model().dataChanged.connect(self.update_info)
        self.gui.library_view.selectionModel().selectionChanged.connect(self.update_info)
        self.update_info()

    def update_info(self):
        '''
        Update the info on top of the window
        '''

        self.db = self.gui.current_db
        # Get selected rows
        rows = self.gui.library_view.selectionModel().selectedRows()
        if not rows or len(rows) == 0:
            self.info.setText(_('<b>No books selected</b>'))
            self.info.setAlignment(Qt.AlignCenter)
            self.suggestion.setText(_('Select one single book'))
            self.selected = None
            self.convert_to_PDF_button.setEnabled(False)
        elif len(rows) > 1:
            self.info.setText(_('<b>Many books selected</b>'))
            self.info.setAlignment(Qt.AlignCenter)
            self.suggestion.setText(_('Select one single book'))
            self.selected = None
            self.convert_to_PDF_button.setEnabled(False)
        else:
            # If there is only one selected book, enable conversion
            # and show list of available formats (formats in prefs are bold)
            book_id = self.gui.library_view.model().id(rows[0])
            fmts = self.db.formats(book_id, index_is_id=True)
            if (fmts):
                fmts = fmts.split(',')
            else: 
                fmts = [_('<i>none</i>')]
            available = False
            for i,fmt in enumerate(fmts):
                fmts[i] = fmt.lower()
                if fmts[i] in prefs['formats']:
                    fmts[i] = '<b>%s</b>' % fmts[i]
                    available = True
            self.info.setText(_('Available formats: %s') % ', '.join(fmts))
            self.info.setAlignment(Qt.AlignLeft)
            # Conversion enabled only if some "preferred" format is found
            if (available):
                self.suggestion.setText(_('Ready'))
                self.selected = book_id
                self.convert_to_PDF_button.setEnabled(True)
            else:
                self.suggestion.setText(_('No preferred format available'))
                self.selected = None
                self.convert_to_PDF_button.setEnabled(False)

    def about(self):
        '''
        Display a short help message
        '''
        from os.path import join
        from calibre.ptempfile import TemporaryDirectory
        from calibre.gui2.dialogs.message_box import MessageBox
        from calibre_plugins.prince_pdf.help import help_txt, license_txt
        from calibre_plugins.prince_pdf import PrincePDFPlugin
        from calibre_plugins.prince_pdf import __license__

        author = PrincePDFPlugin.author
        version = "%i.%i.%i" % PrincePDFPlugin.version
        license = __license__
        with TemporaryDirectory('xxx') as tdir:
          for x in ('prince_icon.png', 'small_icon.png'):
            with open(join(tdir, x),'w') as f:
              f.write(get_resources('images/' + x))
          help_box = MessageBox(type_ = MessageBox.INFO, \
                                title = _('About the Prince PDF Plugin'), \
                                msg = help_txt % {'author':author, 'version':version, 'license':license, 'dir':tdir, 'code':'style="font-family:monospace ; font-weight:bold"'}, \
                                det_msg = 'Copyright \u00a9 %s\n%s' % (__copyright__, license_txt), \
                                q_icon = self.icon, \
                                show_copy_button = False)
          #help_box.gridLayout.addWidget(help_box.icon_widget,0,0,Qt.AlignTop)
          help_box.gridLayout.setAlignment(help_box.icon_widget,Qt.AlignTop)
          help_box.exec_()

    def convert_to_PDF(self):
        '''
        Unpack and convert the currently selected book to PDF
        '''
        from calibre.gui2 import error_dialog
        from calibre.constants import DEBUG

        # Get available formats
        book_id = self.selected
        fmts = self.db.formats(book_id, index_is_id=True)
        fmts = fmts.lower().split(',')
        # Process only the first format matching the 'formats' configuration option
        for fmt in prefs['formats']:
            fmt = fmt.lower()
            if (not fmt in fmts): continue
            mi = self.db.get_metadata(book_id, index_is_id=True, get_cover=False)
            pdf_base_file = self.get_filename(book_id, mi)

            # This is the actual code:
            if DEBUG: print('===========')
            # Unpack the book and call the conversion dialog
            (opf, oeb) = self.unpack(book_id, fmt)
            if (opf == None or oeb == None):
               return error_dialog(self.gui, _('Cannot convert to PDF'), _('Format not supported: %s') % fmt, show=True)
            convert_dialog = ConvertDialog(mi, fmt, opf, oeb, self.icon)
            convert_dialog.pdf_file = pdf_base_file
            pdf_file = ''
            if (convert_dialog.exec_()):
                pdf_file = convert_dialog.pdf_file
            self.prince_log = convert_dialog.prince_log
            # After the dialog returns, pdf_file has the output file path,
            # and prince_log has the Prince console output
            if DEBUG: print(_('PDF file: %s') % pdf_file)
            # If there is any log, enable the View log button
            if (self.prince_log):
                self.view_log.show()
                log_msg = _(' Check the log.')
            else:
                self.view_log.hide()
                log_msg = ''
            # If the conversion failed, pdf_file will be None,
            if (pdf_file == None):
                error_dialog(self.gui, _('Could not convert to PDF'), _('The conversion failed.') + log_msg , show=True)
            # If the user cancelled the dialog, pdf_file will be ''
            if (pdf_file):
                # Set the metadata in the PDF and add it or save it
                try:
                    self.set_pdf_metadata(mi, pdf_file)
                except:
                    error_dialog(self.gui, _('Could not convert to PDF'), _("Error reading or writing the PDF file:\n%s" % pdf_file), show=True)
                    return
                if (prefs['add_book']):
                    self.add_pdf(book_id, pdf_file, ('pdf' in fmts))
                else:
                    self.save_pdf(pdf_file, pdf_base_file)
	    if DEBUG: print('===========')
	    return
        # No matching format in the book
        return error_dialog(self.gui, _('Cannot convert to PDF'), _('No supported format available'), show=True)

    def show_log(self):
        '''
        Display the Prince log dialog
        '''
        msg = LogDialog(self.prince_log, self.icon)
        msg.exec_()

    def config(self):
        '''
        Display the configuration dialog
        '''
        self.do_user_config(parent=self)

    def get_filename(self, book_id, mi):
        '''
        Obtain a filename from the save_to_disk template
        :param book_id: The book identifier
        :param mi: The book metadata
        '''
        from os.path import join
        from calibre.library.save_to_disk import get_components, config
        from calibre import sanitize_file_name_unicode
        from calibre.utils.filenames import ascii_filename

        opts = config().parse()
        components = get_components(opts.template, mi, book_id, opts.timefmt,
                                    sanitize_func=(ascii_filename if opts.asciiize else sanitize_file_name_unicode),
                                    to_lowercase=opts.to_lowercase, replace_whitespace=opts.replace_whitespace)
        base_path = join(*components)
        return '%s.pdf' % base_path

    def unpack(self, book_id, fmt):
        '''
        Unpack the book in a temporary directory
        :param book_id: The book identifier
        :param fmt: The format to unpack
        '''
        from calibre.constants import DEBUG
        from calibre.ptempfile import PersistentTemporaryDirectory
        from calibre.ebooks.tweak import get_tools
        from calibre.ebooks.oeb.base import OEBBook
        from calibre.ebooks.oeb.reader import OEBReader
        from calibre.utils.logging import default_log
        from calibre_plugins.prince_pdf.dummy_preprocessor import dummy_preprocessor

        book_file = self.db.format(book_id, fmt, index_is_id=True, as_path=True)
        if DEBUG: print(_('Unpacking book...'))
        tdir = PersistentTemporaryDirectory('_unpack')
        exploder = get_tools(fmt)[0]
        if (exploder == None): return (None, None)
        opf = exploder(book_file, tdir)
        html_preprocessor = dummy_preprocessor()
        css_preprocessor = dummy_preprocessor()
        oeb = OEBBook(default_log, html_preprocessor, css_preprocessor)
        OEBReader()(oeb, opf)
        return (opf, oeb)

    def set_pdf_metadata(self, mi, pdf_file):
        '''
        Set the metadata in the PDF file
        :param mi: The book metadata
        :param pdf_file: The path to the PDF file
        '''
        from calibre.constants import DEBUG
        from calibre.ebooks.metadata.pdf import set_metadata

        if DEBUG: print(_('Setting metadata...'))
        pdf_stream = open(pdf_file, 'r+b')
        set_metadata(pdf_stream, mi)
        pdf_stream.close()

    def add_pdf(self, book_id, pdf_file, exists):
        '''
        Add the PDF file to the book record, asking for replacement
        :param book_id: The book identifier
        :param pdf_file: The path to the PDF file
        :param exists: True if there is already a PDF in the book
        '''
        from calibre.constants import DEBUG
        from calibre.gui2.dialogs.message_box import MessageBox

        add_it = True
        if (exists):
            msg = MessageBox(MessageBox.QUESTION, _('Existing format'),
                             _('The selected book already contains a PDF format. Are you sure you want to replace it?'),
                             _("The temporary file can be found in:\n%s") % pdf_file)
            msg.toggle_det_msg()
            add_it = (msg.exec_())
        if (add_it):
            if DEBUG: print(_('Adding PDF...'))
            self.db.new_api.add_format(book_id, 'pdf', pdf_file)
            self.gui.library_view.model().refresh_ids([book_id])
            self.gui.library_view.refresh_book_details()
            self.gui.tags_view.recount()

    def save_pdf(self, pdf_file, pdf_base_file):
        '''
        Save the PDF file in the final location
        :param pdf_file: The path to the PDF file
        :param pdf_base_file: The desired file name and relative path
        '''
        from os import rename, makedirs
        from os.path import basename, dirname, join, exists
        from calibre.constants import DEBUG
        from calibre.gui2 import choose_dir
        from calibre.gui2.dialogs.message_box import MessageBox
        from calibre.gui2 import error_dialog

        path = choose_dir(self.gui, 'save to disk dialog', _('Choose destination directory'))
        if not path:
            return
        save_file = join(path, pdf_base_file)
        base_dir = dirname(save_file)
        try:
            makedirs(base_dir)
        except BaseException:
            if not exists(base_dir): raise
        try:
            rename(pdf_file, save_file)
        except:
            error_dialog(self.gui, _('Could not save PDF'), _("Error writing the PDF file:\n%s" % save_file), show=True)
            return
        if DEBUG: print(save_file)
        MessageBox(MessageBox.INFO, _('File saved'), _("PDF file saved in:\n%s") % save_file).exec_()
Example #2
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 #3
0
class MetadataGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(MetadataGroupBox, self).__init__(parent, device)
        self.setTitle(_("Update metadata on the device"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('update_device_metadata'))
        self.setToolTip(wrap_msg(_('Update the metadata on the device when it is connected. '
                               'Be careful when doing this as it will take time and could make the initial connection take a long time.')))

        self.update_series_checkbox = create_checkbox(
                             _("Set Series information"),
                             _('The book lists on the Kobo devices can display series information. '
                               'This is not read by the device from the sideloaded books. '
                               'Series information can only be added to the device after the book has been processed by the device. '
                               'Enable if you wish to set series information.'),
                             device.get_pref('update_series')
                             )
        self.options_layout.addWidget(self.update_series_checkbox, 0, 0, 1, 1)
        self.options_layout.setRowStretch(1, 1)

    @property
    def update_series(self):
        return self.update_series_checkbox.isChecked()

    @property
    def update_device_metadata(self):
        return self.isChecked()
Example #4
0
class MetadataGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(MetadataGroupBox, self).__init__(parent, device)
        self.setTitle(_("Update metadata on the device"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('update_device_metadata'))
        self.setToolTip(
            wrap_msg(
                _('Update the metadata on the device when it is connected. '
                  'Be careful when doing this as it will take time and could make the initial connection take a long time.'
                  )))

        self.update_series_checkbox = create_checkbox(
            _("Set series information"),
            _('The book lists on the Kobo devices can display series information. '
              'This is not read by the device from the sideloaded books. '
              'Series information can only be added to the device after the book has been processed by the device. '
              'Enable if you wish to set series information.'),
            device.get_pref('update_series'))
        self.options_layout.addWidget(self.update_series_checkbox, 0, 0, 1, 1)
        self.options_layout.setRowStretch(1, 1)

    @property
    def update_series(self):
        return self.update_series_checkbox.isChecked()

    @property
    def update_device_metadata(self):
        return self.isChecked()
Example #5
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 #6
0
class DownloadStatus(QScrollArea):
    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.setWidgetResizable(True)
        self.w = QWidget(self)
        self.l = QGridLayout(self.w)
        self.setWidget(self.w)

    def __call__(self, resources):
        self.url_map = {}
        self.labels = []
        for url in resources:
            p = self.url_map[url] = QProgressBar(self.w)
            p.setRange(0, 0)
            self.l.addWidget(p, self.l.rowCount(), 0)
            la = QLabel('\xa0' + url)
            self.labels.append(la)
            self.l.addWidget(la, self.l.rowCount() - 1, 1)
        self.l.addWidget(QLabel(''))
        self.l.setRowStretch(self.l.rowCount() - 1, 10)

    def progress(self, url, done, total):
        p = self.url_map.get(url)
        if p is not None:
            if total > 0:
                p.setRange(0, total)
                p.setValue(done)
            else:
                p.setRange(0, 0)
Example #7
0
class BookUploadsGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(BookUploadsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Book Uploading"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.modify_css_checkbox = create_checkbox(
                _("Modify CSS"),
                _('This allows addition of user CSS rules and removal of some CSS. '
                'When sending a book, the driver adds the contents of {0} to all stylesheets in the ePub. '
                'This file is searched for in the root directory of the main memory of the device. '
                'As well as this, if the file contains settings for the "orphans" or "widows", '
                'these are removed for all styles in the original stylesheet.').format(device.KOBO_EXTRA_CSSFILE),
                device.get_pref('modify_css')
                )

        self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
        self.options_layout.setRowStretch(1, 1)

    @property
    def modify_css(self):
        return self.modify_css_checkbox.isChecked()
Example #8
0
class DownloadStatus(QScrollArea):

    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.setWidgetResizable(True)
        self.w = QWidget(self)
        self.l = QGridLayout(self.w)
        self.setWidget(self.w)

    def __call__(self, resources):
        self.url_map = {}
        self.labels = []
        for url in resources:
            p = self.url_map[url] = QProgressBar(self.w)
            p.setRange(0, 0)
            self.l.addWidget(p, self.l.rowCount(), 0)
            la = QLabel('\xa0' + url)
            self.labels.append(la)
            self.l.addWidget(la, self.l.rowCount()-1, 1)
        self.l.addWidget(QLabel(''))
        self.l.setRowStretch(self.l.rowCount()-1, 10)

    def progress(self, url, done, total):
        p = self.url_map.get(url)
        if p is not None:
            if total > 0:
                p.setRange(0, total)
                p.setValue(done)
            else:
                p.setRange(0, 0)
Example #9
0
class CollectionsGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(CollectionsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Collections"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('manage_collections'))
        self.setToolTip(
            wrap_msg(
                _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'
                  )))

        self.collections_columns_label = QLabel(_('Collections Columns'))
        self.collections_columns_edit = QLineEdit(self)
        self.collections_columns_edit.setToolTip(
            _('The Kobo from firmware V2.0.0 supports bookshelves.'
              ' These are created on the Kobo. ' +
              'Specify a tags type column for automatic management.'))
        self.collections_columns_edit.setText(
            device.get_pref('collections_columns'))

        self.create_collections_checkbox = create_checkbox(
            _("Create Collections"),
            _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'
              ), device.get_pref('create_collections'))
        self.delete_empty_collections_checkbox = create_checkbox(
            _('Delete Empty Bookshelves'),
            _('Delete any empty bookshelves from the Kobo when syncing is finished. This is only for firmware V2.0.0 or later.'
              ), device.get_pref('delete_empty_collections'))

        self.options_layout.addWidget(self.collections_columns_label, 1, 0, 1,
                                      1)
        self.options_layout.addWidget(self.collections_columns_edit, 1, 1, 1,
                                      1)
        self.options_layout.addWidget(self.create_collections_checkbox, 2, 0,
                                      1, 2)
        self.options_layout.addWidget(self.delete_empty_collections_checkbox,
                                      3, 0, 1, 2)
        self.options_layout.setRowStretch(4, 1)

    @property
    def manage_collections(self):
        return self.isChecked()

    @property
    def collections_columns(self):
        return self.collections_columns_edit.text().strip()

    @property
    def create_collections(self):
        return self.create_collections_checkbox.isChecked()

    @property
    def delete_empty_collections(self):
        return self.delete_empty_collections_checkbox.isChecked()
Example #10
0
class DeviceListGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(DeviceListGroupBox, self).__init__(parent, device)
        self.setTitle(_("Show as on device"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.show_recommendations_checkbox = create_checkbox(
                             _("Show Recommendations"),
                             _('Kobo shows recommendations on the device.  In some cases these have '
                               'files but in other cases they are just pointers to the web site to buy. '
                               'Enable if you wish to see/delete them.'),
                             device.get_pref('show_recommendations')
                             )

        self.show_archived_books_checkbox = create_checkbox(
                             _("Show archived books"),
                             _('Archived books are listed on the device but need to be downloaded to read.'
                               ' Use this option to show these books and match them with books in the calibre library.'),
                             device.get_pref('show_archived_books')
                             )

        self.show_previews_checkbox = create_checkbox(
                             _('Show Previews'),
                             _('Kobo previews are included on the Touch and some other versions'
                               ' by default they are no longer displayed as there is no good reason to '
                               'see them.  Enable if you wish to see/delete them.'),
                             device.get_pref('show_previews')
                             )

        self.options_layout.addWidget(self.show_recommendations_checkbox, 0, 0, 1, 1)
        self.options_layout.addWidget(self.show_archived_books_checkbox,  1, 0, 1, 1)
        self.options_layout.addWidget(self.show_previews_checkbox,        2, 0, 1, 1)
        self.options_layout.setRowStretch(3, 1)

    @property
    def show_recommendations(self):
        return self.show_recommendations_checkbox.isChecked()

    @property
    def show_archived_books(self):
        return self.show_archived_books_checkbox.isChecked()

    @property
    def show_previews(self):
        return self.show_previews_checkbox.isChecked()
Example #11
0
class AdvancedGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(AdvancedGroupBox, self).__init__(parent, device,
                                               _("Advanced options"))
        #         self.setTitle(_("Advanced Options"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.support_newer_firmware_checkbox = create_checkbox(
            _("Attempt to support newer firmware"),
            _('Kobo routinely updates the firmware and the '
              'database version. With this option calibre will attempt '
              'to perform full read-write functionality - Here be Dragons!! '
              'Enable only if you are comfortable with restoring your kobo '
              'to factory defaults and testing software. '
              'This driver supports firmware V2.x.x and DBVersion up to ') +
            unicode(device.supported_dbversion),
            device.get_pref('support_newer_firmware'))

        self.debugging_title_checkbox = create_checkbox(
            _("Title to test when debugging"),
            _('Part of title of a book that can be used when doing some tests for debugging. '
              'The test is to see if the string is contained in the title of a book. '
              'The better the match, the less extraneous output.'),
            device.get_pref('debugging_title'))
        self.debugging_title_label = QLabel(_('Title to test when debugging:'))
        self.debugging_title_edit = QLineEdit(self)
        self.debugging_title_edit.setToolTip(
            _('Part of title of a book that can be used when doing some tests for debugging. '
              'The test is to see if the string is contained in the title of a book. '
              'The better the match, the less extraneous output.'))
        self.debugging_title_edit.setText(device.get_pref('debugging_title'))
        self.debugging_title_label.setBuddy(self.debugging_title_edit)

        self.options_layout.addWidget(self.support_newer_firmware_checkbox, 0,
                                      0, 1, 2)
        self.options_layout.addWidget(self.debugging_title_label, 1, 0, 1, 1)
        self.options_layout.addWidget(self.debugging_title_edit, 1, 1, 1, 1)
        self.options_layout.setRowStretch(2, 2)

    @property
    def support_newer_firmware(self):
        return self.support_newer_firmware_checkbox.isChecked()

    @property
    def debugging_title(self):
        return self.debugging_title_edit.text().strip()
Example #12
0
class AdvancedGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(AdvancedGroupBox, self).__init__(parent, device, _("Advanced Options"))
#         self.setTitle(_("Advanced Options"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.support_newer_firmware_checkbox = create_checkbox(
                            _("Attempt to support newer firmware"),
                            _('Kobo routinely updates the firmware and the '
                              'database version.  With this option Calibre will attempt '
                              'to perform full read-write functionality - Here be Dragons!! '
                              'Enable only if you are comfortable with restoring your kobo '
                              'to factory defaults and testing software. '
                              'This driver supports firmware V2.x.x and DBVersion up to ') + unicode(
                                  device.supported_dbversion), device.get_pref('support_newer_firmware')
                             )

        self.debugging_title_checkbox = create_checkbox(
                             _("Title to test when debugging"),
                             _('Part of title of a book that can be used when doing some tests for debugging. '
                               'The test is to see if the string is contained in the title of a book. '
                               'The better the match, the less extraneous output.'),
                             device.get_pref('debugging_title')
                             )
        self.debugging_title_label = QLabel(_('Title to test when debugging:'))
        self.debugging_title_edit = QLineEdit(self)
        self.debugging_title_edit.setToolTip(_('Part of title of a book that can be used when doing some tests for debugging. '
                    'The test is to see if the string is contained in the title of a book. '
                    'The better the match, the less extraneous output.'))
        self.debugging_title_edit.setText(device.get_pref('debugging_title'))
        self.debugging_title_label.setBuddy(self.debugging_title_edit)

        self.options_layout.addWidget(self.support_newer_firmware_checkbox,   0, 0, 1, 2)
        self.options_layout.addWidget(self.debugging_title_label,             1, 0, 1, 1)
        self.options_layout.addWidget(self.debugging_title_edit,              1, 1, 1, 1)
        self.options_layout.setRowStretch(2, 2)

    @property
    def support_newer_firmware(self):
        return self.support_newer_firmware_checkbox.isChecked()

    @property
    def debugging_title(self):
        return self.debugging_title_edit.text().strip()
    def _initUi(self):
        self._paramWidget = DyStockSelectStrategyParamWidget()
        self._paramWidget.set(self._param)

        self._periodsResultWidget = DyStockBackTestingStrategyPeriodsResultWidget(self._strategyCls, self._paramGroupNo, self._param, self._eventEngine, self._dataEngine, self._dataViewer)

        grid = QGridLayout()
        grid.setSpacing(0)

        grid.addWidget(self._paramWidget, 0, 0)
        grid.addWidget(self._periodsResultWidget, 1, 0)
        
        grid.setRowStretch(0, 1)
        grid.setRowStretch(1, 20)

        self.setLayout(grid)
Example #14
0
class DeviceListGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(DeviceListGroupBox, self).__init__(parent, device)
        self.setTitle(_("Show as on device"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.show_recommendations_checkbox = create_checkbox(
            _("Show recommendations"),
            _('Kobo shows recommendations on the device.  In some cases these have '
              'files but in other cases they are just pointers to the web site to buy. '
              'Enable if you wish to see/delete them.'),
            device.get_pref('show_recommendations'))

        self.show_archived_books_checkbox = create_checkbox(
            _("Show archived books"),
            _('Archived books are listed on the device but need to be downloaded to read.'
              ' Use this option to show these books and match them with books in the calibre library.'
              ), device.get_pref('show_archived_books'))

        self.show_previews_checkbox = create_checkbox(
            _('Show previews'),
            _('Kobo previews are included on the Touch and some other versions'
              ' by default they are no longer displayed as there is no good reason to '
              'see them.  Enable if you wish to see/delete them.'),
            device.get_pref('show_previews'))

        self.options_layout.addWidget(self.show_recommendations_checkbox, 0, 0,
                                      1, 1)
        self.options_layout.addWidget(self.show_archived_books_checkbox, 1, 0,
                                      1, 1)
        self.options_layout.addWidget(self.show_previews_checkbox, 2, 0, 1, 1)
        self.options_layout.setRowStretch(3, 1)

    @property
    def show_recommendations(self):
        return self.show_recommendations_checkbox.isChecked()

    @property
    def show_archived_books(self):
        return self.show_archived_books_checkbox.isChecked()

    @property
    def show_previews(self):
        return self.show_previews_checkbox.isChecked()
    def _initUi(self):
        self._paramWidget = DyStockSelectStrategyParamWidget()
        self._paramWidget.set(self._param)

        self._periodsResultWidget = DyStockBackTestingStrategyPeriodsResultWidget(
            self._strategyCls, self._paramGroupNo, self._param,
            self._eventEngine, self._dataEngine, self._dataViewer)

        grid = QGridLayout()
        grid.setSpacing(0)

        grid.addWidget(self._paramWidget, 0, 0)
        grid.addWidget(self._periodsResultWidget, 1, 0)

        grid.setRowStretch(0, 1)
        grid.setRowStretch(1, 20)

        self.setLayout(grid)
Example #16
0
class CoversGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(CoversGroupBox, self).__init__(parent, device)
        self.setTitle(_("Upload covers"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('upload_covers'))
        self.setToolTip(
            wrap_msg(
                _('Upload cover images from the calibre library when sending books to the device.'
                  )))

        self.upload_grayscale_checkbox = create_checkbox(
            _('Upload black and white Covers'),
            _('Convert covers to black and white when uploading'),
            device.get_pref('upload_grayscale'))

        self.keep_cover_aspect_checkbox = create_checkbox(
            _('Keep cover aspect ratio'),
            _('When uploading covers, do not change the aspect ratio when resizing for the device.'
              ' This is for firmware versions 2.3.1 and later.'),
            device.get_pref('keep_cover_aspect'))

        self.options_layout.addWidget(self.keep_cover_aspect_checkbox, 0, 0, 1,
                                      1)
        self.options_layout.addWidget(self.upload_grayscale_checkbox, 1, 0, 1,
                                      1)
        self.options_layout.setRowStretch(2, 1)

    @property
    def upload_covers(self):
        return self.isChecked()

    @property
    def upload_grayscale(self):
        return self.upload_grayscale_checkbox.isChecked()

    @property
    def keep_cover_aspect(self):
        return self.keep_cover_aspect_checkbox.isChecked()
Example #17
0
class CoversGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(CoversGroupBox, self).__init__(parent, device)
        self.setTitle(_("Upload covers"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('upload_covers'))
        self.setToolTip(wrap_msg(_('Upload cover images from the calibre library when sending books to the device.')))

        self.upload_grayscale_checkbox = create_checkbox(
                             _('Upload Black and White Covers'),
                             _('Convert covers to Black and White when uploading'),
                             device.get_pref('upload_grayscale')
                             )

        self.keep_cover_aspect_checkbox = create_checkbox(
                             _('Keep cover aspect ratio'),
                             _('When uploading covers, do not change the aspect ratio when resizing for the device.'
                               ' This is for firmware versions 2.3.1 and later.'),
                             device.get_pref('keep_cover_aspect'))

        self.options_layout.addWidget(self.keep_cover_aspect_checkbox,    0, 0, 1, 1)
        self.options_layout.addWidget(self.upload_grayscale_checkbox,     1, 0, 1, 1)
        self.options_layout.setRowStretch(2, 1)

    @property
    def upload_covers(self):
        return self.isChecked()

    @property
    def upload_grayscale(self):
        return self.upload_grayscale_checkbox.isChecked()

    @property
    def keep_cover_aspect(self):
        return self.keep_cover_aspect_checkbox.isChecked()
Example #18
0
class BookUploadsGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(BookUploadsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Book uploading"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.modify_css_checkbox = create_checkbox(
                _("Modify CSS"),
                _('This allows addition of user CSS rules and removal of some CSS. '
                'When sending a book, the driver adds the contents of {0} to all stylesheets in the EPUB. '
                'This file is searched for in the root directory of the main memory of the device. '
                'As well as this, if the file contains settings for the "orphans" or "widows", '
                'these are removed for all styles in the original stylesheet.').format(device.KOBO_EXTRA_CSSFILE),
                device.get_pref('modify_css')
                )
        self.override_kobo_replace_existing_checkbox = create_checkbox(
                _("Do not treat replacements as new books"),
                _('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. '
                'Even if the book is a replacement for an existing book, the Kobo will remove the book from the database and then treat it as a new book. '
                'This means that the reading status, bookmarks and collections for the book will be lost. '
                'This option overrides firmware behavior and attempts to prevent a book that has been resent from being treated as a new book. '
                'If you prefer to have replacements treated as new books, turn this option off.'
                ),
                device.get_pref('override_kobo_replace_existing')
                )

        self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
        self.options_layout.addWidget(self.override_kobo_replace_existing_checkbox, 1, 0, 1, 2)
        self.options_layout.setRowStretch(2, 1)

    @property
    def modify_css(self):
        return self.modify_css_checkbox.isChecked()

    @property
    def override_kobo_replace_existing(self):
        return self.override_kobo_replace_existing_checkbox.isChecked()
Example #19
0
class BookUploadsGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(BookUploadsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Book uploading"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.modify_css_checkbox = create_checkbox(
            _("Modify CSS"),
            _('This allows addition of user CSS rules and removal of some CSS. '
              'When sending a book, the driver adds the contents of {0} to all stylesheets in the EPUB. '
              'This file is searched for in the root directory of the main memory of the device. '
              'As well as this, if the file contains settings for the "orphans" or "widows", '
              'these are removed for all styles in the original stylesheet.').
            format(device.KOBO_EXTRA_CSSFILE), device.get_pref('modify_css'))
        self.override_kobo_replace_existing_checkbox = create_checkbox(
            _("Do not treat replacements as new books"),
            _('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. '
              'Even if the book is a replacement for an existing book, the Kobo will remove the book from the database and then treat it as a new book. '
              'This means that the reading status, bookmarks and collections for the book will be lost. '
              'This option overrides firmware behavior and attempts to prevent a book that has been resent from being treated as a new book. '
              'If you prefer to have replacements treated as new books, turn this option off.'
              ), device.get_pref('override_kobo_replace_existing'))

        self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
        self.options_layout.addWidget(
            self.override_kobo_replace_existing_checkbox, 1, 0, 1, 2)
        self.options_layout.setRowStretch(2, 1)

    @property
    def modify_css(self):
        return self.modify_css_checkbox.isChecked()

    @property
    def override_kobo_replace_existing(self):
        return self.override_kobo_replace_existing_checkbox.isChecked()
Example #20
0
class BookUploadsGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(BookUploadsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Book uploading"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.modify_css_checkbox = create_checkbox(
            _("Modify CSS"),
            _('This allows addition of user CSS rules and removal of some CSS. '
              'When sending a book, the driver adds the contents of {0} to all stylesheets in the EPUB. '
              'This file is searched for in the root directory of the main memory of the device. '
              'As well as this, if the file contains settings for the "orphans" or "widows", '
              'these are removed for all styles in the original stylesheet.').
            format(device.KOBO_EXTRA_CSSFILE), device.get_pref('modify_css'))

        self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
        self.options_layout.setRowStretch(1, 1)

    @property
    def modify_css(self):
        return self.modify_css_checkbox.isChecked()
Example #21
0
class ExtendedGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(ExtendedGroupBox, self).__init__(parent, device,
                                               _("Extended driver"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.extra_features_checkbox = create_checkbox(
            _('Enable Extended Kobo Features'),
            _('Choose whether to enable extra customizations'),
            device.get_pref('extra_features'))

        self.upload_encumbered_checkbox = create_checkbox(
            _('Upload DRM-encumbered ePub files'),
            _('Select this to upload ePub files encumbered by DRM. If this is '
              'not selected, it is a fatal error to upload an encumbered file'),
            device.get_pref('upload_encumbered'))

        self.skip_failed_checkbox = create_checkbox(
            _('Silently Ignore Failed Conversions'),
            _('Select this to not upload any book that fails conversion to '
              'kepub. If this is not selected, the upload process will be '
              'stopped at the first book that fails. If this is selected, '
              'failed books will be silently removed from the upload queue.'),
            device.get_pref('skip_failed'))

        self.hyphenate_checkbox = create_checkbox(
            _('Hyphenate Files'),
            _('Select this to add a CSS file which enables hyphenation. The '
              'language used will be the language defined for the book in '
              'calibre. Please see the README file for directions on updating '
              'hyphenation dictionaries.'), device.get_pref('hyphenate'))

        self.replace_lang_checkbox = create_checkbox(
            _('Replace Content Language Code'),
            _('Select this to replace the defined language in each content '
              'file inside the ePub.'), device.get_pref('replace_lang'))

        self.smarten_punctuation_checkbox = create_checkbox(
            _('Smarten Punctuation'),
            _('Select this to smarten punctuation in the ePub'),
            device.get_pref('smarten_punctuation'))

        self.clean_markup_checkbox = create_checkbox(
            _('Clean up ePub Markup'),
            _('Select this to clean up the internal ePub markup.'),
            device.get_pref('clean_markup'))

        self.file_copy_dir_checkbox = create_checkbox(
            _('Copy generated KePub files to a directory'),
            _('Enter an absolute directory path to copy all generated KePub '
              'files into for debugging purposes.'),
            device.get_pref('file_copy_dir'))
        self.file_copy_dir_label = QLabel(_(
            'Copy generated KePub files to a directory'))
        self.file_copy_dir_edit = QLineEdit(self)
        self.file_copy_dir_edit.setToolTip(
            _('Enter an absolute directory path to copy all generated KePub '
              'files into for debugging purposes.'))
        self.file_copy_dir_edit.setText(device.get_pref('file_copy_dir'))
        self.file_copy_dir_label.setBuddy(self.file_copy_dir_edit)

        self.full_page_numbers_checkbox = create_checkbox(
            _('Use full book page numbers'),
            _('Select this to show page numbers for the whole book, instead of '
              'each chapter. This will also affect regular ePub page number '
              'display!'), device.get_pref('full_page_numbers'))

        self.disable_hyphenation_checkbox = create_checkbox(
            _('Disable hyphenation'),
            _('Select this to disable hyphenation for books.'),
            device.get_pref('disable_hyphenation'))

        self.options_layout.addWidget(self.extra_features_checkbox, 0, 0, 1, 1)
        self.options_layout.addWidget(self.upload_encumbered_checkbox, 0, 1, 1,
                                      1)
        self.options_layout.addWidget(self.skip_failed_checkbox, 1, 0, 1, 1)
        self.options_layout.addWidget(self.hyphenate_checkbox, 1, 1, 1, 1)
        self.options_layout.addWidget(self.replace_lang_checkbox, 2, 0, 1, 1)
        self.options_layout.addWidget(self.smarten_punctuation_checkbox, 2, 1,
                                      1, 1)
        self.options_layout.addWidget(self.clean_markup_checkbox, 3, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_label, 4, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_edit, 4, 1, 1, 1)
        self.options_layout.addWidget(self.full_page_numbers_checkbox, 5, 0, 1,
                                      1)
        self.options_layout.addWidget(self.disable_hyphenation_checkbox, 5, 1,
                                      1, 1)
        self.options_layout.setRowStretch(6, 2)

    @property
    def extra_features(self):
        return self.extra_features_checkbox.isChecked()

    @property
    def upload_encumbered(self):
        return self.upload_encumbered_checkbox.isChecked()

    @property
    def skip_failed(self):
        return self.skip_failed_checkbox.isChecked()

    @property
    def hyphenate(self):
        return self.hyphenate_checkbox.isChecked()

    @property
    def replace_lang(self):
        return self.replace_lang_checkbox.isChecked()

    @property
    def smarten_punctuation(self):
        return self.smarten_punctuation_checkbox.isChecked()

    @property
    def clean_markup(self):
        return self.clean_markup_checkbox.isChecked()

    @property
    def full_page_numbers(self):
        return self.full_page_numbers_checkbox.isChecked()

    @property
    def disable_hyphenation(self):
        return self.disable_hyphenation_checkbox.isChecked()

    @property
    def file_copy_dir(self):
        return self.file_copy_dir_edit.text().strip()
Example #22
0
class PrincePDFDialog(QDialog):
    prince_log = ''

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

        self.setAttribute(Qt.WA_DeleteOnClose)

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

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

        self.image = QLabel()
        self.image.setPixmap(icon.pixmap(120, 120))
        self.l.addWidget(self.image, 1, 1, 4, 1, Qt.AlignVCenter)

        self.convert_to_PDF_button = QPushButton(_('Convert to &PDF'), self)
        self.convert_to_PDF_button.clicked.connect(self.convert_to_PDF)
        self.convert_to_PDF_button.setDefault(True)
        self.convert_to_PDF_button.setToolTip(
            _('<qt>Start the conversion process</qt>'))
        self.l.addWidget(self.convert_to_PDF_button, 1, 2, Qt.AlignVCenter)

        self.view_log = QPushButton(_('&View log'), self)
        self.view_log.clicked.connect(self.show_log)
        self.view_log.setToolTip(
            _('<qt>Display the log from the last Prince run</qt>'))
        self.l.addWidget(self.view_log, 2, 2, Qt.AlignVCenter)
        self.view_log.hide()

        self.conf_button = QPushButton(_('Con&figure'), self)
        self.conf_button.clicked.connect(self.config)
        self.conf_button.setToolTip(_('<qt>Configure this plugin</qt>'))
        self.l.addWidget(self.conf_button, 4, 2, Qt.AlignVCenter)

        self.info = QLabel()
        self.l.addWidget(self.info, 5, 1, 1, -1)

        self.suggestion = QLabel()
        self.suggestion.setAlignment(Qt.AlignCenter)
        self.l.addWidget(self.suggestion, 6, 1, 1, -1)

        self.l.setColumnStretch(1, 1)
        self.l.setColumnStretch(2, 10)
        self.l.setRowStretch(1, 1)
        self.l.setRowStretch(2, 1)
        self.l.setRowStretch(3, 10)
        self.l.setRowStretch(4, 1)
        self.l.setRowStretch(5, 1)
        self.l.setRowStretch(6, 1)
        self.l.setRowMinimumHeight(1, 1)
        self.l.setRowMinimumHeight(2, 1)
        self.l.setRowMinimumHeight(3, 1)
        self.l.setRowMinimumHeight(4, 1)
        self.l.setRowMinimumHeight(5, 1)
        self.l.setRowMinimumHeight(6, 1)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Close
                                        | QDialogButtonBox.Help)
        self.l.addWidget(self.buttons, 7, 1, 1, -1)
        self.buttons.rejected.connect(self.reject)
        self.buttons.helpRequested.connect(self.about)

        self.adjustSize()

        # Update the info now and every time the selection or the data changes
        self.gui.library_view.model().dataChanged.connect(self.update_info)
        self.gui.library_view.selectionModel().selectionChanged.connect(
            self.update_info)
        self.update_info()

    def update_info(self):
        '''
        Update the info on top of the window
        '''

        self.db = self.gui.current_db
        # Get selected rows
        rows = self.gui.library_view.selectionModel().selectedRows()
        if not rows or len(rows) == 0:
            self.info.setText(_('<b>No books selected</b>'))
            self.info.setAlignment(Qt.AlignCenter)
            self.suggestion.setText(_('Select one single book'))
            self.selected = None
            self.convert_to_PDF_button.setEnabled(False)
        elif len(rows) > 1:
            self.info.setText(_('<b>Many books selected</b>'))
            self.info.setAlignment(Qt.AlignCenter)
            self.suggestion.setText(_('Select one single book'))
            self.selected = None
            self.convert_to_PDF_button.setEnabled(False)
        else:
            # If there is only one selected book, enable conversion
            # and show list of available formats (formats in prefs are bold)
            book_id = self.gui.library_view.model().id(rows[0])
            fmts = self.db.formats(book_id, index_is_id=True)
            if (fmts):
                fmts = fmts.split(',')
            else:
                fmts = [_('<i>none</i>')]
            available = False
            for i, fmt in enumerate(fmts):
                fmts[i] = fmt.lower()
                if fmts[i] in prefs['formats']:
                    fmts[i] = '<b>%s</b>' % fmts[i]
                    available = True
            self.info.setText(_('Available formats: %s') % ', '.join(fmts))
            self.info.setAlignment(Qt.AlignLeft)
            # Conversion enabled only if some "preferred" format is found
            if (available):
                self.suggestion.setText(_('Ready'))
                self.selected = book_id
                self.convert_to_PDF_button.setEnabled(True)
            else:
                self.suggestion.setText(_('No preferred format available'))
                self.selected = None
                self.convert_to_PDF_button.setEnabled(False)

    def about(self):
        '''
        Display a short help message
        '''
        from os.path import join
        from calibre.ptempfile import TemporaryDirectory
        from calibre.gui2.dialogs.message_box import MessageBox
        from calibre_plugins.prince_pdf.help import help_txt, license_txt
        from calibre_plugins.prince_pdf import PrincePDFPlugin
        from calibre_plugins.prince_pdf import __license__

        author = PrincePDFPlugin.author
        version = "%i.%i.%i" % PrincePDFPlugin.version
        license = __license__
        with TemporaryDirectory('xxx') as tdir:
            for x in ('prince_icon.png', 'small_icon.png'):
                with open(join(tdir, x), 'w') as f:
                    f.write(get_resources('images/' + x))
            help_box = MessageBox(type_ = MessageBox.INFO, \
                                  title = _('About the Prince PDF Plugin'), \
                                  msg = help_txt % {'author':author, 'version':version, 'license':license, 'dir':tdir, 'code':'style="font-family:monospace ; font-weight:bold"'}, \
                                  det_msg = 'Copyright \u00a9 %s\n%s' % (__copyright__, license_txt), \
                                  q_icon = self.icon, \
                                  show_copy_button = False)
            #help_box.gridLayout.addWidget(help_box.icon_widget,0,0,Qt.AlignTop)
            help_box.gridLayout.setAlignment(help_box.icon_widget, Qt.AlignTop)
            help_box.exec_()

    def convert_to_PDF(self):
        '''
        Unpack and convert the currently selected book to PDF
        '''
        from calibre.gui2 import error_dialog
        from calibre.constants import DEBUG

        # Get available formats
        book_id = self.selected
        fmts = self.db.formats(book_id, index_is_id=True)
        fmts = fmts.lower().split(',')
        # Process only the first format matching the 'formats' configuration option
        for fmt in prefs['formats']:
            fmt = fmt.lower()
            if (not fmt in fmts): continue
            mi = self.db.get_metadata(book_id,
                                      index_is_id=True,
                                      get_cover=False)
            pdf_base_file = self.get_filename(book_id, mi)

            # This is the actual code:
            if DEBUG: print('===========')
            # Unpack the book and call the conversion dialog
            (opf, oeb) = self.unpack(book_id, fmt)
            if (opf == None or oeb == None):
                return error_dialog(self.gui,
                                    _('Cannot convert to PDF'),
                                    _('Format not supported: %s') % fmt,
                                    show=True)
            convert_dialog = ConvertDialog(mi, fmt, opf, oeb, self.icon)
            convert_dialog.pdf_file = pdf_base_file
            pdf_file = ''
            if (convert_dialog.exec_()):
                pdf_file = convert_dialog.pdf_file
            self.prince_log = convert_dialog.prince_log
            # After the dialog returns, pdf_file has the output file path,
            # and prince_log has the Prince console output
            if DEBUG: print(_('PDF file: %s') % pdf_file)
            # If there is any log, enable the View log button
            if (self.prince_log):
                self.view_log.show()
                log_msg = _(' Check the log.')
            else:
                self.view_log.hide()
                log_msg = ''
            # If the conversion failed, pdf_file will be None,
            if (pdf_file == None):
                error_dialog(self.gui,
                             _('Could not convert to PDF'),
                             _('The conversion failed.') + log_msg,
                             show=True)
            # If the user cancelled the dialog, pdf_file will be ''
            if (pdf_file):
                # Set the metadata in the PDF and add it or save it
                try:
                    self.set_pdf_metadata(mi, pdf_file)
                except:
                    error_dialog(
                        self.gui,
                        _('Could not convert to PDF'),
                        _("Error reading or writing the PDF file:\n%s" %
                          pdf_file),
                        show=True)
                    return
                if (prefs['add_book']):
                    self.add_pdf(book_id, pdf_file, ('pdf' in fmts))
                else:
                    self.save_pdf(pdf_file, pdf_base_file)
            if DEBUG: print('===========')
            return
        # No matching format in the book
        return error_dialog(self.gui,
                            _('Cannot convert to PDF'),
                            _('No supported format available'),
                            show=True)

    def show_log(self):
        '''
        Display the Prince log dialog
        '''
        msg = LogDialog(self.prince_log, self.icon)
        msg.exec_()

    def config(self):
        '''
        Display the configuration dialog
        '''
        self.do_user_config(parent=self)

    def get_filename(self, book_id, mi):
        '''
        Obtain a filename from the save_to_disk template
        :param book_id: The book identifier
        :param mi: The book metadata
        '''
        from os.path import join
        from calibre.library.save_to_disk import get_components, config
        from calibre import sanitize_file_name_unicode
        from calibre.utils.filenames import ascii_filename

        opts = config().parse()
        components = get_components(
            opts.template,
            mi,
            book_id,
            opts.timefmt,
            sanitize_func=(ascii_filename
                           if opts.asciiize else sanitize_file_name_unicode),
            to_lowercase=opts.to_lowercase,
            replace_whitespace=opts.replace_whitespace)
        base_path = join(*components)
        return '%s.pdf' % base_path

    def unpack(self, book_id, fmt):
        '''
        Unpack the book in a temporary directory
        :param book_id: The book identifier
        :param fmt: The format to unpack
        '''
        from calibre.constants import DEBUG
        from calibre.ptempfile import PersistentTemporaryDirectory
        from calibre.ebooks.tweak import get_tools
        from calibre.ebooks.oeb.base import OEBBook
        from calibre.ebooks.oeb.reader import OEBReader
        from calibre.utils.logging import default_log
        from calibre_plugins.prince_pdf.dummy_preprocessor import dummy_preprocessor

        book_file = self.db.format(book_id,
                                   fmt,
                                   index_is_id=True,
                                   as_path=True)
        if DEBUG: print(_('Unpacking book...'))
        tdir = PersistentTemporaryDirectory('_unpack')
        exploder = get_tools(fmt)[0]
        if (exploder == None): return (None, None)
        opf = exploder(book_file, tdir)
        html_preprocessor = dummy_preprocessor()
        css_preprocessor = dummy_preprocessor()
        oeb = OEBBook(default_log, html_preprocessor, css_preprocessor)
        OEBReader()(oeb, opf)
        return (opf, oeb)

    def set_pdf_metadata(self, mi, pdf_file):
        '''
        Set the metadata in the PDF file
        :param mi: The book metadata
        :param pdf_file: The path to the PDF file
        '''
        from calibre.constants import DEBUG
        from calibre.ebooks.metadata.pdf import set_metadata

        if DEBUG: print(_('Setting metadata...'))
        pdf_stream = open(pdf_file, 'r+b')
        set_metadata(pdf_stream, mi)
        pdf_stream.close()

    def add_pdf(self, book_id, pdf_file, exists):
        '''
        Add the PDF file to the book record, asking for replacement
        :param book_id: The book identifier
        :param pdf_file: The path to the PDF file
        :param exists: True if there is already a PDF in the book
        '''
        from calibre.constants import DEBUG
        from calibre.gui2.dialogs.message_box import MessageBox

        add_it = True
        if (exists):
            msg = MessageBox(
                MessageBox.QUESTION, _('Existing format'),
                _('The selected book already contains a PDF format. Are you sure you want to replace it?'
                  ),
                _("The temporary file can be found in:\n%s") % pdf_file)
            msg.toggle_det_msg()
            add_it = (msg.exec_())
        if (add_it):
            if DEBUG: print(_('Adding PDF...'))
            self.db.new_api.add_format(book_id, 'pdf', pdf_file)
            self.gui.library_view.model().refresh_ids([book_id])
            self.gui.library_view.refresh_book_details()
            self.gui.tags_view.recount()

    def save_pdf(self, pdf_file, pdf_base_file):
        '''
        Save the PDF file in the final location
        :param pdf_file: The path to the PDF file
        :param pdf_base_file: The desired file name and relative path
        '''
        from os import makedirs
        from os.path import basename, dirname, join, exists
        from shutil import move
        from calibre.constants import DEBUG
        from calibre.gui2 import choose_dir
        from calibre.gui2.dialogs.message_box import MessageBox
        from calibre.gui2 import error_dialog

        path = choose_dir(self.gui, 'save to disk dialog',
                          _('Choose destination directory'))
        if not path:
            return
        save_file = join(path, pdf_base_file)
        base_dir = dirname(save_file)
        try:
            makedirs(base_dir)
        except BaseException:
            if not exists(base_dir): raise
        try:
            move(pdf_file, save_file)
        except:
            error_dialog(self.gui,
                         _('Could not save PDF'),
                         _("Error writing the PDF file:\n%s" % save_file),
                         show=True)
            return
        if DEBUG: print(save_file)
        MessageBox(MessageBox.INFO, _('File saved'),
                   _("PDF file saved in:\n%s") % save_file).exec_()
class ExtendedGroupBox(DeviceOptionsGroupBox):
    """The options group for KoboTouchExtended."""

    def __init__(self, parent, device):
        """Set up driver config options group."""
        super(ExtendedGroupBox, self).__init__(
            parent, device, _("Extended driver")  # noqa: F821
        )

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.extra_features_checkbox = create_checkbox(
            _("Enable Extended Kobo Features"),  # noqa: F821
            _("Choose whether to enable extra customizations"),  # noqa: F821
            device.get_pref("extra_features"),
        )

        self.upload_encumbered_checkbox = create_checkbox(
            _("Upload DRM-encumbered ePub files"),  # noqa: F821
            _(  # noqa: F821
                "Select this to upload ePub files encumbered by DRM. If this "
                "is not selected, it is a fatal error to upload an encumbered "
                "file"
            ),
            device.get_pref("upload_encumbered"),
        )

        self.skip_failed_checkbox = create_checkbox(
            _("Silently Ignore Failed Conversions"),  # noqa: F821
            _(  # noqa: F821
                "Select this to not upload any book that fails conversion to "
                "kepub. If this is not selected, the upload process will be "
                "stopped at the first book that fails. If this is selected, "
                "failed books will be silently removed from the upload queue."
            ),
            device.get_pref("skip_failed"),
        )

        self.hyphenate_checkbox = create_checkbox(
            _("Hyphenate Files"),  # noqa: F821
            _(  # noqa: F821
                "Select this to add a CSS file which enables hyphenation. The "
                "language used will be the language defined for the book in "
                "calibre. Please see the README file for directions on "
                "updating hyphenation dictionaries."
            ),
            device.get_pref("hyphenate"),
        )

        self.smarten_punctuation_checkbox = create_checkbox(
            _("Smarten Punctuation"),  # noqa: F821
            _("Select this to smarten punctuation in the ePub"),  # noqa: F821
            device.get_pref("smarten_punctuation"),
        )

        self.clean_markup_checkbox = create_checkbox(
            _("Clean up ePub Markup"),  # noqa: F821
            _("Select this to clean up the internal ePub markup."),  # noqa: F821
            device.get_pref("clean_markup"),
        )

        self.file_copy_dir_checkbox = create_checkbox(
            _("Copy generated KePub files to a directory"),  # noqa: F821
            _(  # noqa: F821
                "Enter an absolute directory path to copy all generated KePub "
                "files into for debugging purposes."
            ),
            device.get_pref("file_copy_dir"),
        )
        self.file_copy_dir_label = QLabel(
            _("Copy generated KePub files to a directory")  # noqa: F821
        )
        self.file_copy_dir_edit = QLineEdit(self)
        self.file_copy_dir_edit.setToolTip(
            _(  # noqa: F821
                "Enter an absolute directory path to copy all generated KePub "
                "files into for debugging purposes."
            )
        )
        self.file_copy_dir_edit.setText(device.get_pref("file_copy_dir"))
        self.file_copy_dir_label.setBuddy(self.file_copy_dir_edit)

        self.full_page_numbers_checkbox = create_checkbox(
            _("Use full book page numbers"),  # noqa: F821
            _(  # noqa: F821
                "Select this to show page numbers for the whole book, instead "
                "of each chapter. This will also affect regular ePub page "
                "number display!"
            ),
            device.get_pref("full_page_numbers"),
        )

        self.disable_hyphenation_checkbox = create_checkbox(
            _("Disable hyphenation"),  # noqa: F821
            _("Select this to disable hyphenation for books."),  # noqa: F821
            device.get_pref("disable_hyphenation"),
        )

        self.options_layout.addWidget(self.extra_features_checkbox, 0, 0, 1, 1)
        self.options_layout.addWidget(self.upload_encumbered_checkbox, 0, 1, 1, 1)
        self.options_layout.addWidget(self.skip_failed_checkbox, 1, 0, 1, 1)
        self.options_layout.addWidget(self.hyphenate_checkbox, 1, 1, 1, 1)
        self.options_layout.addWidget(self.smarten_punctuation_checkbox, 2, 1, 1, 1)
        self.options_layout.addWidget(self.clean_markup_checkbox, 3, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_label, 4, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_edit, 4, 1, 1, 1)
        self.options_layout.addWidget(self.full_page_numbers_checkbox, 5, 0, 1, 1)
        self.options_layout.addWidget(self.disable_hyphenation_checkbox, 5, 1, 1, 1)
        self.options_layout.setRowStretch(6, 2)

    @property
    def extra_features(self):
        """Determine if Kobo extra features are enabled."""
        return self.extra_features_checkbox.isChecked()

    @property
    def upload_encumbered(self):
        """Determine if DRM-encumbered files will be uploaded."""
        return self.upload_encumbered_checkbox.isChecked()

    @property
    def skip_failed(self):
        """Determine if failed conversions will be skipped."""
        return self.skip_failed_checkbox.isChecked()

    @property
    def hyphenate(self):
        """Determine if hyphenation should be enabled."""
        return self.hyphenate_checkbox.isChecked()

    @property
    def smarten_punctuation(self):
        """Determine if punctuation should be converted to smart punctuation."""
        return self.smarten_punctuation_checkbox.isChecked()

    @property
    def clean_markup(self):
        """Determine if additional markup cleanup will be done."""
        return self.clean_markup_checkbox.isChecked()

    @property
    def full_page_numbers(self):
        """Determine if full-book page numbers will be displayed."""
        return self.full_page_numbers_checkbox.isChecked()

    @property
    def disable_hyphenation(self):
        """Determine if hyphenation should be disabled."""
        return self.disable_hyphenation_checkbox.isChecked()

    @property
    def file_copy_dir(self):
        """Determine where to copy converted KePub books to."""
        return self.file_copy_dir_edit.text().strip()
Example #24
0
    def _initUi(self):
        self._statsWidget = DyStockBackTestingStrategyResultStatsWidget(self._dataEngine)
        self._posWidget = DyStockBackTestingStrategyResultPositionWidget(self._dataViewer)
        self._dealsWidget = DyStockBackTestingStrategyResultDealsWidget(self._eventEngine, str(self._period), self._strategyCls)
        self._subInfoWidget = DySubInfoWidget(self._eventEngine, self._paramGroupNo, self._period) # 由于线程并行问题,可能会丢掉开始的一些信息

        dealsLabel = QLabel('成交明细')
        posLabel = QLabel('当前持仓')
        statsLabel = QLabel('账户信息')

        grid = QGridLayout()
        grid.setSpacing(0)

        grid.addWidget(statsLabel, 0, 0)
        grid.addWidget(self._statsWidget, 1, 0)
        grid.addWidget(posLabel, 2, 0)
        grid.addWidget(self._posWidget, 3, 0)
        grid.addWidget(dealsLabel, 4, 0)
        grid.addWidget(self._dealsWidget, 5, 0)
        grid.addWidget(self._subInfoWidget, 6, 0)
        
        grid.setRowStretch(0, 1)
        grid.setRowStretch(1, 4)
        grid.setRowStretch(2, 1)
        grid.setRowStretch(3, 25)
        grid.setRowStretch(4, 1)
        grid.setRowStretch(5, 30)
        grid.setRowStretch(6, 1)

        self.setLayout(grid)

        # 成交明细右键菜单
        self._dealsNewWindows = []
        dealsLabel.setContextMenuPolicy(Qt.CustomContextMenu)
        dealsLabel.customContextMenuRequested.connect(self._showDealsContextMenu)

        self._dealsMenu = QMenu(self) 
        
        action = QAction('新窗口', self)
        action.triggered.connect(self._newDealsWindow)
        self._dealsMenu.addAction(action)
class ExtendedGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(ExtendedGroupBox, self).__init__(parent, device,
                                               _("Extended driver"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.extra_features_checkbox = create_checkbox(
            _('Enable Extended Kobo Features'),
            _('Choose whether to enable extra customizations'),
            device.get_pref('extra_features'))

        self.upload_encumbered_checkbox = create_checkbox(
            _('Upload DRM-encumbered ePub files'),
            _('Select this to upload ePub files encumbered by DRM. If this is '
              'not selected, it is a fatal error to upload an encumbered file'
              ), device.get_pref('upload_encumbered'))

        self.skip_failed_checkbox = create_checkbox(
            _('Silently Ignore Failed Conversions'),
            _('Select this to not upload any book that fails conversion to '
              'kepub. If this is not selected, the upload process will be '
              'stopped at the first book that fails. If this is selected, '
              'failed books will be silently removed from the upload queue.'),
            device.get_pref('skip_failed'))

        self.hyphenate_checkbox = create_checkbox(
            _('Hyphenate Files'),
            _('Select this to add a CSS file which enables hyphenation. The '
              'language used will be the language defined for the book in '
              'calibre. Please see the README file for directions on updating '
              'hyphenation dictionaries.'), device.get_pref('hyphenate'))

        self.replace_lang_checkbox = create_checkbox(
            _('Replace Content Language Code'),
            _('Select this to replace the defined language in each content '
              'file inside the ePub.'), device.get_pref('replace_lang'))

        self.smarten_punctuation_checkbox = create_checkbox(
            _('Smarten Punctuation'),
            _('Select this to smarten punctuation in the ePub'),
            device.get_pref('smarten_punctuation'))

        self.clean_markup_checkbox = create_checkbox(
            _('Clean up ePub Markup'),
            _('Select this to clean up the internal ePub markup.'),
            device.get_pref('clean_markup'))

        self.file_copy_dir_checkbox = create_checkbox(
            _('Copy generated KePub files to a directory'),
            _('Enter an absolute directory path to copy all generated KePub '
              'files into for debugging purposes.'),
            device.get_pref('file_copy_dir'))
        self.file_copy_dir_label = QLabel(
            _('Copy generated KePub files to a directory'))
        self.file_copy_dir_edit = QLineEdit(self)
        self.file_copy_dir_edit.setToolTip(
            _('Enter an absolute directory path to copy all generated KePub '
              'files into for debugging purposes.'))
        self.file_copy_dir_edit.setText(device.get_pref('file_copy_dir'))
        self.file_copy_dir_label.setBuddy(self.file_copy_dir_edit)

        self.full_page_numbers_checkbox = create_checkbox(
            _('Use full book page numbers'),
            _('Select this to show page numbers for the whole book, instead of '
              'each chapter. This will also affect regular ePub page number '
              'display!'), device.get_pref('full_page_numbers'))

        self.disable_hyphenation_checkbox = create_checkbox(
            _('Disable hyphenation'),
            _('Select this to disable hyphenation for books.'),
            device.get_pref('disable_hyphenation'))

        self.options_layout.addWidget(self.extra_features_checkbox, 0, 0, 1, 1)
        self.options_layout.addWidget(self.upload_encumbered_checkbox, 0, 1, 1,
                                      1)
        self.options_layout.addWidget(self.skip_failed_checkbox, 1, 0, 1, 1)
        self.options_layout.addWidget(self.hyphenate_checkbox, 1, 1, 1, 1)
        self.options_layout.addWidget(self.replace_lang_checkbox, 2, 0, 1, 1)
        self.options_layout.addWidget(self.smarten_punctuation_checkbox, 2, 1,
                                      1, 1)
        self.options_layout.addWidget(self.clean_markup_checkbox, 3, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_label, 4, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_edit, 4, 1, 1, 1)
        self.options_layout.addWidget(self.full_page_numbers_checkbox, 5, 0, 1,
                                      1)
        self.options_layout.addWidget(self.disable_hyphenation_checkbox, 5, 1,
                                      1, 1)
        self.options_layout.setRowStretch(6, 2)

    @property
    def extra_features(self):
        return self.extra_features_checkbox.isChecked()

    @property
    def upload_encumbered(self):
        return self.upload_encumbered_checkbox.isChecked()

    @property
    def skip_failed(self):
        return self.skip_failed_checkbox.isChecked()

    @property
    def hyphenate(self):
        return self.hyphenate_checkbox.isChecked()

    @property
    def replace_lang(self):
        return self.replace_lang_checkbox.isChecked()

    @property
    def smarten_punctuation(self):
        return self.smarten_punctuation_checkbox.isChecked()

    @property
    def clean_markup(self):
        return self.clean_markup_checkbox.isChecked()

    @property
    def full_page_numbers(self):
        return self.full_page_numbers_checkbox.isChecked()

    @property
    def disable_hyphenation(self):
        return self.disable_hyphenation_checkbox.isChecked()

    @property
    def file_copy_dir(self):
        return self.file_copy_dir_edit.text().strip()
    def __init__(self, gui, existing_names, editing=None):
        QDialog.__init__(self, gui)

        self.gui = gui
        self.existing_names = existing_names

        if editing:
            self.setWindowTitle(_('Edit virtual library'))
        else:
            self.setWindowTitle(_('Create virtual library'))
        self.setWindowIcon(QIcon(I('lt.png')))

        gl = QGridLayout()
        self.setLayout(gl)
        self.la1 = la1 = QLabel(_('Virtual library &name:'))
        gl.addWidget(la1, 0, 0)
        self.vl_name = QComboBox()
        self.vl_name.setEditable(True)
        self.vl_name.lineEdit().setMaxLength(MAX_VIRTUAL_LIBRARY_NAME_LENGTH)
        la1.setBuddy(self.vl_name)
        gl.addWidget(self.vl_name, 0, 1)
        self.editing = editing

        self.saved_searches_label = sl = QTextBrowser(self)
        sl.viewport().setAutoFillBackground(False)
        gl.addWidget(sl, 2, 0, 1, 2)

        self.la2 = la2 = QLabel(_('&Search expression:'))
        gl.addWidget(la2, 1, 0)
        self.vl_text = QLineEdit()
        self.vl_text.textChanged.connect(self.search_text_changed)
        la2.setBuddy(self.vl_text)
        gl.addWidget(self.vl_text, 1, 1)
        self.vl_text.setText(_build_full_search_string(self.gui))

        self.sl = sl = QLabel(
            '<p>' + _('Create a virtual library based on: ') +
            ('<a href="author.{0}">{0}</a>, '
             '<a href="tag.{1}">{1}</a>, '
             '<a href="publisher.{2}">{2}</a>, '
             '<a href="series.{3}">{3}</a>, '
             '<a href="search.{4}">{4}</a>.').format(_('Authors'), _(
                 'Tags'), _('Publishers'), _('Series'), _('Saved searches')))
        sl.setWordWrap(True)
        sl.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        sl.linkActivated.connect(self.link_activated)
        gl.addWidget(sl, 3, 0, 1, 2)
        gl.setRowStretch(3, 10)

        self.hl = hl = QLabel(
            _('''
            <h2>Virtual libraries</h2>

            <p>Using <i>virtual libraries</i> you can restrict calibre to only show
            you books that match a search. When a virtual library is in effect, calibre
            behaves as though the library contains only the matched books. The Tag browser
            display only the tags/authors/series/etc. that belong to the matched books and any searches
            you do will only search within the books in the virtual library. This
            is a good way to partition your large library into smaller and easier to work with subsets.</p>

            <p>For example you can use a Virtual library to only show you books with the Tag <i>"Unread"</i>
            or only books by <i>"My favorite author"</i> or only books in a particular series.</p>

            <p>More information and examples are available in the
            <a href="%s">User Manual</a>.</p>
            ''') % localize_user_manual_link(
                'https://manual.calibre-ebook.com/virtual_libraries.html'))
        hl.setWordWrap(True)
        hl.setOpenExternalLinks(True)
        hl.setFrameStyle(hl.StyledPanel)
        gl.addWidget(hl, 0, 3, 4, 1)

        bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        gl.addWidget(bb, 4, 0, 1, 0)

        if editing:
            db = self.gui.current_db
            virt_libs = db.prefs.get('virtual_libraries', {})
            for dex, vl in enumerate(sorted(virt_libs.keys(), key=sort_key)):
                self.vl_name.addItem(vl, virt_libs.get(vl, ''))
                if vl == editing:
                    self.vl_name.setCurrentIndex(dex)
                    self.original_index = dex
            self.original_search = virt_libs.get(editing, '')
            self.vl_text.setText(self.original_search)
            self.new_name = editing
            self.vl_name.currentIndexChanged[int].connect(
                self.name_index_changed)
            self.vl_name.lineEdit().textEdited.connect(self.name_text_edited)

        self.resize(self.sizeHint() + QSize(150, 25))
Example #27
0
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current = {'title': "[EMPTY]", 'address': ""}

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier)
                    and (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit,
             partial(enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(navigate_completion,
                                                 Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
        ])
Example #28
0
class LLT_ConjAdd(QMainWindow):
    def __init__(self):
        super(LLT_ConjAdd, self).__init__()
        self.w = QWidget()
        self.setCentralWidget(self.w)

        #construct GUI
        self.setWindowTitle("Verb Conjugations")
        self.setGeometry(0, 0, 900, 600)

        self.conjDicList = []
        self.wordList = []
        self.newDic = {'INF': '', 'IND': '', 'SUB': '', 'IMP': ''}

        self.headingLab = QLabel("Add New Conjugation Table")
        self.wordInfLab = QLabel("Infinitive")
        self.wordInfLab.setAlignment(Qt.AlignRight)
        self.infEntry = QLineEdit()

        #INDICATIVE FORM TABLE
        self.indLab = QLabel("Indicative")
        self.indYoLab = QLabel("Yo")
        self.indYoLab.setAlignment(Qt.AlignRight)
        self.indTuLab = QLabel("Tú")
        self.indTuLab.setAlignment(Qt.AlignRight)
        self.indUstLab = QLabel("Él/la, Ud")
        self.indUstLab.setAlignment(Qt.AlignRight)
        self.indNosLab = QLabel("Nosotros")
        self.indNosLab.setAlignment(Qt.AlignRight)
        self.indUstdsLab = QLabel("Ellos/as, Uds")
        self.indUstdsLab.setAlignment(Qt.AlignRight)

        self.indPresLab = QLabel("Present")
        self.indPretLab = QLabel("Preterite")
        self.indImpLab = QLabel("Imperfect")
        self.indFutLab = QLabel("Future")
        self.indCondLab = QLabel("Conditional")

        self.entryGridInd = QGridLayout()
        for i in range(5):
            for j in range(5):
                self.entry = QLineEdit()
                self.entryGridInd.addWidget(self.entry, i, j)

        #SUBJUNCTIVE FORM TABLE
        self.subLab = QLabel("Subjunctive")
        self.subYoLab = QLabel("Yo")
        self.subYoLab.setAlignment(Qt.AlignRight)
        self.subTuLab = QLabel("Tú")
        self.subTuLab.setAlignment(Qt.AlignRight)
        self.subUstLab = QLabel("Él/la, Ud")
        self.subUstLab.setAlignment(Qt.AlignRight)
        self.subNosLab = QLabel("Nosotros/as")
        self.subNosLab.setAlignment(Qt.AlignRight)
        self.subUstdsLab = QLabel("Ellos/as, Uds")
        self.subUstdsLab.setAlignment(Qt.AlignRight)

        self.subPresLab = QLabel("Present")
        self.subImpLab = QLabel("Imperfect")
        self.subFutLab = QLabel("Future")

        self.entryGridSub = QGridLayout()
        for i in range(5):
            for j in range(3):
                self.entry = QLineEdit()
                self.entryGridSub.addWidget(self.entry, i, j)

        #IMPERATIVE FORM TABLE
        self.impvLab = QLabel("Imperative")
        self.impvTu = QLabel("Tú")
        self.impvTu.setAlignment(Qt.AlignRight)
        self.impvUd = QLabel("Usted")
        self.impvUd.setAlignment(Qt.AlignRight)
        self.impvNos = QLabel("Nosotros/as")
        self.impvNos.setAlignment(Qt.AlignRight)
        self.impvUdes = QLabel("Ustedes")
        self.impvUdes.setAlignment(Qt.AlignRight)

        self.impvAffLab = QLabel("Affirmative")
        self.impvNegLab = QLabel("Negative")

        self.entryGridImpv = QGridLayout()
        for i in range(4):
            for j in range(2):
                self.entry = QLineEdit()
                self.entryGridImpv.addWidget(self.entry, i, j)
        self.checkBut = QPushButton("Check")
        self.checkBut.clicked.connect(self.check)
        self.saveBut = QPushButton("Save")
        self.saveBut.clicked.connect(self.save)
        self.newBut = QPushButton("New Word")
        self.newBut.clicked.connect(self.new)
        self.clearBut = QPushButton("Clear")
        self.clearBut.clicked.connect(self.clear)
        self.quitBut = QPushButton("Quit")
        self.quitBut.clicked.connect(self.quit)

        self.theGrid = QGridLayout()

        self.theGrid.addWidget(self.headingLab, 0, 0)
        self.theGrid.addWidget(self.wordInfLab, 1, 0)
        self.theGrid.addWidget(self.infEntry, 1, 1)

        self.theGrid.addWidget(self.indLab, 3, 0)
        self.theGrid.addWidget(self.indPresLab, 3, 1)
        self.theGrid.addWidget(self.indPretLab, 3, 2)
        self.theGrid.addWidget(self.indImpLab, 3, 3)
        self.theGrid.addWidget(self.indFutLab, 3, 4)
        self.theGrid.addWidget(self.indCondLab, 3, 5)
        self.theGrid.addWidget(self.indYoLab, 4, 0)
        self.theGrid.addWidget(self.indTuLab, 5, 0)
        self.theGrid.addWidget(self.indUstLab, 6, 0)
        self.theGrid.addWidget(self.indNosLab, 7, 0)
        self.theGrid.addWidget(self.indUstdsLab, 8, 0)
        self.theGrid.addLayout(self.entryGridInd, 4, 1, 5, 5)

        self.theGrid.addWidget(self.subLab, 11, 0)
        self.theGrid.addWidget(self.subPresLab, 11, 1)
        self.theGrid.addWidget(self.subImpLab, 11, 2)
        self.theGrid.addWidget(self.subFutLab, 11, 3)
        self.theGrid.addWidget(self.subYoLab, 12, 0)
        self.theGrid.addWidget(self.subTuLab, 13, 0)
        self.theGrid.addWidget(self.subUstLab, 14, 0)
        self.theGrid.addWidget(self.subNosLab, 15, 0)
        self.theGrid.addWidget(self.subUstdsLab, 16, 0)
        self.theGrid.addLayout(self.entryGridSub, 12, 1, 5, 3)

        self.theGrid.addWidget(self.impvLab, 19, 0)
        self.theGrid.addWidget(self.impvAffLab, 19, 1)
        self.theGrid.addWidget(self.impvNegLab, 19, 2)
        self.theGrid.addWidget(self.impvTu, 20, 0)
        self.theGrid.addWidget(self.impvUd, 21, 0)
        self.theGrid.addWidget(self.impvNos, 22, 0)
        self.theGrid.addWidget(self.impvUdes, 23, 0)
        self.theGrid.addLayout(self.entryGridImpv, 20, 1, 4, 2)

        self.theGrid.addWidget(self.checkBut, 19, 5)
        self.theGrid.addWidget(self.saveBut, 20, 5)
        self.theGrid.addWidget(self.clearBut, 21, 5)
        self.theGrid.addWidget(self.newBut, 22, 5)
        self.theGrid.addWidget(self.quitBut, 23, 5)

        for i in range(24):
            self.theGrid.setRowStretch(i, 1)
        for j in range(6):
            self.theGrid.setColumnStretch(j, 1)
        self.w.setLayout(self.theGrid)
        self.getDic()

    def check(self):
        word = self.infEntry.text().upper()
        if word in self.wordList:
            msgBox = QMessageBox()
            msgBox.setText(word + ' already in dictionary')
            msgBox.exec_()
        else:
            msgBox = QMessageBox()
            msgBox.setText(word + ' not in dictionary yet')
            msgBox.exec_()

    def save(self):
        infinitive = self.infEntry.text().upper()
        if infinitive in self.wordList:
            msgBox = QMessageBox()
            msgBox.setText(infinitive + ' already in dictionary')
            msgBox.exec_()
        else:
            self.wordList.append(infinitive)
            indList = []
            subList = []
            impList = []
            for i in range(self.entryGridInd.count()):
                item = self.entryGridInd.itemAt(i)
                child = item.widget()
                indList.append(child.text().upper())

            for i in range(self.entryGridSub.count()):
                item = self.entryGridSub.itemAt(i)
                child = item.widget()
                subList.append(child.text().upper())

            for i in range(self.entryGridImpv.count()):
                item = self.entryGridImpv.itemAt(i)
                child = item.widget()
                impList.append(child.text().upper())

                self.newDic['INF'] = infinitive
                self.newDic['IND'] = indList
                self.newDic['SUB'] = subList
                self.newDic['IMP'] = impList

            self.conjDicList.append(self.newDic)
            c = open('conj.txt', 'w')
            json.dump(self.conjDicList, c)
            c.close()
            msgBox = QMessageBox()
            msgBox.setText(infinitive + ' has been saved')
            msgBox.exec_()
            self.newDic = {'INF': '', 'IND': '', 'SUB': '', 'IMP': ''}

    def new(self):
        confirm = QMessageBox.question(
            self.w, 'New Word',
            'Are you sure you want to clear all entries \nand start a new word?',
            QMessageBox.Yes | QMessageBox.No)
        if confirm == QMessageBox.Yes:
            self.infEntry.clear()
            for i in range(self.entryGridInd.count()):
                item = self.entryGridInd.itemAt(i)
                child = item.widget()
                child.clear()
            for i in range(self.entryGridSub.count()):
                item = self.entryGridSub.itemAt(i)
                child = item.widget()
                child.clear()
            for i in range(self.entryGridImpv.count()):
                item = self.entryGridImpv.itemAt(i)
                child = item.widget()
                child.clear()
        else:
            pass

    def clear(self):
        confirm = QMessageBox.question(
            self.w, 'Clear', 'Are you sure you want to clear all entries?',
            QMessageBox.Yes | QMessageBox.No)
        if confirm == QMessageBox.Yes:
            self.infEntry.clear()
            for i in range(self.entryGridInd.count()):
                item = self.entryGridInd.itemAt(i)
                child = item.widget()
                child.clear()
            for i in range(self.entryGridSub.count()):
                item = self.entryGridSub.itemAt(i)
                child = item.widget()
                child.clear()
            for i in range(self.entryGridImpv.count()):
                item = self.entryGridImpv.itemAt(i)
                child = item.widget()
                child.clear()
        else:
            pass

    def quit(self):
        confirm = QMessageBox.question(self.w, 'Quit',
                                       'Are you sure you want to exit?',
                                       QMessageBox.Yes | QMessageBox.No)
        if confirm == QMessageBox.Yes:
            self.close()
        else:
            pass

    def getDic(self):
        try:
            c = open('conj.txt', 'r')
            self.conjDicList = json.load(c)
            c.close()
            for item in self.conjDicList:
                self.wordList.append(item['INF'])

        except:
            self.conjDicList = []
Example #29
0
class ExtraCustomization(DeviceConfigTab):  # {{{

    def __init__(self, extra_customization_message, extra_customization_choices, device_settings):
        super(ExtraCustomization, self).__init__()

        debug_print("ExtraCustomization.__init__ - extra_customization_message=", extra_customization_message)
        debug_print("ExtraCustomization.__init__ - extra_customization_choices=", extra_customization_choices)
        debug_print("ExtraCustomization.__init__ - device_settings.extra_customization=", device_settings.extra_customization)
        debug_print("ExtraCustomization.__init__ - device_settings=", device_settings)
        self.extra_customization_message = extra_customization_message

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

        options_group = QGroupBox(_("Extra driver customization options"), self)
        self.l.addWidget(options_group)
        self.extra_layout = QGridLayout()
        self.extra_layout.setObjectName("extra_layout")
        options_group.setLayout(self.extra_layout)

        if extra_customization_message:
            extra_customization_choices = extra_customization_choices or {}

            def parse_msg(m):
                msg, _, tt = m.partition(':::') if m else ('', '', '')
                return msg.strip(), textwrap.fill(tt.strip(), 100)

            if isinstance(extra_customization_message, list):
                self.opt_extra_customization = []
                if len(extra_customization_message) > 6:
                    row_func = lambda x, y: ((x/2) * 2) + y
                    col_func = lambda x: x%2
                else:
                    row_func = lambda x, y: x*2 + y
                    col_func = lambda x: 0

                for i, m in enumerate(extra_customization_message):
                    label_text, tt = parse_msg(m)
                    if not label_text:
                        self.opt_extra_customization.append(None)
                        continue
                    if isinstance(device_settings.extra_customization[i], bool):
                        self.opt_extra_customization.append(QCheckBox(label_text))
                        self.opt_extra_customization[-1].setToolTip(tt)
                        self.opt_extra_customization[i].setChecked(bool(device_settings.extra_customization[i]))
                    elif i in extra_customization_choices:
                        cb = QComboBox(self)
                        self.opt_extra_customization.append(cb)
                        l = QLabel(label_text)
                        l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy(cb), cb.setToolTip(tt)
                        for li in sorted(extra_customization_choices[i]):
                            self.opt_extra_customization[i].addItem(li)
                        cb.setCurrentIndex(max(0, cb.findText(device_settings.extra_customization[i])))
                    else:
                        self.opt_extra_customization.append(QLineEdit(self))
                        l = QLabel(label_text)
                        l.setToolTip(tt)
                        self.opt_extra_customization[i].setToolTip(tt)
                        l.setBuddy(self.opt_extra_customization[i])
                        l.setWordWrap(True)
                        self.opt_extra_customization[i].setText(device_settings.extra_customization[i])
                        self.opt_extra_customization[i].setCursorPosition(0)
                        self.extra_layout.addWidget(l, row_func(i + 2, 0), col_func(i))
                    self.extra_layout.addWidget(self.opt_extra_customization[i],
                                                row_func(i + 2, 1), col_func(i))
                spacerItem1 = QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
                self.extra_layout.addItem(spacerItem1, row_func(i + 2 + 2, 1), 0, 1, 2)
                self.extra_layout.setRowStretch(row_func(i + 2 + 2, 1), 2)
            else:
                self.opt_extra_customization = QLineEdit()
                label_text, tt = parse_msg(extra_customization_message)
                l = QLabel(label_text)
                l.setToolTip(tt)
                l.setBuddy(self.opt_extra_customization)
                l.setWordWrap(True)
                if device_settings.extra_customization:
                    self.opt_extra_customization.setText(device_settings.extra_customization)
                    self.opt_extra_customization.setCursorPosition(0)
                self.opt_extra_customization.setCursorPosition(0)
                self.extra_layout.addWidget(l, 0, 0)
                self.extra_layout.addWidget(self.opt_extra_customization, 1, 0)

    def extra_customization(self):
        ec = []
        if self.extra_customization_message:
            if isinstance(self.extra_customization_message, list):
                for i in range(0, len(self.extra_customization_message)):
                    if self.opt_extra_customization[i] is None:
                        ec.append(None)
                        continue
                    if hasattr(self.opt_extra_customization[i], 'isChecked'):
                        ec.append(self.opt_extra_customization[i].isChecked())
                    elif hasattr(self.opt_extra_customization[i], 'currentText'):
                        ec.append(unicode_type(self.opt_extra_customization[i].currentText()).strip())
                    else:
                        ec.append(unicode_type(self.opt_extra_customization[i].text()).strip())
            else:
                ec = unicode_type(self.opt_extra_customization.text()).strip()
                if not ec:
                    ec = None

        return ec

    @property
    def has_extra_customizations(self):
        debug_print("ExtraCustomization::has_extra_customizations - self.extra_customization_message", self.extra_customization_message)
        return self.extra_customization_message and len(self.extra_customization_message) > 0
Example #30
0
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current = {
            'title': "[EMPTY]",
            'address': ""
        }

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier) and
                    (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(
                    link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit, partial(
                enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(
                navigate_completion, Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
            ])
Example #31
0
class ExtendedGroupBox(DeviceOptionsGroupBox):
    """The options group for KoboTouchExtended."""
    def __init__(self, parent, device):
        """Set up driver config options group."""
        super(ExtendedGroupBox, self).__init__(
            parent,
            device,
            _("Extended driver")  # noqa: F821
        )

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.extra_features_checkbox = create_checkbox(
            _("Enable Extended Kobo Features"),  # noqa: F821
            _("Choose whether to enable extra customizations"),  # noqa: F821
            device.get_pref("extra_features"),
        )

        self.upload_encumbered_checkbox = create_checkbox(
            _("Upload DRM-encumbered ePub files"),  # noqa: F821
            _(  # noqa: F821
                "Select this to upload ePub files encumbered by DRM. If this "
                "is not selected, it is a fatal error to upload an encumbered "
                "file"),
            device.get_pref("upload_encumbered"),
        )

        self.skip_failed_checkbox = create_checkbox(
            _("Silently Ignore Failed Conversions"),  # noqa: F821
            _(  # noqa: F821
                "Select this to not upload any book that fails conversion to "
                "kepub. If this is not selected, the upload process will be "
                "stopped at the first book that fails. If this is selected, "
                "failed books will be silently removed from the upload queue."
            ),
            device.get_pref("skip_failed"),
        )

        self.hyphenate_checkbox = create_checkbox(
            _("Hyphenate Files"),  # noqa: F821
            _(  # noqa: F821
                "Select this to add a CSS file which enables hyphenation. The "
                "language used will be the language defined for the book in "
                "calibre. Please see the README file for directions on "
                "updating hyphenation dictionaries."),
            device.get_pref("hyphenate"),
        )

        self.smarten_punctuation_checkbox = create_checkbox(
            _("Smarten Punctuation"),  # noqa: F821
            _("Select this to smarten punctuation in the ePub"),  # noqa: F821
            device.get_pref("smarten_punctuation"),
        )

        self.clean_markup_checkbox = create_checkbox(
            _("Clean up ePub Markup"),  # noqa: F821
            _("Select this to clean up the internal ePub markup."
              ),  # noqa: F821
            device.get_pref("clean_markup"),
        )

        self.file_copy_dir_checkbox = create_checkbox(
            _("Copy generated KePub files to a directory"),  # noqa: F821
            _(  # noqa: F821
                "Enter an absolute directory path to copy all generated KePub "
                "files into for debugging purposes."),
            device.get_pref("file_copy_dir"),
        )
        self.file_copy_dir_label = QLabel(
            _("Copy generated KePub files to a directory")  # noqa: F821
        )
        self.file_copy_dir_edit = QLineEdit(self)
        self.file_copy_dir_edit.setToolTip(
            _(  # noqa: F821
                "Enter an absolute directory path to copy all generated KePub "
                "files into for debugging purposes."))
        self.file_copy_dir_edit.setText(device.get_pref("file_copy_dir"))
        self.file_copy_dir_label.setBuddy(self.file_copy_dir_edit)

        self.full_page_numbers_checkbox = create_checkbox(
            _("Use full book page numbers"),  # noqa: F821
            _(  # noqa: F821
                "Select this to show page numbers for the whole book, instead "
                "of each chapter. This will also affect regular ePub page "
                "number display!"),
            device.get_pref("full_page_numbers"),
        )

        self.disable_hyphenation_checkbox = create_checkbox(
            _("Disable hyphenation"),  # noqa: F821
            _("Select this to disable hyphenation for books."),  # noqa: F821
            device.get_pref("disable_hyphenation"),
        )

        self.opt_kepub_hyphenate_chars_label = QLabel(
            _("Minimum word length to hyphenate") + ":"  # noqa: F821
        )

        self.opt_kepub_hyphenate_chars = QSpinBox(self)
        self.opt_kepub_hyphenate_chars_label.setBuddy(
            self.opt_kepub_hyphenate_chars)
        self.opt_kepub_hyphenate_chars.setObjectName(
            "opt_kepub_hyphenate_chars")
        self.opt_kepub_hyphenate_chars.setSpecialValueText(
            _("Disabled"))  # noqa: F821
        self.opt_kepub_hyphenate_chars.valueChanged.connect(
            functools.partial(
                common.intValueChanged,
                self.opt_kepub_hyphenate_chars,
                _("character"),  # noqa: F821
                _("characters"),  # noqa: F821
            ))
        self.opt_kepub_hyphenate_chars.setValue(
            device.get_pref("hyphenate_chars"))

        self.opt_kepub_hyphenate_chars_before_label = QLabel(
            _("Minimum characters before hyphens") + ":"  # noqa: F821
        )

        self.opt_kepub_hyphenate_chars_before = QSpinBox(self)
        self.opt_kepub_hyphenate_chars_before_label.setBuddy(
            self.opt_kepub_hyphenate_chars_before)
        self.opt_kepub_hyphenate_chars_before.setObjectName(
            "opt_kepub_hyphenate_chars_before")
        self.opt_kepub_hyphenate_chars_before.valueChanged.connect(
            functools.partial(
                common.intValueChanged,
                self.opt_kepub_hyphenate_chars_before,
                _("character"),  # noqa: F821
                _("characters"),  # noqa: F821
            ))
        self.opt_kepub_hyphenate_chars_before.setMinimum(2)
        self.opt_kepub_hyphenate_chars_before.setValue(
            device.get_pref("hyphenate_chars_before"))

        self.opt_kepub_hyphenate_chars_after_label = QLabel(
            _("Minimum characters after hyphens") + ":"  # noqa: F821
        )

        self.opt_kepub_hyphenate_chars_after = QSpinBox(self)
        self.opt_kepub_hyphenate_chars_after_label.setBuddy(
            self.opt_kepub_hyphenate_chars_after)
        self.opt_kepub_hyphenate_chars_after.setObjectName(
            "opt_kepub_hyphenate_chars_after")
        self.opt_kepub_hyphenate_chars_after.valueChanged.connect(
            functools.partial(
                common.intValueChanged,
                self.opt_kepub_hyphenate_chars_after,
                _("character"),  # noqa: F821
                _("characters"),  # noqa: F821
            ))
        self.opt_kepub_hyphenate_chars_after.setMinimum(2)
        self.opt_kepub_hyphenate_chars_after.setValue(
            device.get_pref("hyphenate_chars_after"))

        self.opt_kepub_hyphenate_limit_lines_label = QLabel(
            _("Maximum consecutive hyphenated lines") + ":"  # noqa: F821
        )

        self.opt_kepub_hyphenate_limit_lines = QSpinBox(self)
        self.opt_kepub_hyphenate_limit_lines_label.setBuddy(
            self.opt_kepub_hyphenate_limit_lines)
        self.opt_kepub_hyphenate_limit_lines.setObjectName(
            "opt_kepub_hyphenate_limit_lines")
        self.opt_kepub_hyphenate_limit_lines.setSpecialValueText(
            _("Disabled")  # noqa: F821
        )
        self.opt_kepub_hyphenate_limit_lines.valueChanged.connect(
            functools.partial(
                common.intValueChanged,
                self.opt_kepub_hyphenate_limit_lines,
                _("line"),  # noqa: F821
                _("lines"),  # noqa: F821
            ))
        self.opt_kepub_hyphenate_limit_lines.setValue(
            device.get_pref("hyphenate_limit_lines"))

        self.options_layout.addWidget(self.extra_features_checkbox, 0, 0, 1, 1)
        self.options_layout.addWidget(self.upload_encumbered_checkbox, 0, 1, 1,
                                      1)
        self.options_layout.addWidget(self.skip_failed_checkbox, 1, 0, 1, 1)
        self.options_layout.addWidget(self.hyphenate_checkbox, 1, 1, 1, 1)
        self.options_layout.addWidget(self.smarten_punctuation_checkbox, 2, 1,
                                      1, 1)
        self.options_layout.addWidget(self.clean_markup_checkbox, 3, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_label, 4, 0, 1, 1)
        self.options_layout.addWidget(self.file_copy_dir_edit, 4, 1, 1, 1)
        self.options_layout.addWidget(self.full_page_numbers_checkbox, 5, 0, 1,
                                      1)
        self.options_layout.addWidget(self.disable_hyphenation_checkbox, 5, 1,
                                      1, 1)
        self.options_layout.addWidget(self.opt_kepub_hyphenate_chars_label, 6,
                                      0, 1, 1)
        self.options_layout.addWidget(self.opt_kepub_hyphenate_chars, 6, 1, 1,
                                      1)
        self.options_layout.addWidget(
            self.opt_kepub_hyphenate_chars_before_label, 7, 0, 1, 1)
        self.options_layout.addWidget(self.opt_kepub_hyphenate_chars_before, 7,
                                      1, 1, 1)
        self.options_layout.addWidget(
            self.opt_kepub_hyphenate_chars_after_label, 8, 0, 1, 1)
        self.options_layout.addWidget(self.opt_kepub_hyphenate_chars_after, 8,
                                      1, 1, 1)
        self.options_layout.addWidget(
            self.opt_kepub_hyphenate_limit_lines_label, 9, 0, 1, 1)
        self.options_layout.addWidget(self.opt_kepub_hyphenate_limit_lines, 9,
                                      1, 1, 1)
        self.options_layout.setRowStretch(10, 2)

    @property
    def extra_features(self):
        """Determine if Kobo extra features are enabled."""
        return self.extra_features_checkbox.isChecked()

    @property
    def upload_encumbered(self):
        """Determine if DRM-encumbered files will be uploaded."""
        return self.upload_encumbered_checkbox.isChecked()

    @property
    def skip_failed(self):
        """Determine if failed conversions will be skipped."""
        return self.skip_failed_checkbox.isChecked()

    @property
    def hyphenate(self):
        """Determine if hyphenation should be enabled."""
        return self.hyphenate_checkbox.isChecked()

    @property
    def smarten_punctuation(self):
        """Determine if punctuation should be converted to smart punctuation."""
        return self.smarten_punctuation_checkbox.isChecked()

    @property
    def clean_markup(self):
        """Determine if additional markup cleanup will be done."""
        return self.clean_markup_checkbox.isChecked()

    @property
    def full_page_numbers(self):
        """Determine if full-book page numbers will be displayed."""
        return self.full_page_numbers_checkbox.isChecked()

    @property
    def disable_hyphenation(self):
        """Determine if hyphenation should be disabled."""
        return self.disable_hyphenation_checkbox.isChecked()

    @property
    def file_copy_dir(self):
        """Determine where to copy converted KePub books to."""
        return self.file_copy_dir_edit.text().strip()

    @property
    def hyphenate_chars(self):
        return self.opt_kepub_hyphenate_chars.value()

    @property
    def hyphenate_chars_before(self):
        return self.opt_kepub_hyphenate_chars_before.value()

    @property
    def hyphenate_chars_after(self):
        return self.opt_kepub_hyphenate_chars_after.value()

    @property
    def hyphenate_limit_lines(self):
        return self.opt_kepub_hyphenate_limit_lines.value()
Example #32
0
class CollectionsGroupBox(DeviceOptionsGroupBox):

    def __init__(self, parent, device):
        super(CollectionsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Collections"))

        self.options_layout = QGridLayout()
        self.options_layout.setObjectName("options_layout")
        self.setLayout(self.options_layout)

        self.setCheckable(True)
        self.setChecked(device.get_pref('manage_collections'))
        self.setToolTip(wrap_msg(_('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.')))

        self.collections_columns_label = QLabel(_('Collections Columns:'))
        self.collections_columns_edit = QLineEdit(self)
        self.collections_columns_edit.setToolTip(_('The Kobo from firmware V2.0.0 supports bookshelves.'
                ' These are created on the Kobo. ' +
                'Specify a tags type column for automatic management.'))
        self.collections_columns_edit.setText(device.get_pref('collections_columns'))

        self.create_collections_checkbox = create_checkbox(
                         _("Create Collections"),
                         _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'),
                         device.get_pref('create_collections')
                         )
        self.delete_empty_collections_checkbox = create_checkbox(
                         _('Delete Empty Bookshelves'),
                         _('Delete any empty bookshelves from the Kobo when syncing is finished. This is only for firmware V2.0.0 or later.'),
                         device.get_pref('delete_empty_collections')
                         )

        self.ignore_collections_names_label = QLabel(_('Ignore Collections:'))
        self.ignore_collections_names_edit = QLineEdit(self)
        self.ignore_collections_names_edit.setToolTip(_('List the names of collections to be ignored by ' +
                'the collection management. The collections listed ' +
                'will not be changed. Names are separated by commas.'))
        self.ignore_collections_names_edit.setText(device.get_pref('ignore_collections_names'))

        self.options_layout.addWidget(self.collections_columns_label,         1, 0, 1, 1)
        self.options_layout.addWidget(self.collections_columns_edit,          1, 1, 1, 1)
        self.options_layout.addWidget(self.create_collections_checkbox,       2, 0, 1, 2)
        self.options_layout.addWidget(self.delete_empty_collections_checkbox, 3, 0, 1, 2)
        self.options_layout.addWidget(self.ignore_collections_names_label,    4, 0, 1, 1)
        self.options_layout.addWidget(self.ignore_collections_names_edit,     4, 1, 1, 1)
        self.options_layout.setRowStretch(4, 1)

    @property
    def manage_collections(self):
        return self.isChecked()

    @property
    def collections_columns(self):
        return self.collections_columns_edit.text().strip()

    @property
    def create_collections(self):
        return self.create_collections_checkbox.isChecked()

    @property
    def delete_empty_collections(self):
        return self.delete_empty_collections_checkbox.isChecked()

    @property
    def ignore_collections_names(self):
        return self.ignore_collections_names_edit.text().strip()
Example #33
0
    def __init__(self, gui, existing_names, editing=None):
        QDialog.__init__(self, gui)

        self.gui = gui
        self.existing_names = existing_names

        if editing:
            self.setWindowTitle(_('Edit virtual library'))
        else:
            self.setWindowTitle(_('Create virtual library'))
        self.setWindowIcon(QIcon(I('lt.png')))

        gl = QGridLayout()
        self.setLayout(gl)
        self.la1 = la1 = QLabel(_('Virtual library &name:'))
        gl.addWidget(la1, 0, 0)
        self.vl_name = QComboBox()
        self.vl_name.setEditable(True)
        self.vl_name.lineEdit().setMaxLength(MAX_VIRTUAL_LIBRARY_NAME_LENGTH)
        la1.setBuddy(self.vl_name)
        gl.addWidget(self.vl_name, 0, 1)
        self.editing = editing

        self.saved_searches_label = QLabel('')
        self.saved_searches_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        gl.addWidget(self.saved_searches_label, 2, 0, 1, 2)

        self.la2 = la2 = QLabel(_('&Search expression:'))
        gl.addWidget(la2, 1, 0)
        self.vl_text = QLineEdit()
        self.vl_text.textChanged.connect(self.search_text_changed)
        la2.setBuddy(self.vl_text)
        gl.addWidget(self.vl_text, 1, 1)
        self.vl_text.setText(_build_full_search_string(self.gui))

        self.sl = sl = QLabel('<p>'+_('Create a virtual library based on: ')+
            ('<a href="author.{0}">{0}</a>, '
            '<a href="tag.{1}">{1}</a>, '
            '<a href="publisher.{2}">{2}</a>, '
            '<a href="series.{3}">{3}</a>, '
            '<a href="search.{4}">{4}</a>.').format(_('Authors'), _('Tags'),
                                            _('Publishers'), _('Series'), _('Saved Searches')))
        sl.setWordWrap(True)
        sl.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        sl.linkActivated.connect(self.link_activated)
        gl.addWidget(sl, 3, 0, 1, 2)
        gl.setRowStretch(3,10)

        self.hl = hl = QLabel(_('''
            <h2>Virtual Libraries</h2>

            <p>Using <i>virtual libraries</i> you can restrict calibre to only show
            you books that match a search. When a virtual library is in effect, calibre
            behaves as though the library contains only the matched books. The Tag Browser
            display only the tags/authors/series/etc. that belong to the matched books and any searches
            you do will only search within the books in the virtual library. This
            is a good way to partition your large library into smaller and easier to work with subsets.</p>

            <p>For example you can use a Virtual Library to only show you books with the Tag <i>"Unread"</i>
            or only books by <i>"My Favorite Author"</i> or only books in a particular series.</p>

            <p>More information and examples are available in the
            <a href="%s">User Manual</a>.</p>
            ''') % localize_user_manual_link('http://manual.calibre-ebook.com/virtual_libraries.html'))
        hl.setWordWrap(True)
        hl.setOpenExternalLinks(True)
        hl.setFrameStyle(hl.StyledPanel)
        gl.addWidget(hl, 0, 3, 4, 1)

        bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        gl.addWidget(bb, 4, 0, 1, 0)

        if editing:
            db = self.gui.current_db
            virt_libs = db.prefs.get('virtual_libraries', {})
            for dex,vl in enumerate(sorted(virt_libs.keys(), key=sort_key)):
                self.vl_name.addItem(vl, virt_libs.get(vl, ''))
                if vl == editing:
                    self.vl_name.setCurrentIndex(dex)
                    self.original_index = dex
            self.original_search = virt_libs.get(editing, '')
            self.vl_text.setText(self.original_search)
            self.new_name = editing
            self.vl_name.currentIndexChanged[int].connect(self.name_index_changed)
            self.vl_name.lineEdit().textEdited.connect(self.name_text_edited)

        self.resize(self.sizeHint()+QSize(150, 25))
Example #34
0
class ExtraCustomization(DeviceConfigTab):  # {{{
    def __init__(self, extra_customization_message,
                 extra_customization_choices, device_settings):
        super(ExtraCustomization, self).__init__()

        debug_print(
            "ExtraCustomization.__init__ - extra_customization_message=",
            extra_customization_message)
        debug_print(
            "ExtraCustomization.__init__ - extra_customization_choices=",
            extra_customization_choices)
        debug_print(
            "ExtraCustomization.__init__ - device_settings.extra_customization=",
            device_settings.extra_customization)
        debug_print("ExtraCustomization.__init__ - device_settings=",
                    device_settings)
        self.extra_customization_message = extra_customization_message

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

        options_group = QGroupBox(_("Extra driver customization options"),
                                  self)
        self.l.addWidget(options_group)
        self.extra_layout = QGridLayout()
        self.extra_layout.setObjectName("extra_layout")
        options_group.setLayout(self.extra_layout)

        if extra_customization_message:
            extra_customization_choices = extra_customization_choices or {}

            def parse_msg(m):
                msg, _, tt = m.partition(':::') if m else ('', '', '')
                return msg.strip(), textwrap.fill(tt.strip(), 100)

            if isinstance(extra_customization_message, list):
                self.opt_extra_customization = []
                if len(extra_customization_message) > 6:
                    row_func = lambda x, y: ((x / 2) * 2) + y
                    col_func = lambda x: x % 2
                else:
                    row_func = lambda x, y: x * 2 + y
                    col_func = lambda x: 0

                for i, m in enumerate(extra_customization_message):
                    label_text, tt = parse_msg(m)
                    if not label_text:
                        self.opt_extra_customization.append(None)
                        continue
                    if isinstance(device_settings.extra_customization[i],
                                  bool):
                        self.opt_extra_customization.append(
                            QCheckBox(label_text))
                        self.opt_extra_customization[-1].setToolTip(tt)
                        self.opt_extra_customization[i].setChecked(
                            bool(device_settings.extra_customization[i]))
                    elif i in extra_customization_choices:
                        cb = QComboBox(self)
                        self.opt_extra_customization.append(cb)
                        l = QLabel(label_text)
                        l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy(
                            cb), cb.setToolTip(tt)
                        for li in sorted(extra_customization_choices[i]):
                            self.opt_extra_customization[i].addItem(li)
                        cb.setCurrentIndex(
                            max(
                                0,
                                cb.findText(
                                    device_settings.extra_customization[i])))
                    else:
                        self.opt_extra_customization.append(QLineEdit(self))
                        l = QLabel(label_text)
                        l.setToolTip(tt)
                        self.opt_extra_customization[i].setToolTip(tt)
                        l.setBuddy(self.opt_extra_customization[i])
                        l.setWordWrap(True)
                        self.opt_extra_customization[i].setText(
                            device_settings.extra_customization[i])
                        self.opt_extra_customization[i].setCursorPosition(0)
                        self.extra_layout.addWidget(l, row_func(i + 2, 0),
                                                    col_func(i))
                    self.extra_layout.addWidget(
                        self.opt_extra_customization[i], row_func(i + 2, 1),
                        col_func(i))
                spacerItem1 = QSpacerItem(10, 10, QSizePolicy.Minimum,
                                          QSizePolicy.Expanding)
                self.extra_layout.addItem(spacerItem1, row_func(i + 2 + 2, 1),
                                          0, 1, 2)
                self.extra_layout.setRowStretch(row_func(i + 2 + 2, 1), 2)
            else:
                self.opt_extra_customization = QLineEdit()
                label_text, tt = parse_msg(extra_customization_message)
                l = QLabel(label_text)
                l.setToolTip(tt)
                l.setBuddy(self.opt_extra_customization)
                l.setWordWrap(True)
                if device_settings.extra_customization:
                    self.opt_extra_customization.setText(
                        device_settings.extra_customization)
                    self.opt_extra_customization.setCursorPosition(0)
                self.opt_extra_customization.setCursorPosition(0)
                self.extra_layout.addWidget(l, 0, 0)
                self.extra_layout.addWidget(self.opt_extra_customization, 1, 0)

    def extra_customization(self):
        ec = []
        if self.extra_customization_message:
            if isinstance(self.extra_customization_message, list):
                for i in range(0, len(self.extra_customization_message)):
                    if self.opt_extra_customization[i] is None:
                        ec.append(None)
                        continue
                    if hasattr(self.opt_extra_customization[i], 'isChecked'):
                        ec.append(self.opt_extra_customization[i].isChecked())
                    elif hasattr(self.opt_extra_customization[i],
                                 'currentText'):
                        ec.append(
                            unicode(self.opt_extra_customization[i].
                                    currentText()).strip())
                    else:
                        ec.append(
                            unicode(self.opt_extra_customization[i].text()).
                            strip())
            else:
                ec = unicode(self.opt_extra_customization.text()).strip()
                if not ec:
                    ec = None

        return ec

    @property
    def has_extra_customizations(self):
        debug_print(
            "ExtraCustomization::has_extra_customizations - self.extra_customization_message",
            self.extra_customization_message)
        return self.extra_customization_message and len(
            self.extra_customization_message) > 0