Exemple #1
1
class DaysOfMonth(Base):

    HELP = _('''\
                Download this periodical every month, on the specified days.
                The download will happen as soon after the specified time as
                possible on the specified days of each month. For example,
                if you choose the 1st and the 15th after 9:00 AM, the
                periodical will be downloaded on the 1st and 15th of every
                month, as soon after 9:00 AM as possible.
            ''')

    def __init__(self, parent=None):
        Base.__init__(self, parent)

        self.l1 = QLabel(_('&Days of the month:'))
        self.days = QLineEdit(self)
        self.days.setToolTip(
            _('Comma separated list of days of the month.'
              ' For example: 1, 15'))
        self.l1.setBuddy(self.days)

        self.l2 = QLabel(_('Download &after:'))
        self.time = QTimeEdit(self)
        self.time.setDisplayFormat('hh:mm AP')
        self.l2.setBuddy(self.time)

        self.l.addWidget(self.l1, 0, 0, 1, 1)
        self.l.addWidget(self.days, 0, 1, 1, 1)
        self.l.addWidget(self.l2, 1, 0, 1, 1)
        self.l.addWidget(self.time, 1, 1, 1, 1)

    def initialize(self, typ=None, val=None):
        if val is None:
            val = ((1, ), 6, 0)
        days_of_month, hour, minute = val
        self.days.setText(', '.join(map(str, map(int, days_of_month))))
        self.time.setTime(QTime(hour, minute))

    @property
    def schedule(self):
        parts = [
            x.strip() for x in unicode(self.days.text()).split(',')
            if x.strip()
        ]
        try:
            days_of_month = tuple(map(int, parts))
        except:
            days_of_month = (1, )
        if not days_of_month:
            days_of_month = (1, )
        t = self.time.time()
        hour, minute = t.hour(), t.minute()
        return 'days_of_month', (days_of_month, int(hour), int(minute))
Exemple #2
0
    def setup_ui(self):
        self.splitter = QSplitter(self)
        self.l = l = QVBoxLayout(self)
        l.addWidget(self.splitter)
        l.addWidget(self.bb)
        self.w = w = QGroupBox(_('Theme Metadata'), self)
        self.splitter.addWidget(w)
        l = w.l = QFormLayout(w)
        self.missing_icons_group = mg = QGroupBox(self)
        self.mising_icons = mi = QListWidget(mg)
        mi.setSelectionMode(mi.NoSelection)
        mg.l = QVBoxLayout(mg)
        mg.l.addWidget(mi)
        self.splitter.addWidget(mg)
        self.title = QLineEdit(self)
        l.addRow(_('&Title:'), self.title)
        self.author = QLineEdit(self)
        l.addRow(_('&Author:'), self.author)
        self.version = v = QSpinBox(self)
        v.setMinimum(1), v.setMaximum(1000000)
        l.addRow(_('&Version:'), v)
        self.description = QTextEdit(self)
        l.addRow(self.description)
        self.refresh_button = rb = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
        rb.setIcon(QIcon(I('view-refresh.png')))
        rb.clicked.connect(self.refresh)

        self.apply_report()
    def __init__(self, parent=None,):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"Unique Key Name:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(_(u"<p>Enter an identifying name for this new key.</p>" +
                                u"<p>It should be something that will help you remember " +
                                u"what personal information was used to create it."))
        key_group.addWidget(self.key_ledit)
        key_label = QLabel(_(''), self)
        key_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(key_label)

        name_group = QHBoxLayout()
        data_group_box_layout.addLayout(name_group)
        name_group.addWidget(QLabel(u"B&N/nook account email address:", self))
        self.name_ledit = QLineEdit(u"", self)
        self.name_ledit.setToolTip(_(u"<p>Enter your email address as it appears in your B&N " +
                                u"account.</p>" +
                                u"<p>It will only be used to generate this " +
                                u"key and won\'t be stored anywhere " +
                                u"in calibre or on your computer.</p>" +
                                u"<p>eg: [email protected]</p>"))
        name_group.addWidget(self.name_ledit)
        name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self)
        name_disclaimer_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(name_disclaimer_label)

        ccn_group = QHBoxLayout()
        data_group_box_layout.addLayout(ccn_group)
        ccn_group.addWidget(QLabel(u"B&N/nook account password:"******"", self)
        self.cc_ledit.setToolTip(_(u"<p>Enter the password " +
                                u"for your B&N account.</p>" +
                                u"<p>The password will only be used to generate this " +
                                u"key and won\'t be stored anywhere in " +
                                u"calibre or on your computer."))
        ccn_group.addWidget(self.cc_ledit)
        ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self)
        ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(ccn_disclaimer_label)
        layout.addSpacing(10)

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

        self.resize(self.sizeHint())
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)
                
        self.labelText = QLabel('Set the paths to the different directories.\nDo not use "/" at the end of the path.\nDefaults are:\nPath to Calibre Library directory: $HOME/Calibre Library\nPath to Calibre Cofig directory: $HOME/.config/calibre\nPath to recoll bin directory: /usr/bin')
        
        
        self.l.addWidget(self.labelText)

        self.labelLibrary = QLabel('Path to Calibre Library directory:')
        self.l.addWidget(self.labelLibrary)

        self.pathToLibrarySetting = QLineEdit(self)
        self.pathToLibrarySetting.setText(prefs['pathToLibrary'])
        self.l.addWidget(self.pathToLibrarySetting)
        self.labelLibrary.setBuddy(self.pathToLibrarySetting)
        
        self.labelCofig = QLabel('Path to Calibre Cofig directory:')
        self.l.addWidget(self.labelCofig)        
        
        self.pathToCofigSetting = QLineEdit(self)
        self.pathToCofigSetting.setText(prefs['pathToCofig'])
        self.l.addWidget(self.pathToCofigSetting)
        self.labelCofig.setBuddy(self.pathToCofigSetting)
        
        self.labelRecoll = QLabel('Path to recoll bin directory:')
        self.l.addWidget(self.labelRecoll)        
        
        self.pathToRecollSetting = QLineEdit(self)
        self.pathToRecollSetting.setText(prefs['pathToRecoll'])
        self.l.addWidget(self.pathToRecollSetting)
        self.labelRecoll.setBuddy(self.pathToRecollSetting)
Exemple #5
0
    def setup_ui(self):
        self.l = l = QGridLayout()
        self.setLayout(l)

        self.la = la = QLabel(_(
            'Arrange the files in this book into sub-folders based on their types.'
            ' If you leave a folder blank, the files will be placed in the root.'))
        la.setWordWrap(True)
        l.addWidget(la, 0, 0, 1, -1)

        folders = tprefs['folders_for_types']
        for i, (typ, text) in enumerate(self.TYPE_MAP):
            la = QLabel('&' + text)
            setattr(self, '%s_label' % typ, la)
            le = QLineEdit(self)
            setattr(self, '%s_folder' % typ, le)
            val = folders.get(typ, '')
            if val and not val.endswith('/'):
                val += '/'
            le.setText(val)
            la.setBuddy(le)
            l.addWidget(la, i + 1, 0)
            l.addWidget(le, i + 1, 1)
        self.la2 = la = QLabel(_(
            'Note that this will only arrange files inside the book,'
            ' it will not affect how they are displayed in the Files Browser'))
        la.setWordWrap(True)
        l.addWidget(la, i + 2, 0, 1, -1)
        l.addWidget(self.bb, i + 3, 0, 1, -1)
Exemple #6
0
 def __init__(self, field, is_new, parent, metadata, extra):
     QLineEdit.__init__(self, parent)
     self.is_new = is_new
     self.field = field
     self.metadata = metadata
     if not is_new:
         self.setReadOnly(True)
     self.textChanged.connect(self.changed)
Exemple #7
0
 def __init__(self, parent=None):
     QLineEdit.__init__(self, parent)
     self.setAttribute(Qt.WA_MacShowFocusRect, False)
     self.setStyleSheet('QLineEdit { background: transparent; color: %s; selection-background-color: %s }' % (
         color('status bar foreground', 'palette(window-text)'),
         color('status bar selection', 'palette(window-text)'),
     ))
     self.search_forward = True
     self.textEdited.connect(self.text_edited)
Exemple #8
0
 def __init__(self, *args):
     QLineEdit.__init__(self, *args)
     self.setValidator(QRegExpValidator(QRegExp(r'\d+\.\d+'), self))
     self.setToolTip(textwrap.fill('<p>'+_(
         'Go to a reference. To get reference numbers, use the <i>reference '
         'mode</i>, by clicking the reference mode button in the toolbar.')))
     if hasattr(self, 'setPlaceholderText'):
         self.setPlaceholderText(_('Go to...'))
     self.editingFinished.connect(self.editing_finished)
Exemple #9
0
class MovedDialog(QDialog):  # {{{
    def __init__(self, stats, location, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle(_("No library found"))
        self._l = l = QGridLayout(self)
        self.setLayout(l)
        self.stats, self.location = stats, location

        loc = self.oldloc = location.replace("/", os.sep)
        self.header = QLabel(
            _(
                "No existing calibre library was found at %s. "
                "If the library was moved, select its new location below. "
                "Otherwise calibre will forget this library."
            )
            % loc
        )
        self.header.setWordWrap(True)
        ncols = 2
        l.addWidget(self.header, 0, 0, 1, ncols)
        self.cl = QLabel("<br><b>" + _("New location of this library:"))
        l.addWidget(self.cl, 1, 0, 1, ncols)
        self.loc = QLineEdit(loc, self)
        l.addWidget(self.loc, 2, 0, 1, 1)
        self.cd = QToolButton(self)
        self.cd.setIcon(QIcon(I("document_open.png")))
        self.cd.clicked.connect(self.choose_dir)
        l.addWidget(self.cd, 2, 1, 1, 1)
        self.bb = QDialogButtonBox(QDialogButtonBox.Abort)
        b = self.bb.addButton(_("Library moved"), self.bb.AcceptRole)
        b.setIcon(QIcon(I("ok.png")))
        b = self.bb.addButton(_("Forget library"), self.bb.RejectRole)
        b.setIcon(QIcon(I("edit-clear.png")))
        b.clicked.connect(self.forget_library)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        l.addWidget(self.bb, 3, 0, 1, ncols)
        self.resize(self.sizeHint() + QSize(100, 50))

    def choose_dir(self):
        d = choose_dir(self, "library moved choose new loc", _("New library location"), default_dir=self.oldloc)
        if d is not None:
            self.loc.setText(d)

    def forget_library(self):
        self.stats.remove(self.location)

    def accept(self):
        newloc = unicode(self.loc.text())
        if not db_class().exists_at(newloc):
            error_dialog(self, _("No library found"), _("No existing calibre library found at %s") % newloc, show=True)
            return
        self.stats.rename(self.location, newloc)
        self.newloc = newloc
        QDialog.accept(self)
Exemple #10
0
    def do_user_config(self, parent=None):
        '''
        This method shows a configuration dialog for this plugin. It returns
        True if the user clicks OK, False otherwise. The changes are
        automatically applied.
        '''
        from PyQt5.Qt import (QDialog, QDialogButtonBox, QVBoxLayout,
                QLabel, Qt, QLineEdit, QCheckBox)

        config_dialog = QDialog(parent)
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        v = QVBoxLayout(config_dialog)

        def size_dialog():
            config_dialog.resize(config_dialog.sizeHint())

        button_box.accepted.connect(config_dialog.accept)
        button_box.rejected.connect(config_dialog.reject)
        config_dialog.setWindowTitle(_('Customize') + ' ' + self.name)
        from calibre.customize.ui import (plugin_customization,
                customize_plugin)
        help_text = self.customization_help(gui=True)
        help_text = QLabel(help_text, config_dialog)
        help_text.setWordWrap(True)
        help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse
                | Qt.LinksAccessibleByKeyboard)
        help_text.setOpenExternalLinks(True)
        v.addWidget(help_text)
        bf = QCheckBox(_('Add linked files in breadth first order'))
        bf.setToolTip(_('Normally, when following links in HTML files'
            ' calibre does it depth first, i.e. if file A links to B and '
            ' C, but B links to D, the files are added in the order A, B, D, C. '
            ' With this option, they will instead be added as A, B, C, D'))
        sc = plugin_customization(self)
        if not sc:
            sc = ''
        sc = sc.strip()
        enc = sc.partition('|')[0]
        bfs = sc.partition('|')[-1]
        bf.setChecked(bfs == 'bf')
        sc = QLineEdit(enc, config_dialog)
        v.addWidget(sc)
        v.addWidget(bf)
        v.addWidget(button_box)
        size_dialog()
        config_dialog.exec_()

        if config_dialog.result() == QDialog.Accepted:
            sc = unicode(sc.text()).strip()
            if bf.isChecked():
                sc += '|bf'
            customize_plugin(self, sc)

        return config_dialog.result()
 def __init__(self, parent=None):
     super(PasswordQDialog, self).__init__(parent)
     self.setWindowTitle('User Password')
     self.setWindowFlags(Qt.FramelessWindowHint)
     self.setStyleSheet(settings.css_style)
     self.setWindowIcon(QIcon(settings.get_image('icon')))
     self.setObjectName('dialog')
     self.setFixedSize(300, 300)
     # Fields
     self.pass_edit = QLineEdit()
     self.confirm_edit = QLineEdit()
     self.help_label = QLabel()
Exemple #12
0
def create_filterable_names_list(names, filter_text=None, parent=None, model=NamesModel):
    nl = QListView(parent)
    nl.m = m = model(names, parent=nl)
    m.filtered.connect(lambda all_items: nl.scrollTo(m.index(0)))
    nl.setModel(m)
    if model is NamesModel:
        nl.d = NamesDelegate(nl)
        nl.setItemDelegate(nl.d)
    f = QLineEdit(parent)
    f.setPlaceholderText(filter_text or '')
    f.textEdited.connect(m.filter)
    return nl, f
Exemple #13
0
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"Unique Key Name:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(
            u"<p>Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it."
        )
        key_group.addWidget(self.key_ledit)

        name_group = QHBoxLayout()
        data_group_box_layout.addLayout(name_group)
        name_group.addWidget(QLabel(u"Your Name:", self))
        self.name_ledit = QLineEdit(u"", self)
        self.name_ledit.setToolTip(
            u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won't be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)"
        )
        name_group.addWidget(self.name_ledit)
        name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self)
        name_disclaimer_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(name_disclaimer_label)

        ccn_group = QHBoxLayout()
        data_group_box_layout.addLayout(ccn_group)
        ccn_group.addWidget(QLabel(u"Credit Card#:", self))
        self.cc_ledit = QLineEdit(u"", self)
        self.cc_ledit.setToolTip(
            u"<p>Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won't be stored anywhere in calibre or on your computer."
        )
        ccn_group.addWidget(self.cc_ledit)
        ccn_disclaimer_label = QLabel(_("(Will not be saved in configuration data)"), self)
        ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(ccn_disclaimer_label)
        layout.addSpacing(10)

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

        self.resize(self.sizeHint())
Exemple #14
0
class AddSerialDialog(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(
            u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged."
        )
        key_group.addWidget(self.key_ledit)

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

        self.resize(self.sizeHint())

    @property
    def key_name(self):
        return unicode(self.key_ledit.text()).strip()

    @property
    def key_value(self):
        return unicode(self.key_ledit.text()).strip()

    def accept(self):
        if len(self.key_name) == 0 or self.key_name.isspace():
            errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
            return error_dialog(
                None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False
            )
        if len(self.key_name) != 16:
            errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(
                len(self.key_name)
            )
            return error_dialog(
                None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False
            )
        QDialog.accept(self)
Exemple #15
0
    def __init__(self, parent_dialog, plugin_action):
        QWidget.__init__(self)
        self.parent_dialog = parent_dialog
        self.plugin_action = plugin_action
        
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        label = QLabel(_('Searches to use for:'))
        label.setWordWrap(True)
        self.l.addWidget(label)
        #self.l.addSpacing(5)
        
        scrollable = QScrollArea()
        scrollcontent = QWidget()
        scrollable.setWidget(scrollcontent)
        scrollable.setWidgetResizable(True)
        self.l.addWidget(scrollable)

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

        
        self.sl.addWidget(QLabel(_("Search for Duplicated Books:")))
        self.checkdups_search = QLineEdit(self)
        self.sl.addWidget(self.checkdups_search)
        self.checkdups_search.setText(prefs['checkdups_search'])
        self.checkdups_search.setToolTip(_('Default is %s')%default_prefs['checkdups_search'])
        self.sl.addSpacing(5)
        
        self.sl.addWidget(QLabel(_("Deleted Books (not in Library):")))
        self.checknotinlibrary_search = QLineEdit(self)
        self.sl.addWidget(self.checknotinlibrary_search)
        self.checknotinlibrary_search.setText(prefs['checknotinlibrary_search'])
        self.checknotinlibrary_search.setToolTip(_('Default is %s')%default_prefs['checknotinlibrary_search'])
        self.sl.addSpacing(5)
        
        self.sl.addWidget(QLabel(_("Added Books (not on Device):")))
        self.checknotondevice_search = QLineEdit(self)
        self.sl.addWidget(self.checknotondevice_search)
        self.checknotondevice_search.setText(prefs['checknotondevice_search'])
        self.checknotondevice_search.setToolTip(_('Default is %s')%default_prefs['checknotondevice_search'])
                        
        self.sl.insertStretch(-1)
        
        self.l.addSpacing(15)        

        restore_defaults_button = QPushButton(_('Restore Defaults'), self)
        restore_defaults_button.setToolTip(_('Revert all searches to the defaults.'))
        restore_defaults_button.clicked.connect(self.restore_defaults_button)
        self.l.addWidget(restore_defaults_button)
    def _initialize_general(self, v_layout):
        '''Initialize asin/goodreads sections'''
        # Add the ASIN label, line edit, and button to dialog
        self._asin_edit = QLineEdit('')
        asin_layout = QHBoxLayout(None)
        asin_label = QLabel('ASIN:')
        asin_label.setFixedWidth(100)
        asin_browser_button = QPushButton('Open..')
        asin_browser_button.clicked.connect(self.browse_amazon_url)
        asin_browser_button.setToolTip('Open Amazon page for the specified ASIN')
        self._asin_edit.textEdited.connect(lambda: self.edit_asin(self._asin_edit.text(), asin_browser_button))
        asin_layout.addWidget(asin_label)
        asin_layout.addWidget(self._asin_edit)
        asin_layout.addWidget(asin_browser_button)
        v_layout.addLayout(asin_layout)

        # Add the Goodreads URL label, line edit, and button to dialog
        self._goodreads_url_edit = QLineEdit('')
        self._goodreads_url_edit.textEdited.connect(lambda: self.edit_goodreads_url(self._goodreads_url_edit.text(),
                                                                                    goodreads_browser_button))
        goodreads_layout = QHBoxLayout(None)
        goodreads_url_label = QLabel('Goodreads URL:')
        goodreads_url_label.setFixedWidth(100)
        goodreads_browser_button = QPushButton('Open..')
        goodreads_browser_button.clicked.connect(self.browse_goodreads_url)
        goodreads_browser_button.setToolTip('Open Goodreads page at the specified URL')
        goodreads_layout.addWidget(goodreads_url_label)
        goodreads_layout.addWidget(self._goodreads_url_edit)
        goodreads_layout.addWidget(goodreads_browser_button)
        v_layout.addLayout(goodreads_layout)

        # Add the update buttons to dialog
        self._update_aliases_button = QPushButton('Update Aliases from URL')
        self._update_aliases_button.setFixedWidth(175)
        self._update_aliases_button.clicked.connect(self.update_aliases)
        update_buttons_layout = QHBoxLayout(None)
        update_asin_button = QPushButton('Search for ASIN')
        update_asin_button.setFixedWidth(175)
        update_asin_button.clicked.connect(lambda: self.search_for_asin_clicked(asin_browser_button))
        update_buttons_layout.addWidget(update_asin_button)
        update_goodreads_url_button = QPushButton('Search for Goodreads URL')
        update_goodreads_url_button.setFixedWidth(175)
        update_goodreads_url_button.clicked.connect(lambda: self.search_for_goodreads_url(goodreads_browser_button))
        update_buttons_layout.addWidget(update_goodreads_url_button)

        update_buttons_layout.addWidget(self._update_aliases_button)
        v_layout.addLayout(update_buttons_layout)

        return asin_browser_button, goodreads_browser_button
Exemple #17
0
 def __init__(self, *args):
     QLineEdit.__init__(self, *args)
     self.setValidator(QRegExpValidator(QRegExp(r"\d+\.\d+"), self))
     self.setToolTip(
         textwrap.fill(
             "<p>"
             + _(
                 "Go to a reference. To get reference numbers, use the <i>reference "
                 "mode</i>, by clicking the reference mode button in the toolbar."
             )
         )
     )
     if hasattr(self, "setPlaceholderText"):
         self.setPlaceholderText(_("Go to a reference number..."))
     self.editingFinished.connect(self.editing_finished)
Exemple #18
0
    def __init__(self, parent=None, completer_widget=None, sort_func=sort_key):
        QLineEdit.__init__(self, parent)

        self.sep = ","
        self.space_before_sep = False
        self.add_separator = True
        self.original_cursor_pos = None
        completer_widget = self if completer_widget is None else completer_widget

        self.mcompleter = Completer(completer_widget, sort_func=sort_func)
        self.mcompleter.item_selected.connect(self.completion_selected, type=Qt.QueuedConnection)
        self.mcompleter.relayout_needed.connect(self.relayout)
        self.mcompleter.setFocusProxy(completer_widget)
        self.textEdited.connect(self.text_edited)
        self.no_popup = False
Exemple #19
0
    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db

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

        self.header = QLabel(prefs['searchinbookbrainz'])
        self.l.addWidget(self.header)

        self.img = QLabel()
        pixmap = QPixmap("images/BBt.svg")
        self.img.setPixmap(pixmap)
        self.l.addWidget(self.img)

        # QCol = QColor()
        # QCol.setRed(220)
        # QCol.setGreen(255)
        # QCol.setBlue(240)


        self.setWindowTitle('Calibre Book Brainz Integration')
        self.setWindowIcon(icon)

        self.search_space = QLineEdit()
        self.selected_button = QPushButton('Use title from selected book', self)
        self.selected_button.clicked.connect(self.exporttitlefromselected)
        self.l.addWidget(self.selected_button)

        self.search_space = QLineEdit()
        self.l.addWidget(self.search_space)

        self.listWidget = QListWidget()
        self.l.addWidget(self.listWidget)

        self.searchExecutionButton = QPushButton('Search', self)
        self.searchExecutionButton.clicked.connect(self.search)
        self.l.addWidget(self.searchExecutionButton)

        self.aboutButton = QPushButton('About', self)
        self.aboutButton.clicked.connect(self.about)
        self.l.addWidget(self.aboutButton)

        self.resize(400, 600)
        self.search_space.setFocus()
Exemple #20
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()
Exemple #21
0
    def __init__(self, stats, location, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle(_('No library found'))
        self._l = l = QGridLayout(self)
        self.setLayout(l)
        self.stats, self.location = stats, location

        loc = self.oldloc = location.replace('/', os.sep)
        self.header = QLabel(_('No existing calibre library was found at %s. '
            'If the library was moved, select its new location below. '
            'Otherwise calibre will forget this library.')%loc)
        self.header.setWordWrap(True)
        ncols = 2
        l.addWidget(self.header, 0, 0, 1, ncols)
        self.cl = QLabel('<br><b>'+_('New location of this library:'))
        l.addWidget(self.cl, 1, 0, 1, ncols)
        self.loc = QLineEdit(loc, self)
        l.addWidget(self.loc, 2, 0, 1, 1)
        self.cd = QToolButton(self)
        self.cd.setIcon(QIcon(I('document_open.png')))
        self.cd.clicked.connect(self.choose_dir)
        l.addWidget(self.cd, 2, 1, 1, 1)
        self.bb = QDialogButtonBox(QDialogButtonBox.Abort)
        b = self.bb.addButton(_('Library moved'), self.bb.AcceptRole)
        b.setIcon(QIcon(I('ok.png')))
        b = self.bb.addButton(_('Forget library'), self.bb.RejectRole)
        b.setIcon(QIcon(I('edit-clear.png')))
        b.clicked.connect(self.forget_library)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        l.addWidget(self.bb, 3, 0, 1, ncols)
        self.resize(self.sizeHint() + QSize(100, 50))
Exemple #22
0
    def __init__(self, parent=None,):
        print repr(self), repr(parent)
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox('', self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        data_group_box_layout.addWidget(QLabel('New Key Name:', self))
        self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
        self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name))
        data_group_box_layout.addWidget(self.key_ledit)

        layout.addSpacing(20)

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

        self.resize(self.sizeHint())
Exemple #23
0
    def __init__(self, parent=None,):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
        key_group.addWidget(self.key_ledit)

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

        self.resize(self.sizeHint())
Exemple #24
0
    def __init__(self, parent=None,):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"PID:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
        key_group.addWidget(self.key_ledit)

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

        self.resize(self.sizeHint())
Exemple #25
0
class Title(QWidget):

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.ll = ll = QGridLayout()
        self.setLayout(self.ll)

        self.labell = QLabel('Title:')
        ll.addWidget(self.labell, 0, 0, 1, 1)
        self.title_edit = QLineEdit(self)
        self.title_edit.setPlaceholderText('Enter a title for the ebook ')
        ll.addWidget(self.title_edit, 0, 1, 1, 1)

    @property
    def title(self):
        return unicode(self.title_edit.text())
Exemple #26
0
 def __init__(self, parent=None):
     QLineEdit.__init__(self, parent)
     self.setAttribute(Qt.WA_MacShowFocusRect, False)
     self.setStyleSheet('''
     QLineEdit {
         border-radius: 8px;
         padding: 1px 6px;
         background: BG;
         color: FG;
         selection-background-color: SEL;
     }
     '''.replace('BG', color('status bar background', 'palette(window)')).replace(
         'FG', color('status bar foreground', 'palette(window-text)')).replace(
         'SEL', color('status bar selection', 'palette(highlight)'))
     )
     self.setPlaceholderText(_('Enter command'))
Exemple #27
0
    def __init__(self, parent=None,):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle(u"{0} {1}: Add New Kindle for Android Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        data_group_box = QGroupBox(u"", self)
        layout.addWidget(data_group_box)
        data_group_box_layout = QVBoxLayout()
        data_group_box.setLayout(data_group_box_layout)

        key_group = QHBoxLayout()
        data_group_box_layout.addLayout(key_group)
        key_group.addWidget(QLabel(u"Kindle for Android Serial Number:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(u"Enter a Kindle for ANdroid serial number. These can be found using the androidkindlekey.py script.")
        key_group.addWidget(self.key_ledit)
        key_label = QLabel(_(''), self)
        key_label.setAlignment(Qt.AlignHCenter)
        data_group_box_layout.addWidget(key_label)

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

        self.resize(self.sizeHint())
    def update_aliases_on_gui(self):
        '''Updates aliases on the dialog using the info in the book's aliases dict'''
        aliases_widget = QWidget()
        aliases_layout = QGridLayout(aliases_widget)
        aliases_layout.setAlignment(Qt.AlignTop)

        # add aliases for current book
        for index, (character, aliases) in enumerate(sorted(self.book.aliases.items())):
            label = QLabel(character + ':')
            label.setFixedWidth(150)
            aliases_layout.addWidget(label, index, 0)
            line_edit = QLineEdit(', '.join([self.TITLE_CASE(alias) for alias in aliases]))
            line_edit.setFixedWidth(350)
            line_edit.textEdited.connect(functools.partial(self.edit_aliases, character))
            aliases_layout.addWidget(line_edit, index, 1)

        self._scroll_area.setWidget(aliases_widget)
 def __init__(self, parent=None):
     super(SynthesisQWidget, self).__init__(parent)
     # Fields
     self.host_widget = HostQWidget()
     self.services_widget = ServicesQWidget()
     self.line_search = QLineEdit()
     self.completer = QCompleter()
     self.hint_widget = QWidget()
Exemple #30
0
class ConfigWidget(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.l = QHBoxLayout()
        self.setLayout(self.l)

        self.label = QLabel('Hello world &message:')
        self.l.addWidget(self.label)

        self.msg = QLineEdit(self)
        self.msg.setText(prefs['hello_world_msg'])
        self.l.addWidget(self.msg)
        self.label.setBuddy(self.msg)

    def save_settings(self):
        prefs['hello_world_msg'] = self.msg.text()
Exemple #31
0
class ThemeCreateDialog(Dialog):

    def __init__(self, parent, report):
        self.report = report
        Dialog.__init__(self, _('Create an icon theme'), 'create-icon-theme', parent)

    def setup_ui(self):
        self.splitter = QSplitter(self)
        self.l = l = QVBoxLayout(self)
        l.addWidget(self.splitter)
        l.addWidget(self.bb)
        self.w = w = QGroupBox(_('Theme Metadata'), self)
        self.splitter.addWidget(w)
        l = w.l = QFormLayout(w)
        self.missing_icons_group = mg = QGroupBox(self)
        self.mising_icons = mi = QListWidget(mg)
        mi.setSelectionMode(mi.NoSelection)
        mg.l = QVBoxLayout(mg)
        mg.l.addWidget(mi)
        self.splitter.addWidget(mg)
        self.title = QLineEdit(self)
        l.addRow(_('&Title:'), self.title)
        self.author = QLineEdit(self)
        l.addRow(_('&Author:'), self.author)
        self.version = v = QSpinBox(self)
        v.setMinimum(1), v.setMaximum(1000000)
        l.addRow(_('&Version:'), v)
        self.description = QTextEdit(self)
        l.addRow(self.description)
        self.refresh_button = rb = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
        rb.setIcon(QIcon(I('view-refresh.png')))
        rb.clicked.connect(self.refresh)

        self.apply_report()

    def sizeHint(self):
        return QSize(900, 600)

    @property
    def metadata(self):
        return {
            'title': self.title.text().strip(),
            'author': self.author.text().strip(),
            'version': self.version.value(),
            'description': self.description.toPlainText().strip(),
        }

    def save_metadata(self):
        with open(os.path.join(self.report.path, THEME_METADATA), 'wb') as f:
            json.dump(self.metadata, f, indent=2)

    def refresh(self):
        self.save_metadata()
        self.report = read_theme_from_folder(self.report.path)
        self.apply_report()

    def apply_report(self):
        theme = self.report.theme
        self.title.setText((theme.title or '').strip())
        self.author.setText((theme.author or '').strip())
        self.version.setValue(theme.version or 1)
        self.description.setText((theme.description or '').strip())
        if self.report.missing:
            title =  _('%d icons missing in this theme') % len(self.report.missing)
        else:
            title = _('No missing icons')
        self.missing_icons_group.setTitle(title)
        mi = self.mising_icons
        mi.clear()
        for name in sorted(self.report.missing):
            QListWidgetItem(QIcon(I(name, allow_user_override=False)), name, mi)

    def accept(self):
        mi = self.metadata
        if not mi.get('title'):
            return error_dialog(self, _('No title specified'), _(
                'You must specify a title for this icon theme'), show=True)
        if not mi.get('author'):
            return error_dialog(self, _('No author specified'), _(
                'You must specify an author for this icon theme'), show=True)
        return Dialog.accept(self)
Exemple #32
0
 def mousePressEvent(self, ev):
     QLineEdit.mousePressEvent(self, ev)
     if self.select_on_mouse_press is not None and abs(
             time.time() - self.select_on_mouse_press) < 0.2:
         self.selectAll()
     self.select_on_mouse_press = None
 def __init__(self, text, parent):
     if text is None:
         text = ''
     QLineEdit.__init__(self, text, parent)
     self.setEnabled(False)
Exemple #34
0
class LedgerAuthDialog(QDialog):
    def __init__(self, handler, data):
        '''Ask user for 2nd factor authentication. Support text, security card and paired mobile methods.
        Use last method from settings, but support new pairing and downgrade.
        '''
        QDialog.__init__(self, handler.top_level_window())
        self.handler = handler
        self.txdata = data
        self.idxs = self.txdata[
            'keycardData'] if self.txdata['confirmationType'] > 1 else ''
        self.setMinimumWidth(650)
        self.setWindowTitle(_("Ledger Wallet Authentication"))
        self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg)
        self.dongle = self.handler.win.wallet.get_keystore().get_client(
        ).dongle
        self.ws = None
        self.pin = ''

        self.devmode = self.getDevice2FAMode()
        if self.devmode == 0x11 or self.txdata['confirmationType'] == 1:
            self.cfg['mode'] = 0

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        def on_change_mode(idx):
            if idx < 2 and self.ws:
                self.ws.stop()
                self.ws = None
            self.cfg[
                'mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1
            if self.cfg['mode'] > 1 and self.cfg['pair'] and not self.ws:
                self.req_validation()
            if self.cfg['mode'] > 0:
                self.handler.win.wallet.get_keystore().cfg = self.cfg
                self.handler.win.wallet.save_keystore()
            self.update_dlg()

        def add_pairing():
            self.do_pairing()

        def return_pin():
            self.pin = self.pintxt.text(
            ) if self.txdata['confirmationType'] == 1 else self.cardtxt.text()
            if self.cfg['mode'] == 1:
                self.pin = ''.join(chr(int(str(i), 16)) for i in self.pin)
            self.accept()

        self.modebox = QWidget()
        modelayout = QHBoxLayout()
        self.modebox.setLayout(modelayout)
        modelayout.addWidget(QLabel(_("Method:")))
        self.modes = QComboBox()
        modelayout.addWidget(self.modes, 2)
        self.addPair = QPushButton(_("Pair"))
        self.addPair.setMaximumWidth(60)
        modelayout.addWidget(self.addPair)
        modelayout.addStretch(1)
        self.modebox.setMaximumHeight(50)
        vbox.addWidget(self.modebox)

        self.populate_modes()
        self.modes.currentIndexChanged.connect(on_change_mode)
        self.addPair.clicked.connect(add_pairing)

        self.helpmsg = QTextEdit()
        self.helpmsg.setStyleSheet(
            "QTextEdit { background-color: lightgray; }")
        self.helpmsg.setReadOnly(True)
        vbox.addWidget(self.helpmsg)

        self.pinbox = QWidget()
        pinlayout = QHBoxLayout()
        self.pinbox.setLayout(pinlayout)
        self.pintxt = QLineEdit()
        self.pintxt.setEchoMode(2)
        self.pintxt.setMaxLength(4)
        self.pintxt.returnPressed.connect(return_pin)
        pinlayout.addWidget(QLabel(_("Enter PIN:")))
        pinlayout.addWidget(self.pintxt)
        pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        pinlayout.addStretch(1)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        vbox.addWidget(self.pinbox)

        self.cardbox = QWidget()
        card = QVBoxLayout()
        self.cardbox.setLayout(card)
        self.addrtext = QTextEdit()
        self.addrtext.setStyleSheet(
            "QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family:monospace; }"
        )
        self.addrtext.setReadOnly(True)
        self.addrtext.setMaximumHeight(130)
        card.addWidget(self.addrtext)

        def pin_changed(s):
            if len(s) < len(self.idxs):
                i = self.idxs[len(s)]
                addr = self.txdata['address']
                if not constants.net.TESTNET:
                    text = addr[:i] + '<u><b>' + addr[
                        i:i + 1] + '</u></b>' + addr[i + 1:]
                else:
                    # pin needs to be created from mainnet address
                    addr_mainnet = bitcoin.script_to_address(
                        bitcoin.address_to_script(addr),
                        net=constants.BitcoinMainnet)
                    addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[
                        i:i + 1] + '</u></b>' + addr_mainnet[i + 1:]
                    text = str(addr) + '\n' + str(addr_mainnet)
                self.addrtext.setHtml(str(text))
            else:
                self.addrtext.setHtml(_("Press Enter"))

        pin_changed('')
        cardpin = QHBoxLayout()
        cardpin.addWidget(QLabel(_("Enter PIN:")))
        self.cardtxt = QLineEdit()
        self.cardtxt.setEchoMode(2)
        self.cardtxt.setMaxLength(len(self.idxs))
        self.cardtxt.textChanged.connect(pin_changed)
        self.cardtxt.returnPressed.connect(return_pin)
        cardpin.addWidget(self.cardtxt)
        cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        cardpin.addStretch(1)
        card.addLayout(cardpin)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        vbox.addWidget(self.cardbox)

        self.pairbox = QWidget()
        pairlayout = QVBoxLayout()
        self.pairbox.setLayout(pairlayout)
        pairhelp = QTextEdit(helpTxt[5])
        pairhelp.setStyleSheet("QTextEdit { background-color: lightgray; }")
        pairhelp.setReadOnly(True)
        pairlayout.addWidget(pairhelp, 1)
        self.pairqr = QRCodeWidget()
        pairlayout.addWidget(self.pairqr, 4)
        self.pairbox.setVisible(False)
        vbox.addWidget(self.pairbox)
        self.update_dlg()

        if self.cfg['mode'] > 1 and not self.ws:
            self.req_validation()

    def populate_modes(self):
        self.modes.blockSignals(True)
        self.modes.clear()
        self.modes.addItem(
            _("Summary Text PIN (requires dongle replugging)"
              ) if self.txdata['confirmationType'] ==
            1 else _("Summary Text PIN is Disabled"))
        if self.txdata['confirmationType'] > 1:
            self.modes.addItem(_("Security Card Challenge"))
            if not self.cfg['pair']:
                self.modes.addItem(_("Mobile - Not paired"))
            else:
                self.modes.addItem(
                    _("Mobile - {}").format(self.cfg['pair'][1]))
        self.modes.blockSignals(False)

    def update_dlg(self):
        self.modes.setCurrentIndex(self.cfg['mode'])
        self.modebox.setVisible(True)
        self.addPair.setText(
            _("Pair") if not self.cfg['pair'] else _("Re-Pair"))
        self.addPair.setVisible(self.txdata['confirmationType'] > 2)
        self.helpmsg.setText(
            helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self.
                    cfg['pair'] else 4])
        self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] ==
                                      1 else 100)
        self.pairbox.setVisible(False)
        self.helpmsg.setVisible(True)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        self.pintxt.setFocus(
            True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True)
        self.setMaximumHeight(400)

    def do_pairing(self):
        rng = os.urandom(16)
        pairID = (hexlify(rng) +
                  hexlify(hashlib.sha256(rng).digest()[0:1])).decode('utf-8')
        self.pairqr.setData(pairID)
        self.modebox.setVisible(False)
        self.helpmsg.setVisible(False)
        self.pinbox.setVisible(False)
        self.cardbox.setVisible(False)
        self.pairbox.setVisible(True)
        self.pairqr.setMinimumSize(300, 300)
        if self.ws:
            self.ws.stop()
        self.ws = LedgerWebSocket(self, pairID)
        self.ws.pairing_done.connect(self.pairing_done)
        self.ws.start()

    def pairing_done(self, data):
        if data is not None:
            self.cfg['pair'] = [data['pairid'], data['name'], data['platform']]
            self.cfg['mode'] = 2
            self.handler.win.wallet.get_keystore().cfg = self.cfg
            self.handler.win.wallet.save_keystore()
        self.pin = 'paired'
        self.accept()

    def req_validation(self):
        if self.cfg['pair'] and 'secureScreenData' in self.txdata:
            if self.ws:
                self.ws.stop()
            self.ws = LedgerWebSocket(self, self.cfg['pair'][0], self.txdata)
            self.ws.req_updated.connect(self.req_updated)
            self.ws.start()

    def req_updated(self, pin):
        if pin == 'accepted':
            self.helpmsg.setText(helpTxt[3])
        else:
            self.pin = str(pin)
            self.accept()

    def getDevice2FAMode(self):
        apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01]  # get 2fa mode
        try:
            mode = self.dongle.exchange(bytearray(apdu))
            return mode
        except BTChipException as e:
            debug_msg('Device getMode Failed')
        return 0x11

    def closeEvent(self, evnt):
        debug_msg("CLOSE - Stop WS")
        if self.ws:
            self.ws.stop()
        if self.pairbox.isVisible():
            evnt.ignore()
            self.update_dlg()
Exemple #35
0
 def __init__(self, parent):
     QLineEdit.__init__(self, parent)
     self.mi = None
Exemple #36
0
class ImageDisplay(QWidget):

    video_infos = [
        'vidéo : {}', 'nb frames : {}', 'taille : {}', 'FPS : {}',
        'durée : {:.2f} sec'
    ]
    video_keys = ['videoname', 'nframes', 'size', 'fps', 'duration']
    algo_traj = ['barycentre', 'minmax']

    def __init__(self, mainWindow):

        # acall the base class constructor:
        super().__init__(mainWindow)

        self.mw = mainWindow

        # Attributs (objets persistants)
        self.img_lbl = QLabel(self)  # to display the current image
        self.img_lbl.installEventFilter(self)  # filter to catch evenements
        self.selectTargetRect = None  # display a rectangle to show teh target color selection

        self.rubberBand = QRubberBand(QRubberBand.Line, self)

        # Boutons pour avancer/reculer
        self.btn_prev = QPushButton(QIcon("icones/go-prev.png"), "", self)
        self.btn_next = QPushButton(QIcon("icones/go-next.png"), "", self)
        self.btn_first = QPushButton(QIcon("icones/go-first.png"), "", self)
        self.btn_last = QPushButton(QIcon("icones/go-last.png"), "", self)
        self.btn_traj = QPushButton(QIcon("icones/extract.png"), "Extraire...",
                                    self)
        self.btn_clear = QPushButton(QIcon("icones/clear.png"),
                                     "Effacer courbes...", self)
        self.btn_exportCSV = QPushButton(QIcon("icones/exportCSV.png"),
                                         "Export CSV", self)
        self.btn_algo = QComboBox(self)
        self.image_index = QLabel(self)

        # widget QSpinBox
        self.images_step = QSpinBox(parent=self)
        self.images_firstRank = QSpinBox(parent=self)
        self.images_lastRank = QSpinBox(parent=self)

        # QLabel to display the target color
        self.target_color_label = QLabel("target color", parent=self)
        self.picked_color = QLabel(self)

        self.video_path = None  # Chemin de la dernière vidéo
        self.images_dir = None  # Dossier contenant les images
        self.__img_idx = None  # Rang de l'image affichée
        self.img_path = None  # nom du chemin de l'image courante
        self.nb_img = None  # nombre d'images

        self.video_name = None  # nom de la video ("aaaaaa.mp4")
        self.video_nframes = None  # nombre d'images dans la video
        self.video_size = None  # taille (width, height) des images
        self.video_FPS = None  # nombre d'images par seconde
        self.video_duration = None  # durée de la video en secondes
        self.videoLabels = []  # liste de QLabel contenant les infos vidéo
        self.dico_video = {}  # dictionnaire des méta-données

        self.dico_unit = {}  # dictionary "pixels", "mm"
        self.scale_pixel = None  # nombre de pixels pour conversion en mm
        self.scale_mm = None  # nbre de mm pour scale_pixel
        self.valid_scale = False  # données de l'échelle valides ou pas
        self.pix_to_mm_coeff = 1.  # le coefficient de converion pixels -> mm
        self.dicoScale = {}  # dictionnaire des QWidget d'info scale

        self.lbl_epsilon = None  # label epsilon
        self.epsi_spin = None  # boite de choix de epsilon

        # créer l'onglet de visualisation image """
        self.__initUI()
        self.scaleInfoVisible(False)
        self.__epsilonVisible(False)

    def __initUI(self):

        # Onglet "Visualisation images"
        vbox = QVBoxLayout()

        # Ligne 1 : extraction trajec
        self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)

        line1 = QHBoxLayout()
        line1.addStretch(1)
        line1.addWidget(self.btn_algo)
        line1.addWidget(self.btn_traj)
        line1.addWidget(self.target_color_label)
        line1.addWidget(self.picked_color)
        line1.addWidget(self.btn_clear)
        line1.addWidget(self.btn_exportCSV)
        line1.addStretch(1)

        # Ligne 2 : infos video + visu image
        line2 = QHBoxLayout()

        # boîte d'infos sur la vidéo
        infoVBox = QVBoxLayout()
        for _ in ImageDisplay.video_infos:
            label = QLabel(self)
            label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
            infoVBox.addWidget(label)
            self.videoLabels.append(label)
        infoVBox.addStretch()

        widget = QLabel("Conversion pixels -> mm", self)
        self.dicoScale['Pixels-mm'] = widget
        infoVBox.addWidget(widget)

        grid = QGridLayout()
        infoVBox.addLayout(grid)

        widget = QLabel("pixels  ", self)
        self.dicoScale['pixels'] = widget
        grid.addWidget(widget, 1, 1)

        self.scale_pixel = QLineEdit(self)
        self.dicoScale['pixelsForMM'] = self.scale_pixel
        grid.addWidget(self.scale_pixel, 1, 2)

        widget = QLabel("millimètres ", self)
        self.dicoScale['millimeters'] = widget
        grid.addWidget(widget, 2, 1)

        self.scale_mm = QLineEdit(self)
        self.dicoScale['mmForPixels'] = self.scale_mm
        grid.addWidget(self.scale_mm, 2, 2)

        self.lbl_epsilon = QLabel("Epsilon ", self)
        grid.addWidget(self.lbl_epsilon, 5, 1)

        self.epsi_spin = QSpinBox(self)
        self.epsi_spin.setRange(1, 50)
        self.epsi_spin.setSingleStep(1)
        self.epsi_spin.setValue(10)
        grid.addWidget(self.epsi_spin, 5, 2)

        infoVBox.addStretch()

        line2.addLayout(infoVBox)
        line2.addStretch(1)
        line2.addWidget(self.img_lbl)  # le QLabel por afficher l'image
        line2.addStretch(1)

        # line 3 : navigation boutons
        self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.image_index.setText("       ")
        line3 = QHBoxLayout()
        line3.addStretch(1)
        line3.addWidget(self.btn_first)
        line3.addWidget(self.btn_prev)
        line3.addWidget(self.image_index)
        line3.addWidget(self.btn_next)
        line3.addWidget(self.btn_last)
        line3.addStretch(1)

        # line 4 : first , step, last image selection
        line4 = QHBoxLayout()
        line4.addStretch(1)
        line4.addWidget(self.images_firstRank)
        line4.addWidget(self.images_step)
        line4.addWidget(self.images_lastRank)
        line4.addStretch(1)

        vbox.addLayout(line1)
        vbox.addStretch(1)
        vbox.addLayout(line2)
        vbox.addStretch(1)
        vbox.addLayout(line3)
        vbox.addLayout(line4)

        self.setLayout(vbox)

        self.buttonsState()
        self.__buttonsConnect()
        self.__setVideoLabelVisible(False)

    def __setVideoLabelVisible(self, state):
        for label in self.videoLabels:
            label.setVisible(state)

    def __buttonsConnect(self):
        self.btn_traj.clicked.connect(self.extract_trajectoire)
        self.btn_clear.clicked.connect(self.mw.clearPlots)
        self.btn_exportCSV.clicked.connect(self.mw.ExportCSV)
        self.btn_prev.clicked.connect(self.prev_image)
        self.btn_next.clicked.connect(self.next_image)
        self.btn_first.clicked.connect(self.first_image)
        self.btn_last.clicked.connect(self.last_image)
        self.images_step.valueChanged.connect(self.__step_changed)
        self.images_firstRank.valueChanged.connect(self.__first_rank_changed)
        self.images_lastRank.valueChanged.connect(self.__last_rank_changed)

    def buttonsState(self, importCSV=False):

        self.btn_traj.setEnabled(False)
        self.picked_color.setText("X")
        self.picked_color.setEnabled(False)

        self.btn_traj.setStatusTip('Extrait la trajectoire de la cible' +
                                   'dont la couleur a été choisie')

        self.target_color_label.setEnabled(False)
        self.picked_color.setStyleSheet(
            'background-color : rgb(255, 255, 255)')

        self.btn_clear.setEnabled(False)
        self.btn_clear.setStatusTip('Nettoye tous les tracés des onglets' +
                                    '<trajectoire> et <X(t), Y(t)>')

        self.btn_exportCSV.setEnabled(False)
        texte = "Export des données dans un fichier CSV"
        self.btn_exportCSV.setStatusTip(texte)

        if not importCSV: self.btn_algo.addItems(ImageDisplay.algo_traj)
        self.btn_algo.setEnabled(False)

        self.btn_prev.setEnabled(False)
        self.btn_prev.setStatusTip("affiche l'image précédente")

        self.btn_next.setEnabled(False)
        self.btn_next.setStatusTip("affiche l'image suivante")

        self.btn_first.setEnabled(False)
        self.btn_first.setStatusTip("affiche la première image à traiter")

        self.btn_last.setEnabled(False)
        self.btn_last.setStatusTip("affiche la dernière image à traiter")

        # SpinBoxes parameters:
        self.images_step.setRange(1, 1000)
        self.images_step.setSingleStep(1)
        self.images_step.setValue(1)
        self.images_step.setPrefix("step: ")
        self.images_step.setEnabled(False)
        self.images_step.setStatusTip(
            "Fixe le pas pour passer d'une image à l'autre")

        self.images_firstRank.setRange(1, 1000)
        self.images_firstRank.setSingleStep(1)
        self.images_firstRank.setValue(1)
        self.images_firstRank.setPrefix("first: ")
        self.images_firstRank.setEnabled(False)
        self.images_firstRank.setStatusTip(
            "Fixe le rang de la première image à traiter")

        self.images_lastRank.setRange(1, 10000)
        self.images_lastRank.setSingleStep(1)
        self.images_lastRank.setValue(1)
        self.images_lastRank.setPrefix("last: ")
        self.images_lastRank.setEnabled(False)
        self.images_lastRank.setStatusTip(
            "Fixe le rang de la dernière image à traiter")

    def __first_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx < val:
            self.img_idx = val
            self.show_image()

    def __last_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx > val:
            self.img_idx = val
            self.show_image()

    def __step_changed(self, val):
        if self.img_idx is None: return

    def setTextInfoVideoGrid(self):

        for field, name, key in zip(self.videoLabels, ImageDisplay.video_infos,
                                    ImageDisplay.video_keys):
            mess = name.format(self.dico_video.get(key, '?'))
            field.setText(mess)
        self.__setVideoLabelVisible(True)

    def scaleInfoVisible(self, state):
        for widget in self.dicoScale.values():
            widget.setVisible(state)

    def __epsilonVisible(self, state):
        self.lbl_epsilon.setVisible(state)
        self.epsi_spin.setVisible(state)

    def open_video(self):
        '''Lance un sélecteur de fichier pour choisir la vidéo à traiter.'''
        fname = QFileDialog.getOpenFileName(None, 'Choisir une vidéo',
                                            self.mw.cur_dir,
                                            'Fichier vidéo (*.mp4)')
        if fname[0] != '':
            # un fichier vidéo a été chosi :
            vp = fname[0]
            if self.video_path == vp:
                name = os.path.basename(vp)
                rep = QMessageBox.question(
                    self,  # widget parent de QMessageBox
                    'Question',  # texte du bandeau de la fenêtre
                    'Voulez-vous recharger le fichier video {} ?'.format(name),
                    QMessageBox.Yes
                    | QMessageBox.No,  # afficher les boutons Yes et No
                    QMessageBox.No)  # bouton No sélectionné par défaut
                if rep == QMessageBox.No: return
            # fichier vidéo à traiter => faire le split des images :
            self.video_path = vp
            self.extract_images_from_video()

    def load_images_from_directory(self):
        '''Charge les images '*.png' contenue dans le répertoire
           des images choisi avec un sélecteur graphique.'''

        # Choix du répertoire avec un sélecteur de fichier :
        dname = QFileDialog.getExistingDirectory(None,
                                                 'Choisir un dossier images',
                                                 self.mw.image_dir)
        if dname != '':
            # un répertoire valide a été choisi :
            self.video_path = None
            self.images_dir = dname + "/"

            try:
                # Lecture du fichier ascii des méta-données
                with open(self.images_dir + "metaData.txt", "r") as F:
                    data = F.read()
                exec('self.dico_video = ' + data)
            except:
                rep = QMessageBox.critical(
                    None,             # widget parent de QMessageBox
                    'Erreur',    # bandeau de la fenêtre
                    'Pas de fichier de méta-données dans le répertoire'+\
                    ' <{}>'.format(os.path.basename(dname)),
                    QMessageBox.Ok)
                return

            print("méta données :", self.dico_video)

            self.parse_meta_data()
            self.setTextInfoVideoGrid()

            # Mettre à jour l'application avec les nouvelles images chargées :
            self.update_images()

    def extract_trajectoire(self):
        '''Méthode utilisée pour extraire la trajectoire du centre de la
           cible pour toutes les images de la vidéo.'''

        # Récupérer l'algorithme de calcul du centre de la cible :
        algo = self.btn_algo.currentText()

        # Définition de la liste dans laquelle on va récupérer les coordonnées
        # du centre cible pour toutes les images :
        target_pos = []

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction de la cible dans les images tout en affichant une
        # barre d'avancement :

        first = self.images_firstRank.value()
        last = self.images_lastRank.value()
        step = self.images_step.value()

        last = last - (last - first) % step
        first_last_step = (first, last, step)
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_target_extraction(self.mw.target_RGB, algo,
                                           self.epsi_spin.value(), target_pos,
                                           first_last_step)
        ret = pg.exec_()  # lance la barre et le travail d'extraction...
        print("retour de pg.exec_() :", ret)

        if ret != 0:
            self.mw.target_pos = None
            return

        target_pos = np.array(target_pos)
        width, height = self.video_size
        # l'axe verticale est retourné et decalé:
        target_pos[1] = height - target_pos[1]
        self.scale_XY()

        self.mw.target_pos = target_pos
        self.display_plots()

        # remettre le bouton extraire_trajectoire disabled:
        self.btn_exportCSV.setEnabled(True)

    def display_plots(self):
        self.mw.clearPlots()

        # Plot trajectory (X(t), Y(t)) :
        self.mw.onePlot.setEnabled(True)
        self.mw.onePlot.Plot()

        # Plot curves X(t) and Y(t)
        self.mw.twoPlots_xy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_xy.Plot()

        # Plot curves VX(t) and VY(t)
        self.mw.twoPlots_VxVy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_VxVy.Plot()

    def extract_images_from_video(self):
        # name of the video file without path and suffix:
        videoname = os.path.basename(self.video_path)[:-4]

        # directory where to put extracted iamges:
        self.images_dir = self.mw.image_dir + videoname + "/"

        if os.path.isdir(self.images_dir):
            print("Effacement de tous les fichiers de '{}'"\
                  .format(self.images_dir))
            for fn in os.listdir(self.images_dir):
                os.remove(self.images_dir + fn)
        else:
            os.mkdir(self.images_dir)

        video = cv2.VideoCapture(self.video_path)

        self.dico_video['nframes'] = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
        self.dico_video['size'] = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
                                   int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
        self.dico_video['fps'] = int(video.get(cv2.CAP_PROP_FPS))
        self.dico_video['duration'] = video.get(
            cv2.CAP_PROP_FRAME_COUNT) / video.get(cv2.CAP_PROP_FPS)
        self.dico_video['videoname'] = os.path.basename(self.video_path)

        self.parse_meta_data()
        self.dico_video["videoname"] = videoname + ".mp4"
        self.__setTextInfoVideoGrid()

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction des images tout en affichant une barre d'avancement :
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_video_extraction(video, self.mw.image_fmt)
        ret = pg.exec_()
        print("retour de pg.exec_() :", ret)
        if ret != 0: return

        # MAJ de la liste des fichiers images :
        self.update_images()

        # écriture des méta-data dans le fichier 'nom_video'.info
        with open(self.mw.image_dir + videoname + "/metaData.txt", "w") as F:
            F.write(str(self.dico_video))

    def computeTargetColor(self, draw_selection=False):
        col_min, row_min, col_max, row_max = self.selection.getCoords()
        print("Pixels selectionnés : lignes [{},{}] colonnes [{},{}]".\
              format(row_min, row_max, col_min, col_max))

        tab = imread(self.img_path)
        self.target_pix = tab[row_min:row_max + 1, col_min:col_max + 1, :]
        R = round(self.target_pix[:, :, 0].mean())
        G = round(self.target_pix[:, :, 1].mean())
        B = round(self.target_pix[:, :, 2].mean())
        self.mw.target_RGB = np.array([R, G, B], dtype=int)
        print(
            "RGB sélection dans <{}> :".format(os.path.basename(
                self.img_path)), self.mw.target_RGB)

        draw_selection = self.mw.flags["drawTargetSelection"]
        if draw_selection:
            self.show_image()
            print("drawTargetSelection")
            #if self.selectTargetRect is not None : del self.selectTargetRect
            # create painter instance with pixmap
            self.selectTargetRect = QPainter(self.img_lbl.pixmap())

            # set rectangle color and thickness
            self.penRectangle = QPen(QColor(0, 0, 0))
            self.penRectangle.setWidth(2)

            # draw rectangle on painter
            self.selectTargetRect.begin(self)
            self.selectTargetRect.setPen(self.penRectangle)
            self.selectTargetRect.drawRect(col_min, row_min, col_max - col_min,
                                           row_max - row_min)
            self.selectTargetRect.setOpacity(0.1)
            self.selectTargetRect.end()
            #self.show_image()

        self.btn_traj.setEnabled(True)
        self.btn_algo.setEnabled(True)
        self.btn_clear.setEnabled(True)
        self.target_color_label.setEnabled(True)
        self.picked_color.setStyleSheet(
            'background-color : rgb({},{},{})'.format(R, G, B))

    @property
    def img_idx(self):
        return self.__img_idx

    @img_idx.setter
    def img_idx(self, index):
        self.__img_idx = index
        self.image_index.setText(str(index))

    def update_images(self):
        '''Méthode à exécuter quand de nouvelles images sont apparues
           après une extraction d'images depuis une vidéo par exemple.
           Cette méthode :
           - met à jour des attributs qui dépendant de la liste des images,
           - met à jour l'état de certains boutons
           - fait afficher la première image et un message d'information.'''

        if self.images_dir is None:
            self.__img_idx = None
            #self.btn_prev.setEnabled(False)
            self.btn_prev.setStatusTip("")
            #self.btn_next.setEnabled(False)
            self.btn_next.setStatusTip("")
            self.images_step.setEnabled(False)
            self.images_firstRank.setEnabled(False)
            self.images_lastRank.setEnabled(False)

        else:
            self.buttonsState()
            self.mw.clearPlots()
            self.mw.twoPlots_VxVy.reset()

            # liste des noms des fichiers image pour avoir leur nombre :
            file_names = [ f for f in os.listdir(self.images_dir) \
                           if f.endswith('.png')]
            file_names.sort()
            self.nb_img = len(file_names)

            # Update spinBox:
            self.images_step.setEnabled(True)
            self.images_firstRank.setEnabled(True)
            self.images_lastRank.setEnabled(True)

            self.images_firstRank.setValue(1)
            self.images_step.setValue(1)
            self.images_lastRank.setValue(self.nb_img)

            self.images_firstRank.setMaximum(self.nb_img)
            self.images_lastRank.setMaximum(self.nb_img)
            self.images_step.setMaximum(self.nb_img)

            # MAJ des boutons prev et next
            self.img_idx = self.images_firstRank.value()
            self.btn_prev.setEnabled(True)
            self.btn_first.setEnabled(True)

            self.btn_prev.setStatusTip("charge l'image précédente")

            self.btn_next.setEnabled(True)
            self.btn_last.setEnabled(True)
            self.btn_next.setStatusTip("afficher "+self.mw.image_fmt.format(\
                self.img_idx+self.images_step.value()))

            self.show_image()
            self.scaleInfoVisible(True)
            self.__epsilonVisible(True)
            self.mw.tabs.setCurrentWidget(self)

            self.scale_mm.clear()
            self.scale_mm.setText("???")
            self.scale_pixel.clear()
            try:
                text = str(self.video_size[1])
            except:
                text = ""
            self.scale_pixel.setText(text)

            self.mw.twoPlots_VxVy.reset()

            if self.mw.flags["displayInfo"]:
                rep = QMessageBox.information(
                    None,             # widget parent de QMessageBox
                    'Information',    # bandeau de la fenêtre
                    'Vous pouvez maintenant sélectionner une couleur de cible'+\
                    'avec la souris...',
                    QMessageBox.Ok)

    def show_image(self):
        '''Affiche l'image dont le numéro est donné par l'attribut 'img_idx'.'''
        if self.img_idx is None:
            self.img_path = ''
        else:
            self.img_path = self.images_dir + self.mw.image_fmt.format(
                self.img_idx)
        pixmap = QPixmap(self.img_path)
        self.img_lbl.setPixmap(pixmap)
        self.img_lbl.setStatusTip(os.path.basename(self.img_path))

    def first_image(self):
        if self.img_idx == None: return
        self.img_idx = self.images_firstRank.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def prev_image(self):
        if self.img_idx == None: return
        if self.img_idx >= self.images_firstRank.value(
        ) + self.images_step.value():
            self.img_idx -= self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def last_image(self):
        if self.img_idx == None: return
        self.img_idx = self.images_lastRank.value(
        )  # rank of last image to process
        self.mw.statusBar().showMessage("")
        self.show_image()

    def next_image(self):
        if self.img_idx == None: return
        if self.img_idx <= self.images_lastRank.value(
        ) - self.images_step.value():
            self.img_idx += self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def parse_meta_data(self):
        self.video_nframes = self.dico_video.get('nframes', None)
        self.video_size = self.dico_video.get('size', None)
        self.video_FPS = self.dico_video.get('fps', None)
        self.video_duration = self.dico_video.get('duration', None)
        self.video_name = self.dico_video.get('videoname', "none.mp4")

        if self.mw.flags["debug"]:
            info = " nb images    : {},\n taille image : {},\n FPS : {} image/sec,\n durée : {.2f} sec."
            info = info.format(self.video_nframes, self.video_size,
                               self.video_FPS, self.video_duration)
            QMessageBox.about(
                None,  # widget parent de QMessageBox
                'Informations video {}'.format(self.video_name),
                info)

    def eventFilter(self, object, event):
        if object == self.img_lbl:
            if event.type() == QEvent.MouseButtonPress:
                self.mousePressInLabel(event)
                return True
            elif event.type() == QEvent.MouseButtonRelease:
                self.mouseReleaseInLabel(event)
                return True
            elif event.type() == QEvent.MouseMove:
                self.mouseMoveInLabel(event)
                return True
        return False

    def mousePressInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt1 = event.pos()
            self.pt1_rect = self.img_lbl.mapTo(self, self.pt1)
            print("\nCoord. pt1 image :", self.pt1)
            self.rubberBand.setGeometry(QRect(self.pt1_rect, QSize()))
            self.rubberBand.show()
            self.mw.statusBar().showMessage('sélection en cours....')

    def mouseMoveInLabel(self, event):
        if not self.pt1.isNull():
            pt = self.img_lbl.mapTo(self, event.pos())
            self.rubberBand.setGeometry(QRect(self.pt1_rect, pt).normalized())

    def mouseReleaseInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt2 = event.pos()
            print("Coord. pt2 image :", self.pt2)
            self.rubberBand.hide()
            self.selection = QRect(self.pt1, self.pt2).normalized()
            print(self.selection)
            self.computeTargetColor()

    def scale_XY(self):

        self.valid_scale = False
        self.pix_to_mm_coeff = 1.

        try:
            pixels = float(self.scale_pixel.text())
            mm = float(self.scale_mm.text())
        except:
            if self.mw.flags["displayInfo"]:
                info = 'Les données de conversion Pixels -> mm n\'ont pas été '
                info += 'complétées.. les ordonnées des tracés seront en pixels.'
                rep = QMessageBox.information(
                    None,  # parent de QMessageBox
                    'Info',  # bandeau de la fenêtre
                    info,
                    QMessageBox.Ok)
            return
        self.valid_scale = True
        self.pix_to_mm_coeff = mm / pixels
        print("valid scale : ", self.pix_to_mm_coeff)
    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>With <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))
    def __init__(self):
        QWidget.__init__(self)

        self.main_layout = QVBoxLayout()
        self.l = QFormLayout()
        self.l2 = QHBoxLayout()
        self.l3 = QHBoxLayout()

        self.group_box = QGroupBox('Ustawienia ogólne')
        self.group_box2 = QGroupBox('Pobieraj metadane')
        self.group_box3 = QGroupBox(
            'Pobieraj dodatkowe metadane i dołącz je do komentarza')

        # general settings
        self.max_results_label = QLabel('Maksymalna liczba wyników')
        self.max_results_label.setToolTip(
            'Maksymalna liczba pobieranych metadanych. Dla książek o nieunikalnych tytułach \
pierwszy wynik może być niepoprawny')
        self.max_results = QLineEdit(self)
        self.max_results.setValidator(QIntValidator())
        self.max_results.setText(str(PREFS['max_results']))
        self.max_results_label.setBuddy(self.max_results)
        self.l.addRow(self.max_results_label, self.max_results)

        self.authors_search_label = QLabel('Używaj autorów do wyszukiwań')
        self.authors_search_label.setToolTip(
            'Wyszukuj uwzględniając autorów. Może poprawić trafność wyników, ale błędni autorzy spowodują brak wyników'
        )
        self.authors_search = QCheckBox()
        self.authors_search.setChecked(PREFS['authors_search'])
        self.authors_search_label.setBuddy(self.authors_search)
        self.l.addRow(self.authors_search_label, self.authors_search)

        self.only_first_author_label = QLabel(
            'Używaj tylko pierwszego autora do wyszukiwania')
        self.only_first_author_label.setToolTip(
            'Używaj tylko pierwszego autora do wyszukiwań, obowiązuje tylko gdy wyszukiwanie z autorami jest aktywowane'
        )
        self.only_first_author = QCheckBox()
        self.only_first_author.setChecked(PREFS['only_first_author'])
        self.only_first_author_label.setBuddy(self.only_first_author)
        self.l.addRow(self.only_first_author_label, self.only_first_author)

        self.covers_label = QLabel('Pobieraj okładki')
        self.covers = QCheckBox()
        self.covers.setChecked(PREFS['covers'])
        self.covers_label.setBuddy(self.covers)
        self.l.addRow(self.covers_label, self.covers)

        self.max_covers_label = QLabel('Maksymalna liczba okładek')
        self.max_covers_label.setToolTip(
            'Maksymalna liczba pobieranych okładek')
        self.max_covers = QLineEdit(self)
        self.max_covers.setValidator(QIntValidator())
        self.max_covers.setText(str(PREFS['max_covers']))
        self.max_covers_label.setBuddy(self.max_covers)
        self.l.addRow(self.max_covers_label, self.max_covers)

        self.threads_label = QLabel('Wielowątkowe przetwarzanie')
        self.threads_label.setToolTip(
            'Przyśpiesza pracę używając wielu wątków')
        self.threads = QCheckBox()
        self.threads.setChecked(PREFS['threads'])
        self.threads_label.setBuddy(self.threads)
        self.l.addRow(self.threads_label, self.threads)

        self.max_threads_label = QLabel('Maksymalna liczba wątków')
        self.max_threads = QLineEdit(self)
        self.max_threads.setValidator(QIntValidator())
        self.max_threads.setText(str(PREFS['max_threads']))
        self.max_threads_label.setBuddy(self.max_threads)
        self.l.addRow(self.max_threads_label, self.max_threads)

        self.thread_delay_label = QLabel('Opóźnienie wątku')
        self.thread_delay_label.setToolTip(
            'Czas oczekiwania na uruchomienie kolejnego wątku')
        self.thread_delay = QLineEdit(self)
        self.thread_delay.setValidator(QDoubleValidator())
        self.thread_delay.setText(str(PREFS['thread_delay']))
        self.thread_delay_label.setBuddy(self.thread_delay)
        self.l.addRow(self.thread_delay_label, self.thread_delay)

        # metadata settings
        if 'title' in PREFS.defaults:
            self.title = QCheckBox('Tytuł')
            self.title.setChecked(PREFS['title'])
            self.l2.addWidget(self.title)

        if 'authors' in PREFS.defaults:
            self.authors = QCheckBox('Autorzy')
            self.authors.setChecked(PREFS['authors'])
            self.l2.addWidget(self.authors)

        if 'pubdate' in PREFS.defaults:
            self.pubdate = QCheckBox('Data wydania')
            self.pubdate.setChecked(PREFS['pubdate'])
            self.l2.addWidget(self.pubdate)

        if 'publisher' in PREFS.defaults:
            self.publisher = QCheckBox('Wydawca')
            self.publisher.setChecked(PREFS['publisher'])
            self.l2.addWidget(self.publisher)

        if 'isbn' in PREFS.defaults:
            self.isbn = QCheckBox('ISBN')
            self.isbn.setChecked(PREFS['isbn'])
            self.l2.addWidget(self.isbn)

        if 'comments' in PREFS.defaults:
            self.comments = QCheckBox('Opis')
            self.comments.setChecked(PREFS['comments'])
            self.l2.addWidget(self.comments)

        if 'languages' in PREFS.defaults:
            self.languages = QCheckBox('Języki')
            self.languages.setChecked(PREFS['languages'])
            self.l2.addWidget(self.languages)

        if 'rating' in PREFS.defaults:
            self.rating = QCheckBox('Ocena')
            self.rating.setChecked(PREFS['rating'])
            self.l2.addWidget(self.rating)

        if 'tags' in PREFS.defaults:
            self.tags = QCheckBox('Etykiety (tagi)')
            self.tags.setChecked(PREFS['tags'])
            self.l2.addWidget(self.tags)

        if 'series' in PREFS.defaults:
            self.series = QCheckBox('Cykle')
            self.series.setChecked(PREFS['series'])
            self.l2.addWidget(self.series)

        if 'identifier' in PREFS.defaults:
            self.identifier = QCheckBox('Identyfikator')
            self.identifier.setChecked(PREFS['identifier'])
            self.l2.addWidget(self.identifier)

        # custom metadata
        if 'translators' in PREFS.defaults:
            self.translators = QCheckBox('Tłumaczenie')
            self.translators.setChecked(PREFS['translators'])
            self.l3.addWidget(self.translators)

        if 'original_title' in PREFS.defaults:
            self.original_title = QCheckBox('Tytuł oryginału')
            self.original_title.setChecked(PREFS['original_title'])
            self.l3.addWidget(self.original_title)

        if 'categories' in PREFS.defaults:
            self.categories = QCheckBox('Kategorie')
            self.categories.setChecked(PREFS['categories'])
            self.l3.addWidget(self.categories)

        if 'genres' in PREFS.defaults:
            self.genres = QCheckBox('Gatunki')
            self.genres.setChecked(PREFS['genres'])
            self.l3.addWidget(self.genres)

        self.group_box.setLayout(self.l)
        self.group_box2.setLayout(self.l2)
        self.group_box3.setLayout(self.l3)
        self.main_layout.addWidget(self.group_box)
        self.main_layout.addWidget(self.group_box2)
        self.main_layout.addWidget(self.group_box3)
        self.main_layout.setAlignment(Qt.AlignTop)
        self.setLayout(self.main_layout)
Exemple #39
0
    def ask_link(self):
        class Ask(QDialog):
            def accept(self):
                if self.treat_as_image.isChecked():
                    url = self.url.text()
                    if url.lower().split(':', 1)[0] in ('http', 'https'):
                        error_dialog(
                            self,
                            _('Remote images not supported'),
                            _('You must download the image to your computer, URLs pointing'
                              ' to remote images are not supported.'),
                            show=True)
                        return
                QDialog.accept(self)

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

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

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

        # Onglet "Visualisation images"
        vbox = QVBoxLayout()

        # Ligne 1 : extraction trajec
        self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)

        line1 = QHBoxLayout()
        line1.addStretch(1)
        line1.addWidget(self.btn_algo)
        line1.addWidget(self.btn_traj)
        line1.addWidget(self.target_color_label)
        line1.addWidget(self.picked_color)
        line1.addWidget(self.btn_clear)
        line1.addWidget(self.btn_exportCSV)
        line1.addStretch(1)

        # Ligne 2 : infos video + visu image
        line2 = QHBoxLayout()

        # boîte d'infos sur la vidéo
        infoVBox = QVBoxLayout()
        for _ in ImageDisplay.video_infos:
            label = QLabel(self)
            label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
            infoVBox.addWidget(label)
            self.videoLabels.append(label)
        infoVBox.addStretch()

        widget = QLabel("Conversion pixels -> mm", self)
        self.dicoScale['Pixels-mm'] = widget
        infoVBox.addWidget(widget)

        grid = QGridLayout()
        infoVBox.addLayout(grid)

        widget = QLabel("pixels  ", self)
        self.dicoScale['pixels'] = widget
        grid.addWidget(widget, 1, 1)

        self.scale_pixel = QLineEdit(self)
        self.dicoScale['pixelsForMM'] = self.scale_pixel
        grid.addWidget(self.scale_pixel, 1, 2)

        widget = QLabel("millimètres ", self)
        self.dicoScale['millimeters'] = widget
        grid.addWidget(widget, 2, 1)

        self.scale_mm = QLineEdit(self)
        self.dicoScale['mmForPixels'] = self.scale_mm
        grid.addWidget(self.scale_mm, 2, 2)

        self.lbl_epsilon = QLabel("Epsilon ", self)
        grid.addWidget(self.lbl_epsilon, 5, 1)

        self.epsi_spin = QSpinBox(self)
        self.epsi_spin.setRange(1, 50)
        self.epsi_spin.setSingleStep(1)
        self.epsi_spin.setValue(10)
        grid.addWidget(self.epsi_spin, 5, 2)

        infoVBox.addStretch()

        line2.addLayout(infoVBox)
        line2.addStretch(1)
        line2.addWidget(self.img_lbl)  # le QLabel por afficher l'image
        line2.addStretch(1)

        # line 3 : navigation boutons
        self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.image_index.setText("       ")
        line3 = QHBoxLayout()
        line3.addStretch(1)
        line3.addWidget(self.btn_first)
        line3.addWidget(self.btn_prev)
        line3.addWidget(self.image_index)
        line3.addWidget(self.btn_next)
        line3.addWidget(self.btn_last)
        line3.addStretch(1)

        # line 4 : first , step, last image selection
        line4 = QHBoxLayout()
        line4.addStretch(1)
        line4.addWidget(self.images_firstRank)
        line4.addWidget(self.images_step)
        line4.addWidget(self.images_lastRank)
        line4.addStretch(1)

        vbox.addLayout(line1)
        vbox.addStretch(1)
        vbox.addLayout(line2)
        vbox.addStretch(1)
        vbox.addLayout(line3)
        vbox.addLayout(line4)

        self.setLayout(vbox)

        self.buttonsState()
        self.__buttonsConnect()
        self.__setVideoLabelVisible(False)
Exemple #41
0
 def __init__(self, *args):
     QLineEdit.__init__(self, *args)
     self.setValidator(QRegExpValidator(QRegExp(r'(^\d*\.[\d]{1,2}$)|(^[1-9]\d*[\.]$)'), self))
Exemple #42
0
 def focusInEvent(self, ev):
     self.select_on_mouse_press = time.time()
     return QLineEdit.focusInEvent(self, ev)
class CreateVirtualLibrary(QDialog):  # {{{

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

    def search_text_changed(self, txt):
        db = self.gui.current_db
        searches = [_('Saved searches recognized in the expression:')]
        txt = unicode_type(txt)
        while txt:
            p = txt.partition('search:')
            if p[1]:  # found 'search:'
                possible_search = p[2]
                if possible_search:  # something follows the 'search:'
                    if possible_search[0] == '"':  # strip any quotes
                        possible_search = possible_search[1:].partition('"')
                    else:  # find end of the search name. Is EOL, space, rparen
                        sp = possible_search.find(' ')
                        pp = possible_search.find(')')
                        if pp < 0 or (sp > 0 and sp <= pp):
                            # space in string before rparen, or neither found
                            possible_search = possible_search.partition(' ')
                        else:
                            # rparen in string before space
                            possible_search = possible_search.partition(')')
                    txt = possible_search[2]  # grab remainder of the string
                    search_name = possible_search[0]
                    if search_name.startswith('='):
                        search_name = search_name[1:]
                    if search_name in db.saved_search_names():
                        searches.append(search_name + '=' +
                                        db.saved_search_lookup(search_name))
                else:
                    txt = ''
            else:
                txt = ''
        if len(searches) > 1:
            self.saved_searches_label.setPlainText('\n'.join(searches))
        else:
            self.saved_searches_label.setPlainText('')

    def name_text_edited(self, new_name):
        self.new_name = unicode_type(new_name)

    def name_index_changed(self, dex):
        if self.editing and (self.vl_text.text() != self.original_search or
                             self.new_name != self.editing):
            if not question_dialog(self.gui, _('Search text changed'),
                         _('The virtual library name or the search text has changed. '
                           'Do you want to discard these changes?'),
                         default_yes=False):
                self.vl_name.blockSignals(True)
                self.vl_name.setCurrentIndex(self.original_index)
                self.vl_name.lineEdit().setText(self.new_name)
                self.vl_name.blockSignals(False)
                return
        self.new_name = self.editing = self.vl_name.currentText()
        self.original_index = dex
        self.original_search = unicode_type(self.vl_name.itemData(dex) or '')
        self.vl_text.setText(self.original_search)

    def link_activated(self, url):
        db = self.gui.current_db
        f, txt = unicode_type(url).partition('.')[0::2]
        if f == 'search':
            names = db.saved_search_names()
        else:
            names = getattr(db, 'all_%s_names'%f)()
        d = SelectNames(names, txt, parent=self)
        if d.exec_() == d.Accepted:
            prefix = f+'s' if f in {'tag', 'author'} else f
            if f == 'search':
                search = ['(%s)'%(db.saved_search_lookup(x)) for x in d.names]
            else:
                search = ['%s:"=%s"'%(prefix, x.replace('"', '\\"')) for x in d.names]
            if search:
                if not self.editing:
                    self.vl_name.lineEdit().setText(next(d.names))
                    self.vl_name.lineEdit().setCursorPosition(0)
                self.vl_text.setText(d.match_type.join(search))
                self.vl_text.setCursorPosition(0)

    def accept(self):
        n = unicode_type(self.vl_name.currentText()).strip()
        if not n:
            error_dialog(self.gui, _('No name'),
                         _('You must provide a name for the new virtual library'),
                         show=True)
            return

        if n.startswith('*'):
            error_dialog(self.gui, _('Invalid name'),
                         _('A virtual library name cannot begin with "*"'),
                         show=True)
            return

        if n in self.existing_names and n != self.editing:
            if not question_dialog(self.gui, _('Name already in use'),
                         _('That name is already in use. Do you want to replace it '
                           'with the new search?'),
                            default_yes=False):
                return

        v = unicode_type(self.vl_text.text()).strip()
        if not v:
            error_dialog(self.gui, _('No search string'),
                         _('You must provide a search to define the new virtual library'),
                         show=True)
            return

        try:
            db = self.gui.library_view.model().db
            recs = db.data.search_getting_ids('', v, use_virtual_library=False, sort_results=False)
        except ParseException as e:
            error_dialog(self.gui, _('Invalid search'),
                         _('The search in the search box is not valid'),
                         det_msg=e.msg, show=True)
            return

        if not recs and not question_dialog(
                self.gui, _('Search found no books'),
                _('The search found no books, so the virtual library '
                'will be empty. Do you really want to use that search?'),
                default_yes=False):
            return

        self.library_name = n
        self.library_search = v
        QDialog.accept(self)
Exemple #44
0
class ConverterWidget(QMainWindow):

    name = 'RWConvert'

    # For easier usage calculate the path relative to here.
    here = os.path.abspath(os.path.dirname(__file__))
    getPath = partial(os.path.join, here)

    # Setup a plugin base for "rwconvert.plugins" and make sure to load
    # all the default built-in plugins from the builtin_plugins folder.
    pluginBase = PluginBase(package='rwconvert.plugins',
                            searchpath=[getPath('./plugins')])

    plugins = {}
    filenames = []
    currentPlugin = None
    filetypes = 'All Files (*.*)'
    config = {}

    def __init__(self):
        '''
        init
        '''

        super().__init__()

        self.comms = CommSignals()
        """
        Read configuration file and return its contents
        """
        self.initConfig()
        cfgDir = self.config[PATHS]['config_path']
        self.cfgFileName = os.path.join(cfgDir,
                                        self.config[FILES]['config_name'])
        if not os.path.isfile(self.cfgFileName):
            os.makedirs(os.path.dirname(self.cfgFileName), exist_ok=True)
            self.exportConfig()
        else:
            with open(self.cfgFileName, 'r') as configFile:
                c = yaml.load(configFile)
                c = {} if c is None else c
                if c != {}:
                    self.config = c

        # and a source which loads the plugins from the "plugins"
        # folder.  We also pass the application name as identifier.  This
        # is optional but by doing this out plugins have consistent
        # internal module names which allows pickle to work.
        self.source = self.pluginBase.make_plugin_source(
            searchpath=[self.getPath('./plugins')], identifier=self.name)

        # Here we list all the plugins the source knows about, load them
        # and the use the "setup" function provided by the plugin to
        # initialize the plugin.
        for pluginName in self.source.list_plugins():
            plugin = self.source.load_plugin(pluginName)
            pluginClass = getattr(plugin, pluginName)
            instance = pluginClass(self.config, self.comms)
            self.plugins[pluginName] = instance

        self.initGui()


#         self.showFullScreen()

    def initConfig(self):
        if PATHS not in self.config: self.config[PATHS] = {}
        if FILES not in self.config: self.config[FILES] = {}
        if FORMS not in self.config: self.config[FORMS] = {}
        if NAMES not in self.config: self.config[NAMES] = {}

        self.config[PATHS]['homepath'] = os.path.expanduser('~')
        self.config[PATHS]['docpath'] = os.path.join(
            self.config[PATHS]['homepath'], 'Documents')
        self.config[PATHS]['download_path'] = os.path.join(
            self.config[PATHS]['homepath'], 'Downloads')
        self.config[PATHS]['save_path'] = os.path.join(
            self.config[PATHS]['docpath'], self.name)
        self.config[PATHS]['config_path'] = appdirs.user_config_dir(self.name)
        self.config[PATHS]['db_path'] = os.path.join(
            self.config[PATHS]['config_path'], 'data')

        self.config[FILES]['config_name'] = 'config.yaml'
        self.config[FILES]['db_name'] = 'rwconvert.sqlite'
        self.config[FILES]['save_file'] = 'roadwarrior'
        self.config[FILES]['save_ext'] = '.xlsx'

        self.config[FORMS]['include_date'] = False
        self.config[FORMS]['prefix_date'] = False
        self.config[FORMS]['include_routes'] = False
        self.config[FORMS]['combine_routes'] = False

        self.config[NAMES]['current_plugin_name'] = ''

        self.destFilename = self.config['Files']['save_file'] + self.config[
            'Files']['save_ext']

        # Create destination file directory if it doesn't already exist'
        #         if not os.path.exists(self.config[PATHS]['config_path']):
        os.makedirs(self.config[PATHS]['config_path'], exist_ok=True)
        #         if not os.path.exists(self.config[PATHS]['db_path']):
        os.makedirs(self.config[PATHS]['db_path'], exist_ok=True)
        #         if not os.path.exists(self.config[PATHS]['save_path']):
        os.makedirs(self.config[PATHS]['save_path'], exist_ok=True)

    def initGui(self):
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('Road warrior Upload File Converter')
        self.center()

        fMain = QFrame()
        mainLayout = QGridLayout()
        fMain.setLayout(mainLayout)
        self.setCentralWidget(fMain)

        tabWidget = QTabWidget()
        mainLayout.addWidget(tabWidget, 0, 0)

        self.closeBtn = QPushButton('Close Application')
        self.closeBtn.clicked.connect(self.handleCloseClicked)
        mainLayout.addWidget(self.closeBtn, 1, 0)

        tabWidget.addTab(self.initConvertPage(), 'Converter')
        tabWidget.addTab(self.initResultPage(), 'Converter')
        tabWidget.addTab(self.initConfigPage(), 'Configuration')

    def initResultPage(self):
        f = QFrame()
        l = QHBoxLayout()
        f.setLayout(l)

        self.convertedTabs = QTabWidget()
        l.addWidget(self.convertedTabs)
        '''
        This just adds a blank page with an empty tab widget.
        Pages are added on the fly when the files are converted as
        this could involve one or many pages depending on combine_route
        flag and number of routes.

        self.convertedTabs is the empty tab widget
        '''

        return f

    def initConvertPage(self):
        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        row = 0

        l.addWidget(QLabel('Converter :'), row, 0)
        currentPluginBox = QComboBox()
        currentPluginBox.currentTextChanged.connect(self.selectPlugin)
        l.addWidget(currentPluginBox, row, 1)
        for key in self.plugins.keys():
            currentPluginBox.addItem(key)
        row += 1

        l.addWidget(QLabel('Destination path :'), row, 0)
        self.destPathLbl = QLabel(
            self.joinSavePath(self.config[PATHS]['save_path'],
                              self.config[FILES]['save_file'],
                              self.config[FILES]['save_ext']))
        self.destPathLbl.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Fixed)
        l.addWidget(self.destPathLbl, row, 1)

        row += 1

        f2 = QFrame()
        l2 = QHBoxLayout()
        f2.setLayout(l2)

        f3 = QFrame()
        l3 = QGridLayout()
        f3.setLayout(l3)

        l3.addWidget(QLabel('Destination Files :'), 0, 0)
        self.destFilesList = QListWidget()
        self.destFilesList.setAlternatingRowColors(True)
        l3.addWidget(self.destFilesList, 1, 0)

        l2.addWidget(self.initFileFrame())
        l2.addWidget(f3)
        l.addWidget(f2, row, 0, 1, 3)

        row += 1

        l.addWidget(self.initSrcFiles(), row, 0, 1, 3)

        row += 1

        self.convertBtn = QPushButton('Convert')
        self.convertBtn.clicked.connect(self.handleConvertClicked)
        self.convertBtn.setEnabled(False)
        l.addWidget(self.convertBtn, row, 0, 1, 3)

        return f

    def initSrcFiles(self):

        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        l.addWidget(QLabel('Source Files :'), row, 0)
        self.srcFilesList = QListWidget()
        self.srcFilesList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.srcFilesList.setAlternatingRowColors(True)
        self.srcFilesList.model().rowsInserted.connect(
            self.handleSrcFilesChanged)
        self.srcFilesList.model().rowsRemoved.connect(
            self.handleSrcFilesChanged)
        selectionModel = self.srcFilesList.selectionModel()
        selectionModel.selectionChanged.connect(
            self.handleSrcFilesSelectionChanged)
        l.addWidget(self.srcFilesList, row, 1, 3, 1)

        self.srcFilesBtn = QPushButton('Select Files')
        self.srcFilesBtn.clicked.connect(self.handleSelectSrcFiles)
        self.srcFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.Expanding)
        l.addWidget(self.srcFilesBtn, row, 2)
        row += 1

        self.addFilesBtn = QPushButton('Add Files')
        self.addFilesBtn.clicked.connect(self.handleAddSrcFiles)
        self.addFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.Expanding)
        l.addWidget(self.addFilesBtn, row, 2)
        row += 1

        self.removeFilesBtn = QPushButton('Remove Files')
        self.removeFilesBtn.setEnabled(False)
        self.removeFilesBtn.clicked.connect(self.handleRemoveSrcFiles)
        self.removeFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                          QSizePolicy.Expanding)
        l.addWidget(self.removeFilesBtn, row, 2)
        row += 1

        self.errorEdit = QPlainTextEdit()
        self.errorEdit.setReadOnly(True)
        l.addWidget(self.errorEdit, row, 1, 1, 2)
        self.comms.errorSignal.connect(self.errorEdit.appendPlainText)

        return f

    def initFileFrame(self):
        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)
        #         f.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        l.addWidget(QLabel('Destination File :'), row, 0)
        self.destFilenameEdit = QLineEdit(self.destFilename)
        self.destFilenameEdit.setEnabled(False)
        self.destFilenameEdit.textChanged.connect(
            self.handleDestFilenameChanged)
        l.addWidget(self.destFilenameEdit, row, 1)
        row += 1

        self.combineRoutesBox = QCheckBox('combine_routes')
        if self.config[FORMS]['combine_routes']:
            self.combineRoutesBox.setChecked(True)
        else:
            self.combineRoutesBox.setChecked(False)
        self.combineRoutesBox.clicked.connect(self.handleCombineRoutesClicked)
        self.combineRoutesBox.setEnabled(False)
        l.addWidget(self.combineRoutesBox, row, 0)
        row += 1

        addDateInNameBox = QCheckBox('Add date to filename')
        addDateInNameBox.clicked.connect(self.handleAddDateClicked)
        l.addWidget(addDateInNameBox, row, 0)
        if self.config[FORMS]['prefix_date']:
            self.prefixDateInNameBox = QPushButton('prefix_date')
            self.prefixDateInNameBox.setEnabled(False)
        else:
            self.prefixDateInNameBox = QPushButton('Suffix date')
            self.prefixDateInNameBox.setEnabled(False)
        self.prefixDateInNameBox.setToolTip('Click to change to prefix date.')
        self.prefixDateInNameBox.clicked.connect(self.handlePrefixDateClicked)

        l.addWidget(self.prefixDateInNameBox, row, 1)
        row += 1

        addRouteInNameBox = QCheckBox('Add route to filename')
        addRouteInNameBox.clicked.connect(self.handleAddRouteClicked)
        l.addWidget(addRouteInNameBox, row, 0)
        #         row += 1

        return f

    def initConfigPage(self):
        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        srcLbl = QLabel('Source directory :')
        srcLbl.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(srcLbl, row, 0)

        self.srcDirBox = QLineEdit()
        self.srcDirBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.srcDirBox.setText(self.config[PATHS]['download_path'])
        l.addWidget(self.srcDirBox, row, 1)

        srcDirSelectBtn = QPushButton('Select')
        srcDirSelectBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        srcDirSelectBtn.clicked.connect(self.handleSelectSrcDirectory)
        l.addWidget(srcDirSelectBtn, row, 2)

        row += 1

        destLbl = QLabel('Destination directory :')
        destLbl.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(destLbl, row, 0)

        self.destDirBox = QLineEdit()
        self.destDirBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.destDirBox.setText(self.config[PATHS]['save_path'])
        l.addWidget(self.destDirBox, row, 1)

        destDirSelectBtn = QPushButton('Select')
        destDirSelectBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        destDirSelectBtn.clicked.connect(self.handleSelectDestDirectory)
        l.addWidget(destDirSelectBtn, row, 2)

        row += 1

        l.addWidget(QFrame(), row, 0, 1, 3)

        return f

    def handleSelectSrcDirectory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 'Select Source Directory',
            self.config[PATHS]['download_path'], QFileDialog.ShowDirsOnly)
        if not directory == '':
            self.config[PATHS]['download_path'] = directory
            self.srcDirBox.setText(directory)

    def handleSelectDestDirectory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 'Select Destination Directory',
            self.config[PATHS]['save_path'], QFileDialog.ShowDirsOnly)
        if not directory == '':
            self.config[PATHS]['save_path'] = directory
            self.destDirBox.setText(directory)

    def joinSavePath(self, path, filename, ext):
        newpath = os.path.join(path, filename)
        newpath += ext
        return newpath

    @pyqtSlot(bool)
    def handleAddDateClicked(self, checked):
        if checked:
            self.config[FORMS]['include_path'] = True
            self.prefixDateInNameBox.setEnabled(True)
        else:
            self.config[FORMS]['include_path'] = False
            self.prefixDateInNameBox.setEnabled(False)

    @pyqtSlot()
    def handlePrefixDateClicked(self):
        if self.config[FORMS]['prefix_date']:
            self.config[FORMS]['prefix_date'] = False
            self.prefixDateInNameBox.setText('Suffix date')
            self.prefixDateInNameBox.setToolTip(
                'Click to change to prefix date.')
        else:
            self.config[FORMS]['prefix_date'] = True
            self.prefixDateInNameBox.setText('Prefix date')
            self.prefixDateInNameBox.setToolTip(
                'Click to change to suffix date.')

    @pyqtSlot()
    def handleAddRouteClicked(self, checked):
        if checked:
            self.config[FORMS]['include_routes'] = True
        else:
            self.config[FORMS]['include_routes'] = False

    @pyqtSlot()
    def handleCombineRoutesClicked(self):
        if self.combineRoutesBox.isChecked():
            self.config[FORMS]['combine_routes'] = True
        else:
            self.config[FORMS]['combine_routes'] = False

        self.enableStuff()

    def enableStuff(self):
        if self.srcFilesList.model().rowCount() == 0:
            self.convertBtn.setEnabled(False)
            self.combineRoutesBox.setEnabled(False)
            self.destFilenameEdit.setEnabled(False)
        elif self.srcFilesList.model().rowCount() == 1:
            self.convertBtn.setEnabled(True)
            self.combineRoutesBox.setEnabled(False)
            self.destFilenameEdit.setEnabled(True)
        else:
            self.convertBtn.setEnabled(True)
            self.combineRoutesBox.setEnabled(True)
            if self.combineRoutesBox.isChecked():
                self.destFilenameEdit.setEnabled(True)
            else:
                self.destFilenameEdit.setEnabled(False)

    @pyqtSlot()
    def handleDestFilenameChanged(self, text):
        if len(text) > 0:
            if self.config[PATHS]['include_path']:
                year = datetime.year
                month = datetime.month
                day = datetime.day
                datestr = str(year)
                if month < 10: datestr += '0'
                datestr += str(month)
                if day < 10: datestr += '0'
                datestr += str(day)
                if self.config[FORMS]['prefix_date']:
                    name = datestr + '_' + text
                else:
                    name = text + '_' + datestr
            else:
                name = text

            self.config[FILES]['save file'] = name
            self.destPathLbl.setText(
                self.joinSavePath(self.savepath, self.savefile, self.saveext))

    def createDestinationFilePath(self):
        return self.joinSavePath(self.savepath, self.savefile, self.saveext)

    @pyqtSlot()
    def handleSrcFilesSelectionChanged(self, selected):
        if len(selected.indexes()) > 0:
            self.removeFilesBtn.setEnabled(True)
        else:
            self.removeFilesBtn.setEnabled(False)

    @pyqtSlot()
    def handleSrcFilesChanged(self):
        self.enableStuff()

    @pyqtSlot()
    def handleConvertClicked(self):
        if len(self.filenames) > 0:
            toexcel = ToExcel()

            self.currentPlugin.convert(self.filenames)
            routedata = self.currentPlugin.data

            if self.config[FORMS]['combine_routes']:
                combined = []
                for route in routedata.keys():
                    singleroute = routedata[route]
                    combined += singleroute
                path = self.joinSavePath(self.config[PATHS]['save_path'],
                                         self.config[FILES]['save_file'],
                                         self.config[FILES]['save_ext'])
                toexcel.create_workbook(combined, path)
                self.destFilesList.addItem(path)

            else:
                i = 1
                for route in routedata.keys():
                    singleroute = routedata[route]
                    if self.config[FORMS]['include_routes'] and len(route) > 0:
                        path = self.joinSavePath(
                            self.config[PATHS]['save_path'],
                            self.config[FILES]['save_file'] + '_' + route,
                            self.config[FILES]['save_ext'])
                    else:
                        path = self.joinSavePath(
                            self.config[PATHS]['save_path'],
                            self.config[FILES]['save_file'] + '(' + str(i) +
                            ')', self.config[FILES]['save_ext'])
                        i += 1

                    toexcel.create_workbook(singleroute, path)
                    self.destFilesList.addItem(path)

    @pyqtSlot()
    def handleConverterChanged(self):
        pluginName = self.currentPluginBox.currentText()
        if pluginName != self.config[NAMES]['current_plugin_name']:
            self.config[NAMES]['current_plugin_name'] = pluginName
            self.currentPlugin = self.plugins[pluginName]
            self.filetypes = self.currentPlugin.filetypes

    @pyqtSlot()
    def handleCloseClicked(self):
        self.close()

    @pyqtSlot()
    def handleSelectSrcFiles(self):
        fileDlg = QFileDialog(self, 'Select Files',
                              self.config[PATHS]['download_path'],
                              self.filetypes)
        fileDlg.setFileMode(QFileDialog.ExistingFiles)

        if fileDlg.exec_():
            self.filenames = fileDlg.selectedFiles()

        self.srcFilesList.clear()
        self.srcFilesList.addItems(self.filenames)

    @pyqtSlot()
    def handleAddSrcFiles(self):
        fileDlg = QFileDialog(self, 'Select Files',
                              self.config[PATHS]['download_path'],
                              self.filetypes)
        fileDlg.setFileMode(QFileDialog.ExistingFiles)

        if fileDlg.exec_():
            for filename in fileDlg.selectedFiles():
                if filename not in self.filenames:
                    self.filenames.append(filename)
                    self.srcFilesList.addItem(filename)

    @pyqtSlot()
    def handleRemoveSrcFiles(self):
        selectedModel = self.srcFilesList.selectionModel()
        selected = selectedModel.selectedIndexes()
        for index in selected:
            name = index.data()
            self.filenames.remove(name)
            self.srcFilesList.takeItem(index.row())
        selectedModel.clear()

    @pyqtSlot(str)
    def selectPlugin(self, name):
        # activate the current plugin
        #             self.pluginManager.activatePluginByName(name)
        self.config[NAMES]['current_plugin_name'] = name
        self.currentPlugin = self.plugins[name]
        self.filetypes = self.currentPlugin.filetypes

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def exportConfig(self):
        with open(self.cfgFileName, 'w') as configFile:
            yaml.dump(self.config, configFile)

    def createUserConfig(self):
        """
        Create the user's config file in OS specific location
        """
        os.makedirs(os.path.dirname(self.cfgFileName), exist_ok=True)
        self.exportConfig()

    def closeEvent(self, event):
        buttonReply = QMessageBox.warning(
            self, 'Close Application',
            'You are about to close the Application,'
            ' Press Yes to continue or Cancel to return to the Application',
            QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)
        if buttonReply == QMessageBox.Yes:
            self.exportConfig()
            exit()
Exemple #45
0
    def __init__(self, handler, data):
        '''Ask user for 2nd factor authentication. Support text, security card and paired mobile methods.
        Use last method from settings, but support new pairing and downgrade.
        '''
        QDialog.__init__(self, handler.top_level_window())
        self.handler = handler
        self.txdata = data
        self.idxs = self.txdata[
            'keycardData'] if self.txdata['confirmationType'] > 1 else ''
        self.setMinimumWidth(650)
        self.setWindowTitle(_("Ledger Wallet Authentication"))
        self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg)
        self.dongle = self.handler.win.wallet.get_keystore().get_client(
        ).dongle
        self.ws = None
        self.pin = ''

        self.devmode = self.getDevice2FAMode()
        if self.devmode == 0x11 or self.txdata['confirmationType'] == 1:
            self.cfg['mode'] = 0

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        def on_change_mode(idx):
            if idx < 2 and self.ws:
                self.ws.stop()
                self.ws = None
            self.cfg[
                'mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1
            if self.cfg['mode'] > 1 and self.cfg['pair'] and not self.ws:
                self.req_validation()
            if self.cfg['mode'] > 0:
                self.handler.win.wallet.get_keystore().cfg = self.cfg
                self.handler.win.wallet.save_keystore()
            self.update_dlg()

        def add_pairing():
            self.do_pairing()

        def return_pin():
            self.pin = self.pintxt.text(
            ) if self.txdata['confirmationType'] == 1 else self.cardtxt.text()
            if self.cfg['mode'] == 1:
                self.pin = ''.join(chr(int(str(i), 16)) for i in self.pin)
            self.accept()

        self.modebox = QWidget()
        modelayout = QHBoxLayout()
        self.modebox.setLayout(modelayout)
        modelayout.addWidget(QLabel(_("Method:")))
        self.modes = QComboBox()
        modelayout.addWidget(self.modes, 2)
        self.addPair = QPushButton(_("Pair"))
        self.addPair.setMaximumWidth(60)
        modelayout.addWidget(self.addPair)
        modelayout.addStretch(1)
        self.modebox.setMaximumHeight(50)
        vbox.addWidget(self.modebox)

        self.populate_modes()
        self.modes.currentIndexChanged.connect(on_change_mode)
        self.addPair.clicked.connect(add_pairing)

        self.helpmsg = QTextEdit()
        self.helpmsg.setStyleSheet(
            "QTextEdit { background-color: lightgray; }")
        self.helpmsg.setReadOnly(True)
        vbox.addWidget(self.helpmsg)

        self.pinbox = QWidget()
        pinlayout = QHBoxLayout()
        self.pinbox.setLayout(pinlayout)
        self.pintxt = QLineEdit()
        self.pintxt.setEchoMode(2)
        self.pintxt.setMaxLength(4)
        self.pintxt.returnPressed.connect(return_pin)
        pinlayout.addWidget(QLabel(_("Enter PIN:")))
        pinlayout.addWidget(self.pintxt)
        pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        pinlayout.addStretch(1)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        vbox.addWidget(self.pinbox)

        self.cardbox = QWidget()
        card = QVBoxLayout()
        self.cardbox.setLayout(card)
        self.addrtext = QTextEdit()
        self.addrtext.setStyleSheet(
            "QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family:monospace; }"
        )
        self.addrtext.setReadOnly(True)
        self.addrtext.setMaximumHeight(130)
        card.addWidget(self.addrtext)

        def pin_changed(s):
            if len(s) < len(self.idxs):
                i = self.idxs[len(s)]
                addr = self.txdata['address']
                if not constants.net.TESTNET:
                    text = addr[:i] + '<u><b>' + addr[
                        i:i + 1] + '</u></b>' + addr[i + 1:]
                else:
                    # pin needs to be created from mainnet address
                    addr_mainnet = bitcoin.script_to_address(
                        bitcoin.address_to_script(addr),
                        net=constants.BitcoinMainnet)
                    addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[
                        i:i + 1] + '</u></b>' + addr_mainnet[i + 1:]
                    text = str(addr) + '\n' + str(addr_mainnet)
                self.addrtext.setHtml(str(text))
            else:
                self.addrtext.setHtml(_("Press Enter"))

        pin_changed('')
        cardpin = QHBoxLayout()
        cardpin.addWidget(QLabel(_("Enter PIN:")))
        self.cardtxt = QLineEdit()
        self.cardtxt.setEchoMode(2)
        self.cardtxt.setMaxLength(len(self.idxs))
        self.cardtxt.textChanged.connect(pin_changed)
        self.cardtxt.returnPressed.connect(return_pin)
        cardpin.addWidget(self.cardtxt)
        cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        cardpin.addStretch(1)
        card.addLayout(cardpin)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        vbox.addWidget(self.cardbox)

        self.pairbox = QWidget()
        pairlayout = QVBoxLayout()
        self.pairbox.setLayout(pairlayout)
        pairhelp = QTextEdit(helpTxt[5])
        pairhelp.setStyleSheet("QTextEdit { background-color: lightgray; }")
        pairhelp.setReadOnly(True)
        pairlayout.addWidget(pairhelp, 1)
        self.pairqr = QRCodeWidget()
        pairlayout.addWidget(self.pairqr, 4)
        self.pairbox.setVisible(False)
        vbox.addWidget(self.pairbox)
        self.update_dlg()

        if self.cfg['mode'] > 1 and not self.ws:
            self.req_validation()
Exemple #46
0
    def do_user_config(self, parent=None):
        '''
        This method shows a configuration dialog for this plugin. It returns
        True if the user clicks OK, False otherwise. The changes are
        automatically applied.
        '''
        from PyQt5.Qt import QDialog, QDialogButtonBox, QVBoxLayout, \
                QLabel, Qt, QLineEdit
        from calibre.gui2 import gprefs

        prefname = 'plugin config dialog:' + self.type + ':' + self.name
        geom = gprefs.get(prefname, None)

        config_dialog = QDialog(parent)
        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        v = QVBoxLayout(config_dialog)

        def size_dialog():
            if geom is None:
                config_dialog.resize(config_dialog.sizeHint())
            else:
                config_dialog.restoreGeometry(geom)

        button_box.accepted.connect(config_dialog.accept)
        button_box.rejected.connect(config_dialog.reject)
        config_dialog.setWindowTitle(_('Customize') + ' ' + self.name)
        try:
            config_widget = self.config_widget()
        except NotImplementedError:
            config_widget = None

        if isinstance(config_widget, tuple):
            from calibre.gui2 import warning_dialog
            warning_dialog(parent,
                           _('Cannot configure'),
                           config_widget[0],
                           det_msg=config_widget[1],
                           show=True)
            return False

        if config_widget is not None:
            v.addWidget(config_widget)
            v.addWidget(button_box)
            size_dialog()
            config_dialog.exec_()

            if config_dialog.result() == QDialog.Accepted:
                if hasattr(config_widget, 'validate'):
                    if config_widget.validate():
                        self.save_settings(config_widget)
                else:
                    self.save_settings(config_widget)
        else:
            from calibre.customize.ui import plugin_customization, \
                customize_plugin
            help_text = self.customization_help(gui=True)
            help_text = QLabel(help_text, config_dialog)
            help_text.setWordWrap(True)
            help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse
                                              | Qt.LinksAccessibleByKeyboard)
            help_text.setOpenExternalLinks(True)
            v.addWidget(help_text)
            sc = plugin_customization(self)
            if not sc:
                sc = ''
            sc = sc.strip()
            sc = QLineEdit(sc, config_dialog)
            v.addWidget(sc)
            v.addWidget(button_box)
            size_dialog()
            config_dialog.exec_()

            if config_dialog.result() == QDialog.Accepted:
                sc = str(sc.text()).strip()
                customize_plugin(self, sc)

        geom = bytearray(config_dialog.saveGeometry())
        gprefs[prefname] = geom

        return config_dialog.result()
Exemple #47
0
 def paste(self, *args):
     self.parent().normalize_state()
     return QLineEdit.paste(self)
Exemple #48
0
 def dropEvent(self, ev):
     self.parent().normalize_state()
     return QLineEdit.dropEvent(self, ev)
Exemple #49
0
 def keyPressEvent(self, event):
     self.key_pressed.emit(event)
     QLineEdit.keyPressEvent(self, event)
    def setup_ui(self):  # {{{
        self.setWindowModality(Qt.ApplicationModal)
        self.setWindowIcon(QIcon(I('column.png')))
        self.vl = l = QVBoxLayout(self)
        self.heading_label = la = QLabel('')
        l.addWidget(la)
        self.shortcuts = s = QLabel('')
        s.setWordWrap(True)
        s.linkActivated.connect(self.shortcut_activated)
        text = '<p>' + _('Quick create:')
        for col, name in [('isbn', _('ISBN')), ('formats', _('Formats')),
                          ('yesno', _('Yes/No')), ('tags', _('Tags')),
                          ('series', _('Series')), ('rating', _('Rating')),
                          ('people', _("Names")), ('text', _('Short text'))]:
            text += ' <a href="col:%s">%s</a>,' % (col, name)
        text = text[:-1]
        s.setText(text)
        l.addWidget(s)
        self.g = g = QGridLayout()
        l.addLayout(g)
        l.addStretch(10)
        self.button_box = bb = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        bb.accepted.connect(self.accept), bb.rejected.connect(self.reject)
        l.addWidget(bb)

        def add_row(text, widget):
            if text is None:
                f = g.addWidget if isinstance(widget, QWidget) else g.addLayout
                f(widget, g.rowCount(), 0, 1, -1)
                return

            row = g.rowCount()
            la = QLabel(text)
            g.addWidget(la, row, 0, 1, 1)
            if isinstance(widget, QWidget):
                la.setBuddy(widget)
                g.addWidget(widget, row, 1, 1, 1)
            else:
                widget.setContentsMargins(0, 0, 0, 0)
                g.addLayout(widget, row, 1, 1, 1)
                for i in range(widget.count()):
                    w = widget.itemAt(i).widget()
                    if isinstance(w, QWidget):
                        la.setBuddy(w)
                        break
            return la

        # Lookup name
        self.column_name_box = cnb = QLineEdit(self)
        cnb.setToolTip(
            _("Used for searching the column. Must contain only digits and lower case letters."
              ))
        add_row(_("&Lookup name"), cnb)

        # Heading
        self.column_heading_box = chb = QLineEdit(self)
        chb.setToolTip(
            _("Column heading in the library view and category name in the tag browser"
              ))
        add_row(_("Column &heading"), chb)

        # Column Type
        h = QHBoxLayout()
        self.column_type_box = ctb = QComboBox(self)
        ctb.setMinimumWidth(70)
        ctb.setToolTip(
            _("What kind of information will be kept in the column."))
        h.addWidget(ctb)
        self.use_decorations = ud = QCheckBox(_("Show &checkmarks"), self)
        ud.setToolTip(
            _("Show check marks in the GUI. Values of 'yes', 'checked', and 'true'\n"
              "will show a green check. Values of 'no', 'unchecked', and 'false' will show a red X.\n"
              "Everything else will show nothing."))
        h.addWidget(ud)
        self.is_names = ins = QCheckBox(_("Contains names"), self)
        ins.setToolTip(
            _("Check this box if this column contains names, like the authors column."
              ))
        h.addWidget(ins)
        add_row(_("&Column type"), h)

        # Description
        self.description_box = d = QLineEdit(self)
        d.setToolTip(_("Optional text describing what this column is for"))
        add_row(_("D&escription"), d)

        # Date/number formatting
        h = QHBoxLayout()
        self.format_box = fb = QLineEdit(self)
        h.addWidget(fb)
        self.format_default_label = la = QLabel('')
        la.setOpenExternalLinks(True)
        h.addWidget(la)
        self.format_label = add_row('', h)

        # Template
        self.composite_box = cb = QLineEdit(self)
        self.composite_default_label = cdl = QLabel(_("Default: (nothing)"))
        cb.setToolTip(
            _("Field template. Uses the same syntax as save templates."))
        cdl.setToolTip(
            _("Similar to save templates. For example, %s") % "{title} {isbn}")
        h = QHBoxLayout()
        h.addWidget(cb), h.addWidget(cdl)
        self.composite_label = add_row(_("&Template"), h)

        # Comments properties
        self.comments_heading_position = ct = QComboBox(self)
        for k, text in (('hide', _('No heading')),
                        ('above', _('Show heading above the text')),
                        ('side', _('Show heading to the side of the text'))):
            ct.addItem(text, k)
        ct.setToolTip(
            _('Choose whether or not the column heading is shown in the Book\n'
              'Details panel and, if shown, where'))
        self.comments_heading_position_label = add_row(_('Column heading'), ct)

        self.comments_type = ct = QComboBox(self)
        for k, text in (('html', 'HTML'), ('short-text',
                                           _('Short text, like a title')),
                        ('long-text', _('Plain text')),
                        ('markdown',
                         _('Plain text formatted using markdown'))):
            ct.addItem(text, k)
        ct.setToolTip(
            _('Choose how the data in this column is interpreted.\n'
              'This controls how the data is displayed in the Book Details panel\n'
              'and how it is edited.'))
        self.comments_type_label = add_row(
            _('Interpret this column as:') + ' ', ct)

        # Values for enum type
        l = QGridLayout()
        self.enum_box = eb = QLineEdit(self)
        eb.setToolTip(
            _("A comma-separated list of permitted values. The empty value is always\n"
              "included, and is the default. For example, the list 'one,two,three' has\n"
              "four values, the first of them being the empty value."))
        self.enum_default_label = la = QLabel(_("Values"))
        la.setBuddy(eb)
        l.addWidget(eb), l.addWidget(la, 0, 1)
        self.enum_colors = ec = QLineEdit(self)
        ec.setToolTip(
            _("A list of color names to use when displaying an item. The\n"
              "list must be empty or contain a color for each value."))
        self.enum_colors_label = la = QLabel(_('Colors'))
        la.setBuddy(ec)
        l.addWidget(ec), l.addWidget(la, 1, 1)
        self.enum_label = add_row(_('&Values'), l)

        # Rating allow half stars
        self.allow_half_stars = ahs = QCheckBox(_('Allow half stars'))
        ahs.setToolTip(
            _('Allow half star ratings, for example: ') +
            '<span style="font-family:calibre Symbols">★★★½</span>')
        add_row(None, ahs)

        # Composite display properties
        l = QHBoxLayout()
        self.composite_sort_by_label = la = QLabel(_("&Sort/search column by"))
        self.composite_sort_by = csb = QComboBox(self)
        la.setBuddy(csb), csb.setToolTip(
            _("How this column should handled in the GUI when sorting and searching"
              ))
        l.addWidget(la), l.addWidget(csb)
        self.composite_make_category = cmc = QCheckBox(
            _("Show in tags browser"))
        cmc.setToolTip(
            _("If checked, this column will appear in the tags browser as a category"
              ))
        l.addWidget(cmc)
        self.composite_contains_html = cch = QCheckBox(
            _("Show as HTML in book details"))
        cch.setToolTip(
            '<p>' +
            _('If checked, this column will be displayed as HTML in '
              'book details and the content server. This can be used to '
              'construct links with the template language. For example, '
              'the template '
              '<pre>&lt;big&gt;&lt;b&gt;{title}&lt;/b&gt;&lt;/big&gt;'
              '{series:| [|}{series_index:| [|]]}</pre>'
              'will create a field displaying the title in bold large '
              'characters, along with the series, for example <br>"<big><b>'
              'An Oblique Approach</b></big> [Belisarius [1]]". The template '
              '<pre>&lt;a href="http://www.beam-ebooks.de/ebook/{identifiers'
              ':select(beam)}"&gt;Beam book&lt;/a&gt;</pre> '
              'will generate a link to the book on the Beam ebooks site.') +
            '</p>')
        l.addWidget(cch)
        add_row(None, l)

        self.resize(self.sizeHint())
Exemple #51
0
    def setup_ui(self):
        self.l = l = QVBoxLayout(self)
        self.setLayout(l)

        self.h = h = QHBoxLayout()
        l.addLayout(h)

        names = [n for n, linear in self.container.spine_names]
        fn, f = create_filterable_names_list(names,
                                             filter_text=_('Filter files'),
                                             parent=self)
        self.file_names, self.file_names_filter = fn, f
        fn.selectionModel().selectionChanged.connect(
            self.selected_file_changed)
        self.fnl = fnl = QVBoxLayout()
        self.la1 = la = QLabel(_('Choose a &file to link to:'))
        la.setBuddy(fn)
        fnl.addWidget(la), fnl.addWidget(f), fnl.addWidget(fn)
        h.addLayout(fnl), h.setStretch(0, 2)

        fn, f = create_filterable_names_list([],
                                             filter_text=_('Filter locations'),
                                             parent=self,
                                             model=AnchorsModel)
        fn.setSpacing(5)
        self.anchor_names, self.anchor_names_filter = fn, f
        fn.selectionModel().selectionChanged.connect(self.update_target)
        fn.doubleClicked.connect(self.accept, type=Qt.QueuedConnection)
        self.anl = fnl = QVBoxLayout()
        self.la2 = la = QLabel(_('Choose a &location (anchor) in the file:'))
        la.setBuddy(fn)
        fnl.addWidget(la), fnl.addWidget(f), fnl.addWidget(fn)
        h.addLayout(fnl), h.setStretch(1, 1)

        self.tl = tl = QFormLayout()
        tl.setFieldGrowthPolicy(tl.AllNonFixedFieldsGrow)
        self.target = t = QLineEdit(self)
        t.setPlaceholderText(_('The destination (href) for the link'))
        tl.addRow(_('&Target:'), t)
        l.addLayout(tl)

        self.text_edit = t = QLineEdit(self)
        la.setBuddy(t)
        tl.addRow(_('Te&xt:'), t)
        t.setText(self.initial_text or '')
        t.setPlaceholderText(_('The (optional) text for the link'))

        self.template_edit = t = HistoryComboBox(self)
        t.lineEdit().setClearButtonEnabled(True)
        t.initialize('edit_book_insert_link_template_history')
        tl.addRow(_('Tem&plate:'), t)
        from calibre.gui2.tweak_book.editor.smarts.html import DEFAULT_LINK_TEMPLATE
        t.setText(
            tprefs.get('insert-hyperlink-template', None)
            or DEFAULT_LINK_TEMPLATE)
        t.setToolTip('<p>' + _('''
            The template to use for generating the link. In addition to {0} and {1}
            you can also use {2}, {3} and {4} variables
            in the template, they will be replaced by the source filename, the destination
            filename and the anchor, respectively.
        ''').format('_TITLE_', '_TARGET', '_SOURCE_FILENAME_',
                    '_DEST_FILENAME_', '_ANCHOR_'))

        l.addWidget(self.bb)