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))
class ConfigWidget(QWidget):
    def __init__(self):

        QWidget.__init__(self)
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.AuthLayout = QHBoxLayout()
        self.layout.addLayout(self.AuthLayout)

        self.AuthLabel = QLabel('Auth token:')
        self.AuthLayout.addWidget(self.AuthLabel)

        self.AuthMsg = QLineEdit(self)
        self.AuthMsg.setText(prefs['cookie_auth_token'])
        self.AuthLayout.addWidget(self.AuthMsg)
        self.AuthLabel.setBuddy(self.AuthMsg)

        self.DownloadLayout = QHBoxLayout()
        self.layout.addLayout(self.DownloadLayout)

        self.DownloadLabel = QLabel('Download location:')
        self.DownloadLayout.addWidget(self.DownloadLabel)

        self.DownloadMsg = QLineEdit(self)
        self.DownloadMsg.setText(prefs['download_loc'])
        self.DownloadLayout.addWidget(self.DownloadMsg)
        self.DownloadLabel.setBuddy(self.DownloadMsg)

    def save_settings(self):
        prefs['cookie_auth_token'] = unicode(self.AuthMsg.text())
        prefs['download_loc'] = unicode(self.DownloadMsg.text())
Exemple #3
0
class ConfigWidget(QWidget):

    def __init__(self, rm_client):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)
        self.rm_client = rm_client

        if self.rm_client.is_registered():
            self.label = QLabel('Device is already registered')
            self.l.addWidget(self.label)
        else:
            self.label = QLabel(
                'Retrieve one-time registration code from <a href="https://my.remarkable.com/connect/remarkable">https://my.remarkable.com/connect/remarkable</a>:')
            self.label.setOpenExternalLinks(True)
            self.l.addWidget(self.label)

            self.registration_code = QLineEdit(self)
            self.l.addWidget(self.registration_code)
            self.label.setBuddy(self.registration_code)

    def validate(self):
        if self.rm_client.is_registered():
            return True

        # TODO: waiting screen when waiting for registration ?
        if self.registration_code.text():
            return self.rm_client.register_device(self.registration_code.text())
        return True

    def save_settings(self):
        dump()
class ConfigWidget(QWidget):

    def __init__(self, config):
        QWidget.__init__(self)
        self.create_ui()
        self.urlField.setText(config.get('url', ''))
        self.usernameField.setText(config.get('user', ''))
        self.passwordField.setText(config.get('pass', ''))

    def create_ui(self):
        self.urlField = QLineEdit()
        self.usernameField = QLineEdit()
        self.passwordField = QLineEdit()
        layout = QFormLayout()
        layout.addRow("URL:", self.urlField)
        layout.addRow("Username:"******"Password:", self.passwordField)
        self.setLayout(layout)

    def url(self):
        return self.urlField.text()

    def username(self):
        return self.usernameField.text()

    def password(self):
        return self.passwordField.text()
    def createWordDialog(self, word=Word('')):
        dialog = QDialog(self)
        layout = QGridLayout(self)

        dialog.setLayout(layout)
        shortEdit = QLineEdit(word.short)
        longEdit = QLineEdit(word.long)
        explainEdit = QLineEdit(word.explain)
        okButton = QPushButton('OK')
        okButton.clicked.connect(dialog.accept)
        cancelButton = QPushButton('Cancel')
        cancelButton.clicked.connect(dialog.reject)

        layout.addWidget(QLabel('Short'), 0, 0)
        layout.addWidget(shortEdit, 0, 1)
        layout.addWidget(QLabel('Long'), 1, 0)
        layout.addWidget(longEdit, 1, 1)
        layout.addWidget(QLabel('Translate'), 2, 0)
        layout.addWidget(explainEdit, 2, 1)
        layout.addWidget(okButton, 3, 0)
        layout.addWidget(cancelButton, 3, 1)

        dialog.exec()
        if (dialog.result() == QDialog.Accepted):
            word = Word(
                '%s,%s,%s' %
                (shortEdit.text(), longEdit.text(), explainEdit.text()))
            self.dictionary.append(word)
            self.dictionary.save()
            self.updateTable(self.dictionary.words)
Exemple #6
0
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.label = QLabel(
            'Retrieve one-time registration code from <a href="https://my.remarkable.com/connect/remarkable">https://my.remarkable.com/connect/remarkable</a>:'
        )
        self.label.setOpenExternalLinks(True)
        self.l.addWidget(self.label)

        self.registration_code = QLineEdit(self)
        self.l.addWidget(self.registration_code)
        self.label.setBuddy(self.registration_code)

    def validate(self):
        if self.registration_code.text():
            from calibre_plugins.remarkable_cloud.rmapy.api import Client
            rm_client = Client()
            return rm_client.register_device(self.registration_code.text())
        return True

    def save_settings(self):
        pass
Exemple #7
0
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.l = QHBoxLayout()
        self.layout.addLayout(self.l)

        self.l = QHBoxLayout()
        self.layout.addLayout(self.l)
        self.label = QLabel('epub tag')
        self.l.addWidget(self.label)

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

        self.l = QHBoxLayout()
        self.layout.addLayout(self.l)
        self.label = QLabel('search result limit:')
        self.l.addWidget(self.label)

        self.search_result_count = QLineEdit(self)
        self.search_result_count.setValidator(
            QIntValidator(self.search_result_count))
        self.search_result_count.setText(prefs['search_result_count'])
        self.l.addWidget(self.search_result_count)
        self.label.setBuddy(self.search_result_count)

    def save_settings(self):
        prefs['tags'] = self.tags.text()
        prefs['search_result_count'] = self.search_result_count.text()
Exemple #8
0
class ConfigWidget(QWidget):

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

        self.about_button = QPushButton('Help', self)
        self.about_button.clicked.connect(self.about)
        self.l.addWidget(self.about_button)

        self.notebookLabel = QLabel('evernote Notebook')
        self.l.addWidget(self.notebookLabel)

        self.notebookMsg = QLineEdit(self)
        self.notebookMsg.setText(prefs['notebook'])
        self.l.addWidget(self.notebookMsg)
        self.notebookLabel.setBuddy(self.notebookMsg)
        
        self.tagsCsvLabel = QLabel('evernote Tags CSV (ie calibre,mykindle)')
        self.l.addWidget(self.tagsCsvLabel)

        self.tagsCsvMsg = QLineEdit(self)
        self.tagsCsvMsg.setText(prefs['tagsCsv'])
        self.l.addWidget(self.tagsCsvMsg)
        self.tagsCsvLabel.setBuddy(self.tagsCsvMsg)

    def save_settings(self):
        prefs['notebook'] = unicode(self.notebookMsg.text())
        prefs['tagsCsv'] = unicode(self.tagsCsvMsg.text())

    def about(self):
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About calibrebeam',
                text.decode('utf-8'))
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.pandoc_label = QLabel('Pandoc Executable path:')
        self.l1 = QHBoxLayout()
        self.l.addLayout(self.l1)
        self.l1.addWidget(self.pandoc_label)

        self.pandoc_path = QLineEdit(self)
        self.pandoc_path.setText(prefs['pandoc_exec'])
        self.l1.addWidget(self.pandoc_path)
        self.pandoc_label.setBuddy(self.pandoc_path)

        self.l2 = QHBoxLayout()
        self.l.addLayout(self.l2)
        self.java_label = QLabel('Java Executable path:')
        self.l2.addWidget(self.java_label)

        self.java_path = QLineEdit(self)
        self.java_path.setText(prefs['java_exec'])
        self.l2.addWidget(self.java_path)
        self.java_label.setBuddy(self.java_path)

        self.resize(self.sizeHint())

    def save_settings(self):
        prefs['pandoc_exec'] = unicode(self.pandoc_path.text())
        prefs['java_exec'] = unicode(self.java_path.text())
class ConfigWidget(QWidget):
  'Configuration widget'
  def __init__(self):
    QWidget.__init__(self)
    self.layout = QGridLayout()
    self.layout.setSpacing(10)
    self.setLayout(self.layout)

    self.key_label = QLabel('&api key:')
    self.key_msg = QLineEdit(self)
    self.key_msg.setText(PREFS['api_key'])
    self.layout.addWidget(self.key_label, 1, 0)
    self.layout.addWidget(self.key_msg, 1, 1)
    self.key_label.setBuddy(self.key_msg)

    self.threads_label = QLabel('&worker_threads:')
    self.threads_msg = QLineEdit(self)
    self.threads_msg.setText(unicode(PREFS['worker_threads']))
    self.layout.addWidget(self.threads_label, 2, 0)
    self.layout.addWidget(self.threads_msg, 2, 1)
    self.threads_label.setBuddy(self.threads_msg)

  def save_settings(self):
    'Apply new settings value'
    PREFS['api_key'] = unicode(self.key_msg.text())
    PREFS['worker_threads'] = int(self.threads_msg.text())
    pycomicvine.api_key = PREFS['api_key']
Exemple #11
0
class App(QWidget):
    def __init__(self):
        super(App, self).__init__(None)
        self.title = 'steering angle test'
        self.left = 10
        self.top = 10
        self.width = 400
        self.height = 400
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.max_angle_label = QLabel("max_angle", self)
        self.max_angle_label.move(20, 20)
        self.max_angle_label.resize(80, 40)
        self.max_angle_text = QLineEdit('450', self)
        self.max_angle_text.move(120, 20)
        self.max_angle_text.resize(240, 40)

        self.angle_label = QLabel("angle", self)
        self.angle_label.move(20, 60)
        self.angle_label.resize(80, 40)
        self.angle_text = QLineEdit('450', self)
        self.angle_text.move(120, 60)
        self.angle_text.resize(240, 40)

        self.times_label = QLabel("times", self)
        self.times_label.move(20, 100)
        self.times_label.resize(80, 40)
        self.times_text = QLineEdit('10', self)
        self.times_text.move(120, 100)
        self.times_text.resize(240, 40)

        self.discret_label = QLabel("discret", self)
        self.discret_label.move(20, 140)
        self.discret_label.resize(80, 40)
        self.discret_text = QLineEdit('200', self)
        self.discret_text.move(120, 140)
        self.discret_text.resize(240, 40)

        self.test_button = QPushButton('test', self)
        self.test_button.move(20, 240)
        self.test_button.resize(360, 40)

        # connect button to function on_click

        self.test_button.clicked.connect(self.on_test_click)

        self.show()

    def on_test_click(self):

        sendVehicleCmd(vehicle_info.steering_angle,
                       int(self.angle_text.text()),
                       int(self.max_angle_text.text()),
                       int(self.times_text.text()),
                       int(self.discret_text.text()))
Exemple #12
0
class AddSerialDialog(QDialog):
    def __init__(
        self,
        parent=None,
    ):
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setWindowTitle("{0} {1}: Add New eInk Kobo 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("EInk Kobo Serial Number:", self))
        self.key_ledit = QLineEdit("", self)
        self.key_ledit.setToolTip(
            "Enter an eInk Kobo serial number. EInk Kobo serial numbers are 13 characters long and usually start with a 'N'. Kobo 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 self.key_ledit.text().strip()

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

    def accept(self):
        if len(self.key_name) == 0 or self.key_name.isspace():
            errmsg = "Please enter an eInk Kobo 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) != 13:
            errmsg = "EInk Kobo Serial Numbers must be 13 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)
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.label = QLabel("Voice")
        self.l.addWidget(self.label)

        self.voiceOptions = QComboBox()
        self.l.addWidget(self.voiceOptions)

        self.rateLabel = QLabel("Rate (-10 to 10)")
        self.l.addWidget(self.rateLabel)

        self.rateEdit = QLineEdit()
        self.rateEdit.setValidator(QIntValidator(-10, 10))
        self.rateEdit.setText(str(prefs['rate']))

        self.l.addWidget(self.rateEdit)

        self.volumeLabel = QLabel("Volume (0 to 100)")
        self.volumeEdit = QLineEdit()
        self.volumeEdit.setValidator(QIntValidator(0, 100))
        self.volumeEdit.setText(str(prefs['volume']))
        self.l.addWidget(self.volumeLabel)
        self.l.addWidget(self.volumeEdit)

        import win32com.client
        self.spVoice = win32com.client.Dispatch("SAPI.SpVoice")
        voices = self.spVoice.GetVoices("", "")

        for i in range(voices.Count):
            self.voiceOptions.addItem(voices.Item(i).GetDescription())

            if voices.Item(i).GetDescription() == prefs['voice']:
                self.voiceOptions.setCurrentIndex(i)

        self.pauseHotKey = HotkeyWidget(prefs, "pause",
                                        "Enable Pause/Play hotkey")
        self.l.addWidget(self.pauseHotKey)

        self.stopHotKey = HotkeyWidget(prefs, "stop", "Enable Stop hotkey")
        self.l.addWidget(self.stopHotKey)

        self.selectHotKey = HotkeyWidget(prefs, "select",
                                         "Enable Select Mode hotkey")
        self.l.addWidget(self.selectHotKey)

    def save_settings(self):
        from calibre_plugins.tts_ebook_viewer.hotkeys import keycodes

        prefs['voice'] = unicode(self.voiceOptions.currentText())
        prefs['rate'] = int(self.rateEdit.text())
        prefs['volume'] = int(self.volumeEdit.text())

        self.pauseHotKey.save_settings(prefs)
        self.stopHotKey.save_settings(prefs)
        self.selectHotKey.save_settings(prefs)
class PortScannerTab(QWidget):
    def __init__(self, console):
        self.console = console
        self.openPorts = []

        super().__init__()
        self.layout = QVBoxLayout(self)

        self.titleText = QLabel("<H1>Portscanner</H1>\nIP-Adresse")
        self.layout.addWidget(self.titleText)

        self.ipField = QLineEdit("192.168.178.1")
        self.layout.addWidget(self.ipField)

        self.hbox = QHBoxLayout()

        self.startLabel = QLabel("Von Port")
        self.endLabel = QLabel("Bis Port")

        self.startField = QLineEdit("1")
        self.endField = QLineEdit("65535")

        self.hbox.addWidget(self.startLabel)
        self.hbox.addWidget(self.startField)
        self.hbox.addWidget(self.endLabel)
        self.hbox.addWidget(self.endField)

        self.layout.addLayout(self.hbox)

        self.startButton = QPushButton()
        self.startButton.setText("Starte Scan")

        self.portScanner = PortScanner()
        self.startButton.clicked.connect(self.btnClicked)
        self.layout.addWidget(self.startButton)

        self.output = Console("Output")
        self.layout.addWidget(self.output)

        # self.layout.addStretch(1)

    def btnClicked(self):
        if self.startButton.text() == "Starte Scan":
            self.output.clear()
            self.thread = PortScanThread(args=(int(self.startField.text()),
                                               int(self.endField.text()),
                                               self.ipField.text()))
            self.thread.portadd.connect(self.logPort)
            self.thread.start()
            self.startButton.setText("Beende Scan")
        else:
            self.startButton.setText("Starte Scan")
            self.thread.kill()

    def logPort(self, port):
        if port.startswith("Scan abgeschlossen"):
            self.btnClicked()
        self.output.log(port)
class DosTab(QWidget):
    running = False
    dos = None

    def __init__(self, console):
        super().__init__()
        self.console = console
        self.layout = QVBoxLayout(self)

        self.titleText = QLabel()
        self.titleText.setText("<H1>Denial of service</h1>\nIp Adresse")
        self.layout.addWidget(self.titleText)

        self.ipField = QLineEdit("127.0.0.1")
        self.layout.addWidget(self.ipField)

        self.portLabel = QLabel()
        self.portLabel.setText("Port")
        self.layout.addWidget(self.portLabel)

        self.portField = QLineEdit()
        self.layout.addWidget(self.portField)

        self.startButton = QPushButton()
        self.startButton.setText("Starte Attacke")

        self.dos = DenialOfService(self.console)

        self.startButton.clicked.connect(self.start)
        self.layout.addWidget(self.startButton)

        self.layout.addStretch(1)

    def start(self):
        if not self.running:

            try:
                mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                mysocket.connect(
                    (self.ipField.text(), int(self.portField.text())))
            except:
                self.console.log("Verbindung fehlgeschlagen")
                return

            self.running = True
            self.startButton.setText("Stoppe Attacke")
            self.console.log("Angrff gestartet")
            self.dos.setIp(self.ipField.text())
            self.dos.setPort(int(self.portField.text()))
            self.dos.start()

        else:
            self.startButton.setText("Starte Attacke")
            self.running = False
            self.console.log("Angrff gestoppt")
            self.dos.stop()
Exemple #16
0
    def _on_command_run(self, command_input: QLineEdit):
        """Handles running commands."""
        if command_input.text().strip() == "":
            return

        self._model.add_command(self._current_bot.uid, Command(CommandType.SHELL, command_input.text().encode()))

        command_input.clear()
        self.display_info("Command added to the queue of:\n {}@{}".format(
            self._current_bot.username, self._current_bot.hostname
        ))
Exemple #17
0
class Weather(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Weather')
        self.setWindowIcon(QIcon('umbrella.png'))
        self.resize(300, 120)
        self.ui()
        self.show()

    def ui(self):
        vbox = QVBoxLayout()
        title = QLabel()
        title.setText('Weather')
        title.setStyleSheet('font: 20pt')
        title.setAlignment(Qt.AlignCenter)
        vbox.addWidget(title)
        hbox = QHBoxLayout()
        label = QLabel()
        label.setText('City Name:')
        label.setStyleSheet('font: 15px')
        self.textLine = QLineEdit()
        self.textLine.setMinimumHeight(30)
        hbox.addWidget(label)
        hbox.addWidget(self.textLine)
        vbox.addItem(hbox)
        button = QPushButton()
        button.setText('Search')
        button.setStyleSheet('font: 15px')
        button.setMinimumHeight(30)
        button.clicked.connect(self.checkText)
        vbox.addWidget(button)
        self.setLayout(vbox)

    def checkText(self):
        if not self.textLine.text().isalpha():
            message = QErrorMessage(self)
            message.showMessage('Invalid Entry! Try Again.')
            message.setWindowTitle('Warning')
            message.setWindowIcon(QIcon('error.png'))
        else:
            location = self.textLine.text()
            url = weather_url + location
            global json
            json = requests.get(url).json()
            try:
                json['message']
            except Exception:
                self.obj = ShowWeather()
            else:
                message = QErrorMessage(self)
                message.showMessage('Invalid City Name! Try Again.')
                message.setWindowTitle('Warning')
                message.setWindowIcon(QIcon('error.png'))
Exemple #18
0
class ConfigWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.layout = QGridLayout()
        self.layout.setSpacing(10)

        self.ip_label = QLabel("Remarkable IP:")
        self.layout.addWidget(self.ip_label, 1, 0)
        self.ip_label_msg = QLineEdit(self)
        self.ip_label_msg.setText(prefs["ip"])
        self.layout.addWidget(self.ip_label_msg, 1, 1)
        self.ip_label.setBuddy(self.ip_label_msg)

        self.books_path_label = QLabel("Books Path:")
        self.layout.addWidget(self.books_path_label, 2, 0)
        self.books_path_label_msg = QLineEdit(self)
        self.books_path_label_msg.setText(prefs["books_path"])
        self.layout.addWidget(self.books_path_label_msg, 2, 1)
        self.books_path_label.setBuddy(self.books_path_label_msg)

        self.metadata_path_label = QLabel("Config Path:")
        self.layout.addWidget(self.metadata_path_label, 3, 0)
        self.metadata_path_label_msg = QLineEdit(self)
        self.metadata_path_label_msg.setText(prefs["metadata_path"])
        self.layout.addWidget(self.metadata_path_label_msg, 3, 1)
        self.metadata_path_label.setBuddy(self.metadata_path_label_msg)

        self.password_label = QLabel("Password ( If not using Key ):")
        self.layout.addWidget(self.password_label, 4, 0)
        self.password_label_msg = QLineEdit(self)
        self.password_label_msg.setText(prefs["password"])
        self.layout.addWidget(self.password_label_msg, 4, 1)
        self.password_label.setBuddy(self.password_label_msg)

        self.storage_label = QLabel("Storage ( like '/dev/mmcblk1p7' ):")
        self.layout.addWidget(self.storage_label, 5, 0)
        self.storage_label_msg = QLineEdit(self)
        self.storage_label_msg.setText(prefs["storage"])
        self.layout.addWidget(self.storage_label_msg, 5, 1)
        self.storage_label.setBuddy(self.storage_label_msg)

        self.setLayout(self.layout)
        self.setGeometry(150, 150, 150, 150)
        self.setWindowTitle("Remarkable Config")

    def save_settings(self):
        prefs["ip"] = self.ip_label_msg.text()
        # append an extra '/' in case it was forgotten
        prefs["books_path"] = self.books_path_label_msg.text() + "/"
        prefs["metadata_path"] = self.metadata_path_label_msg.text() + "/"
        prefs["password"] = self.password_label_msg.text()
        prefs["storage"] = self.storage_label_msg.text()
Exemple #19
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 #20
0
class editpopup(QWidget):
    user_id = ""
    session = Session()

    def __init__(self):
        super().__init__()
        self.title = "Edit Pop Up"
        self.width = 500
        self.height = 500
        self.top = 100
        self.left = 100
        self.initUI()

    def initUI(self):
        self.username = QLineEdit(self)
        self.username.move(200, 200)

        self.password = QLineEdit(self)
        self.password.move(200, 240)
        self.password.setEchoMode(QLineEdit.Password)

        self.role = QComboBox(self)
        self.role.addItem("Student")
        self.role.addItem("Librarian")
        self.role.addItem("Admin")
        self.role.move(200, 280)

        self.savechanges = QPushButton("Save changes", self)
        self.savechanges.move(250, 350)
        self.savechanges.clicked.connect(self.updateValues)
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

    def setValues(self, user_id, user_name, user_password, user_role):
        self.user_id = user_id
        self.username.setText(user_name)
        self.password.setText(user_password)
        self.role.setCurrentText(user_role)

    def updateValues(self):
        result = self.session.query(User).filter(
            User.id == self.user_id).first()
        result.username = self.username.text()
        result.password = self.password.text()
        result.role = self.role.currentText()
        try:
            self.session.add(result)
            self.session.commit()
            self.close()
        except:
            print("Error occured while saving")
Exemple #21
0
class Login(QWidget):
    session = Session()

    def __init__(self):
        super().__init__()
        self.title = "Admin Panel"
        self.width = 640
        self.height = 400
        self.top = 100
        self.left = 100
        self.adminPanelUI = AdminPanel()
        self.initUI()

    def initUI(self):
        self.lblusername = QLabel(self)
        self.lblpassword = QLabel(self)
        self.lblusername.move(200, 100)
        self.lblusername.setText("USERNAME")
        self.lblpassword.move(200, 140)
        self.lblpassword.setText("PASSWORD")
        self.username = QLineEdit(self)
        self.username.move(250, 100)

        self.password = QLineEdit(self)
        self.password.move(250, 140)
        self.password.setEchoMode(QLineEdit.Password)

        self.login = QPushButton("Login", self)
        self.login.move(280, 300)

        self.login.clicked.connect(self.onclick)

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.show()

    def onclick(self):
        user = self.session.query(User).filter(
            User.username == self.username.text()).first()
        print("User Exists")
        if (user.password == self.password.text()):
            role = user.role
            print(role)
            if (role == "Student"):
                print("It is a student")
            elif (role == "Librarian"):
                print("Redirect to the librarian UI")
            else:
                self.adminPanelUI.show()
Exemple #22
0
class AddUserUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.width = 640
        self.height = 400
        self.top = 100
        self.left = 100
        self.initUI()

    def initUI(self):
        self.labelUsername = QLabel(self)
        self.labelUsername.setText("Username")
        self.labelPassword = QLabel(self)
        self.labelPassword.setText("Password")
        self.labelRole = QLabel(self)
        self.labelRole.setText("Role")
        self.labelUsername.move(250, 100)
        self.labelPassword.move(250, 130)
        self.labelRole.move(250, 160)
        self.username = QLineEdit(self)
        self.username.move(300, 100)
        self.password = QLineEdit(self)
        self.password.setEchoMode(QLineEdit.Password)
        self.password.move(300, 130)
        self.role = QComboBox(self)
        self.role.addItem("Student")
        self.role.addItem("Librarian")
        self.role.addItem("Admin")
        self.role.move(300, 160)

        button = QPushButton("Add User", self)
        button.move(300, 190)
        button.clicked.connect(self.add_user)

        self.setWindowTitle("Add Users")
        self.setGeometry(self.left, self.top, self.width, self.height)

    def add_user(self):
        uname = self.username.text()
        password = self.password.text()
        role = self.role.currentText()
        print(uname)
        print(password)
        print(role)
        user = User(uname, password, role)
        session.add(user)
        session.commit()
        self.statusBar().showMessage("User Saved Successfully")
Exemple #23
0
class FileSelector(QWidget):
    def __init__(self, parent, filter_, file_dialog_service):
        QWidget.__init__(self, parent)
        self._file_dialog_service = file_dialog_service
        self._filter = filter_
        self._line_edit = QLineEdit(self)
        self._open_dialog = ShrunkPushButton('...', self)
        self._layout = QHBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.addWidget(self._line_edit)
        self._layout.addWidget(self._open_dialog)
        self._line_edit.textChanged.connect(self.textChanged)
        self._open_dialog.clicked.connect(self._open_file_dialog)

    textChanged = pyqtSignal(str)

    @auto_property(str)
    def text(self):
        return self._line_edit.text()

    @text.setter
    def text(self, value):
        self._line_edit.setText(value)

    def _open_file_dialog(self):
        file_name = self._file_dialog_service.get_open_filename(
            self, self._filter)
        if file_name:
            self.text = file_name
Exemple #24
0
class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        #窗口设置
        self.setGeometry(300, 300, 300, 320)
        self.setWindowTitle('聊天室')
        self.setWindowIcon(QIcon('timg.jpg'))  #设置窗口图标
        #按钮设置
        btn = QPushButton('Button', self)
        btn.move(200, 200)
        btn.resize(100, 120)
        btn.clicked.connect(self.Onchanged)
        #消息框
        self.textbox = QLineEdit(self)
        self.textbox.move(0, 200)
        self.textbox.resize(200, 120)
        #label设置
        self.lb1 = QLabel(self)
        self.show()

    def Onchanged(self, text):
        txt = self.textbox.text()
        MySQL_Op.InsertTB(txt)
        self.lb1.setText(txt)
        self.lb1.adjustSize()
Exemple #25
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('...')

        self.url_le = QLineEdit('http://qt-project.org/')

        self.go_pb = QPushButton('Go')
        self.go_pb.clicked.connect(self._on_load_url)

        url_layout = QHBoxLayout()
        url_layout.addWidget(self.url_le)
        url_layout.addWidget(self.go_pb)

        self.view = QWebEngineView()
        self.view.urlChanged.connect(self._on_url_changed)
        self.view.titleChanged.connect(self.setWindowTitle)

        main_layout = QVBoxLayout()
        main_layout.addLayout(url_layout)
        main_layout.addWidget(self.view)

        self.setLayout(main_layout)

    def _on_load_url(self):
        self.view.load(QUrl(self.url_le.text()))

    def _on_url_changed(self, url: QUrl):
        self.url_le.setText(url.toString())
Exemple #26
0
class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 textbox'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # create textbox
        self.textbox = QLineEdit(self)
        self.textbox.move(20, 20)
        self.textbox.resize(280, 40)

        # Create a button in the window
        self.button = QPushButton('show text', self)
        self.button.move(20, 80)

        # connect button to function on_click
        self.button.clicked.connect(self.on_click)
        self.show()

    @pyqtSlot()
    def on_click(self):
        textboxValue = self.textbox.text()
        QMessageBox.question(self, "Message", 'You typed:' + textboxValue,
                             QMessageBox.Ok, QMessageBox.Ok)
        """打印完毕之后清空文本框"""
        self.textbox.setText('')
Exemple #27
0
class CollectionsGroupBox(DeviceOptionsGroupBox):
    def __init__(self, parent, device):
        super(CollectionsGroupBox, self).__init__(parent, device)
        self.setTitle(_("Collections"))

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

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

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

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

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

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

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

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

    @property
    def delete_empty_collections(self):
        return self.delete_empty_collections_checkbox.isChecked()
Exemple #28
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('<b>' + _('New location of this library:'))
        l.addWidget(self.cl, l.rowCount(), 0, 1, ncols)
        self.loc = QLineEdit(loc, self)
        l.addWidget(self.loc, l.rowCount(), 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, l.rowCount() - 1, 1, 1, 1)
        self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Abort)
        b = self.bb.addButton(_('Library moved'),
                              QDialogButtonBox.ButtonRole.AcceptRole)
        b.setIcon(QIcon(I('ok.png')))
        b = self.bb.addButton(_('Forget library'),
                              QDialogButtonBox.ButtonRole.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(120, 0))

    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_type(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 #29
0
class App(QWidget):
    def __init__(self):
        '''
        初始化操作
        '''
        # 调用父类QWidget的方法
        super().__init__()
        # 对话框标题文字
        self.title = '人人都是Pythonista'
        # 对话框初始显示位置(从屏幕左边开始往右数)
        self.left = 200
        # 对话框的初始高度(从屏幕上面开始往下数)
        self.top = 250
        # 对话框宽
        self.width = 500
        # 对话框高
        self.height = 500
        # 初始化时执行页面ui初始化方法
        self.initUI()

    def initUI(self):
        '''
        页面ui初始化
        '''
        # 设置窗口标题
        self.setWindowTitle(self.title)
        # 设置窗口初始位置
        self.setGeometry(self.left, self.top, self.width, self.height)
        # 设置窗口小图标(icon)
        self.setWindowIcon(QtGui.QIcon('icon.jpg'))
        # 创建文本框
        self.textbox = QLineEdit(self)
        # 文本框在界面中的初始位置(左上角的位置)
        self.textbox.move(20, 30)
        # 文本框的尺寸(长,宽)
        self.textbox.resize(400, 300)

        # 创建一个按钮
        self.button = QPushButton('在这里点击', self)
        # 按钮的初始位置(左上角的位置)
        self.button.move(20, 340)

        # 将按钮点击事件与下面的on_click方法关联起来
        self.button.clicked.connect(self.on_click)
        # 弹出对话框
        self.show()

    @pyqtSlot()
    def on_click(self):
        '''
        点击事件
        '''
        # 获取文本框中输入的值
        textboxValue = self.textbox.text()
        # 弹出对话框
        QMessageBox.question(self, "Message", '你输入了这些内容:' + textboxValue,
                             QMessageBox.Ok, QMessageBox.Ok)
        # 点击以后清空文本框
        self.textbox.setText('')
Exemple #30
0
class AddPIDDialog(QDialog):
    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)
        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())

    @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 a Mobipocket PID 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) != 8 and len(self.key_name) != 10:
            errmsg = u"Mobipocket PIDs must be 8 or 10 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 #31
0
class AddPIDDialog(QDialog):
    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)
        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())

    @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 a Mobipocket PID 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) != 8 and len(self.key_name) != 10:
            errmsg = u"Mobipocket PIDs must be 8 or 10 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 #32
0
    class GenerateLabelsDialog(QDialog):
        #Generate labels dialog class
        def __init__(self, p=None):
            QDialog.__init__(self, p)
            self.setWindowTitle("Generate page layout...")
            self.layout = QFormLayout()

            self.numberOfLabelsSpinBox = QSpinBox()
            self.numberOfLabelsSpinBox.setRange(1, 200)
            self.numberOfLabelsSpinBox.setValue(
                generate_settings['defaultNumberOfLabels'])
            self.layout.addRow("Number of labels", self.numberOfLabelsSpinBox)

            self.firstLabelArticleNumberSB = QSpinBox()
            self.firstLabelArticleNumberSB.setRange(0, 9999)
            self.firstLabelArticleNumberSB.setValue(
                generate_settings['firstLabelArticleNumber'])
            self.layout.addRow("First label article number",
                               self.firstLabelArticleNumberSB)

            self.weekNrYearLE = QLineEdit()
            self.weekNrYearLE.setText(generate_settings['weekNrYear'])
            self.layout.addRow("Week nr/ year", self.weekNrYearLE)

            self.lotNameLE = QLineEdit()
            self.lotNameLE.setText(generate_settings['lotName'])
            self.layout.addRow("Lot", self.lotNameLE)

            self.generatePB = QPushButton("Generate")
            self.generatePB.clicked.connect(self.onGenerate)
            self.layout.addRow("", self.generatePB)
            self.cancelPB = QPushButton("Cancel")
            self.cancelPB.clicked.connect(self.close)
            self.layout.addRow("", self.cancelPB)
            self.setLayout(self.layout)

        def onGenerate(self):
            generate_settings[
                'defaultNumberOfLabels'] = self.numberOfLabelsSpinBox.value()
            generate_settings[
                'firstLabelArticleNumber'] = self.firstLabelArticleNumberSB.value(
                )
            generate_settings['weekNrYear'] = self.weekNrYearLE.text()
            generate_settings['lotName'] = self.lotNameLE.text()
            self.accept()
Exemple #33
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.StandardButton.Ok
                                      | QDialogButtonBox.StandardButton.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.TextInteractionFlag.LinksAccessibleByMouse
            | Qt.TextInteractionFlag.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.DialogCode.Accepted:
            sc = unicode_type(sc.text()).strip()
            if bf.isChecked():
                sc += '|bf'
            customize_plugin(self, sc)

        return config_dialog.result()
Exemple #34
0
class ChooseName(Dialog):  # {{{
    ''' Chooses the filename for a newly imported file, with error checking '''
    def __init__(self, candidate, parent=None):
        self.candidate = candidate
        self.filename = None
        Dialog.__init__(self,
                        _('Choose file name'),
                        'choose-file-name',
                        parent=parent)

    def setup_ui(self):
        self.l = l = QFormLayout(self)
        self.setLayout(l)

        self.err_label = QLabel('')
        self.name_edit = QLineEdit(self)
        self.name_edit.textChanged.connect(self.verify)
        self.name_edit.setText(self.candidate)
        pos = self.candidate.rfind('.')
        if pos > -1:
            self.name_edit.setSelection(0, pos)
        l.addRow(_('File &name:'), self.name_edit)
        l.addRow(self.err_label)
        l.addRow(self.bb)

    def show_error(self, msg):
        self.err_label.setText('<p style="color:red">' + msg)
        return False

    def verify(self):
        return name_is_ok(unicode_type(self.name_edit.text()), self.show_error)

    def accept(self):
        if not self.verify():
            return error_dialog(
                self,
                _('No name specified'),
                _('You must specify a file name for the new file, with an extension.'
                  ),
                show=True)
        n = unicode_type(self.name_edit.text()).replace('\\', '/')
        name, ext = n.rpartition('.')[0::2]
        self.filename = name + '.' + ext.lower()
        super(ChooseName, self).accept()
Exemple #35
0
class Logwindow(QWidget):
    def __init__(self):
        super().__init__()
        self.InitGUI()

    def InitGUI(self):
        self.lab1 = QLabel('账号', self)
        self.lab1.move(23, 30)
        self.lab2 = QLabel('密码', self)
        self.lab2.move(23, 80)
        self.text1 = QLineEdit(self)
        self.text1.move(50, 30)
        self.text1.resize(150, 15)
        self.text2 = QLineEdit(self)
        self.text2.move(50, 80)
        self.text2.resize(150, 15)
        self.text2.setEchoMode(QLineEdit.Password)
        self.btn = QPushButton('登陆', self)
        self.btn.move(30, 150)
        self.btn.clicked.connect(lambda: self.check())
        self.btn2 = QPushButton('退出', self)
        self.btn2.move(150, 150)
        self.btn2.clicked.connect(lambda: QCoreApplication.instance().quit())
        self.setWindowTitle('登录')
        self.resize(250, 250)
        self.center()
        self.show()

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

    def check(self):
        acc = self.text1.text()
        pas = self.text2.text()
        #if(check.check(acc,pas)):
        if (True):
            MW = M.MainW(acc)
            self.close()
            pass
        else:
            QMessageBox.critical(self, 'login', '账号密码错误')
Exemple #36
0
class AddAndroidSerialDialog(QDialog):
    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())

    @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 a Kindle for Android 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)
        QDialog.accept(self)
Exemple #37
0
class ChooseName(Dialog):  # {{{

    """ Chooses the filename for a newly imported file, with error checking """

    def __init__(self, candidate, parent=None):
        self.candidate = candidate
        self.filename = None
        Dialog.__init__(self, _("Choose file name"), "choose-file-name", parent=parent)

    def setup_ui(self):
        self.l = l = QFormLayout(self)
        self.setLayout(l)

        self.err_label = QLabel("")
        self.name_edit = QLineEdit(self)
        self.name_edit.textChanged.connect(self.verify)
        self.name_edit.setText(self.candidate)
        pos = self.candidate.rfind(".")
        if pos > -1:
            self.name_edit.setSelection(0, pos)
        l.addRow(_("File &name:"), self.name_edit)
        l.addRow(self.err_label)
        l.addRow(self.bb)

    def show_error(self, msg):
        self.err_label.setText('<p style="color:red">' + msg)
        return False

    def verify(self):
        return name_is_ok(unicode(self.name_edit.text()), self.show_error)

    def accept(self):
        if not self.verify():
            return error_dialog(
                self,
                _("No name specified"),
                _("You must specify a file name for the new file, with an extension."),
                show=True,
            )
        n = unicode(self.name_edit.text()).replace("\\", "/")
        name, ext = n.rpartition(".")[0::2]
        self.filename = name + "." + ext.lower()
        super(ChooseName, self).accept()
Exemple #38
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 #39
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()
class ConfigWidget(QWidget):

    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)

    def save_settings(self):
        prefs['pathToLibrary'] = unicode(self.pathToLibrarySetting.text())
        prefs['pathToCofig'] = unicode(self.pathToCofigSetting.text())
        prefs['pathToRecoll'] = unicode(self.pathToRecollSetting.text())
Exemple #41
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 #42
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 #43
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()
class ConfigWidget(QWidget):

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

        self.label = QLabel('Enter the keyword')
        self.l.addWidget(self.label)

        self.msg = QLineEdit(self)
        self.msg.setText("")
        self.l.addWidget(self.msg)
        self.label.setBuddy(self.msg)

    def save_settings(self):
        prefs['hello_world_msg'] = unicode(self.msg.text())
Exemple #45
0
class URL(QWidget):

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

        self.label = QLabel('URL:')
        l.addWidget(self.label, 0, 0, 1, 1)
        self.url_edit = QLineEdit(self)
        self.url_edit.setPlaceholderText('Enter the URL of the wikipedia '
                                         'article to download')
        l.addWidget(self.url_edit, 0, 1, 1, 1)

    @property
    def url(self):
        return unicode(self.url_edit.text())
Exemple #46
0
class RenameKeyDialog(QDialog):
    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())

    def accept(self):
        if not unicode(self.key_ledit.text()) or unicode(self.key_ledit.text()).isspace():
            errmsg = u"Key name field cannot be empty!"
            return error_dialog(
                None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), _(errmsg), show=True, show_copy_button=False
            )
        if len(self.key_ledit.text()) < 4:
            errmsg = u"Key name must be at <i>least</i> 4 characters long!"
            return error_dialog(
                None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), _(errmsg), show=True, show_copy_button=False
            )
        if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()):
            # Same exact name ... do nothing.
            return QDialog.reject(self)
        for k in self.parent.plugin_keys.keys():
            if uStrCmp(self.key_ledit.text(), k, True) and not uStrCmp(k, self.parent.listy.currentItem().text(), True):
                errmsg = u"The key name <strong>{0}</strong> is already being used.".format(self.key_ledit.text())
                return error_dialog(
                    None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), _(errmsg), show=True, show_copy_button=False
                )
        QDialog.accept(self)

    @property
    def key_name(self):
        return unicode(self.key_ledit.text()).strip()
class PluginWidget(QWidget):
    TITLE = _('HTML Virtual Shelf options')
    HELP  = _('Options specific to Virtual Shelf plugin')
    sync_enabled = False
    formats = set(['html'])

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

        self.layout = QHBoxLayout(self)
        label = QLabel(_("Output directory"))
        self.pathEdit = QLineEdit()

        self.pathEdit.setText("/home/carles/virtual-shelf")

        self.layout.addWidget(label)
        self.layout.addWidget(self.pathEdit)

    def initialize(self, catalog_name):
        print "def Virtual Shelf initialize"

    def options(self):
        return { 'output_directory': self.pathEdit.text() }
class CheckLibraryDialog(QDialog):

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

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

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

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

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

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

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

        '''))

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

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

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

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

    def do_exec(self):
        self.run_the_check()

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

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

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

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

        plaintext = []

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def copy_to_clipboard(self):
        QApplication.clipboard().setText(self.text_results)
Exemple #49
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 = unicode(sc.text()).strip()
                customize_plugin(self, sc)

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

        return config_dialog.result()
Exemple #50
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)
        l.setFieldGrowthPolicy(l.ExpandingFieldsGrow)
        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.license = lc = QLineEdit(self)
        l.addRow(_('&License:'), lc)
        self.url = QLineEdit(self)
        l.addRow(_('&URL:'), self.url)
        lc.setText(_(
            'The license for the icons in this theme. Common choices are'
            ' Creative Commons or Public Domain.'))
        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, 670)

    @property
    def metadata(self):
        self.report.theme.title = self.title.text().strip()  # Needed for report.name to work
        return {
            'title': self.title.text().strip(),
            'author': self.author.text().strip(),
            'version': self.version.value(),
            'description': self.description.toPlainText().strip(),
            'number': len(self.report.name_map) - len(self.report.extra),
            'date': utcnow().date().isoformat(),
            'name': self.report.name,
            'license': self.license.text().strip() or 'Unknown',
            'url': self.url.text().strip() or None,
        }

    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())
        self.license.setText((theme.license or 'Unknown').strip())
        self.url.setText((theme.url 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 #51
0
class ConditionEditor(QWidget):  # {{{

    ACTION_MAP = {
            'bool' : (
                    (_('is true'), 'is true',),
                    (_('is false'), 'is false'),
                    (_('is undefined'), 'is undefined')
            ),
            'ondevice' : (
                    (_('is true'), 'is set',),
                    (_('is false'), 'is not set'),
            ),
            'identifiers' : (
                (_('has id'), 'has id'),
                (_('does not have id'), 'does not have id'),
            ),
            'int' : (
                (_('is equal to'), 'eq'),
                (_('is less than'), 'lt'),
                (_('is greater than'), 'gt')
            ),
            'datetime' : (
                (_('is equal to'), 'eq'),
                (_('is less than'), 'lt'),
                (_('is greater than'), 'gt'),
                (_('is set'), 'is set'),
                (_('is not set'), 'is not set'),
                (_('is more days ago than'), 'older count days'),
                (_('is fewer days ago than'), 'count_days'),
                (_('is more days from now than'), 'newer future days'),
                (_('is fewer days from now than'), 'older future days')
            ),
            'multiple' : (
                (_('has'), 'has'),
                (_('does not have'), 'does not have'),
                (_('has pattern'), 'has pattern'),
                (_('does not have pattern'), 'does not have pattern'),
                (_('is set'), 'is set'),
                (_('is not set'), 'is not set'),
            ),
            'single'   : (
                (_('is'), 'is'),
                (_('is not'), 'is not'),
                (_('matches pattern'), 'matches pattern'),
                (_('does not match pattern'), 'does not match pattern'),
                (_('is set'), 'is set'),
                (_('is not set'), 'is not set'),
            ),
    }

    for x in ('float', 'rating'):
        ACTION_MAP[x] = ACTION_MAP['int']

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

        self.action_map = self.ACTION_MAP

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

        texts = _('If the ___ column ___ values')
        try:
            one, two, three = texts.split('___')
        except:
            one, two, three = 'If the ', ' column ', ' value '

        self.l1 = l1 = QLabel(one)
        l.addWidget(l1, 0, 0)

        self.column_box = QComboBox(self)
        l.addWidget(self.column_box, 0, 1)

        self.l2 = l2 = QLabel(two)
        l.addWidget(l2, 0, 2)

        self.action_box = QComboBox(self)
        l.addWidget(self.action_box, 0, 3)

        self.l3 = l3 = QLabel(three)
        l.addWidget(l3, 0, 4)

        self.value_box = QLineEdit(self)
        l.addWidget(self.value_box, 0, 5)

        self.column_box.addItem('', '')
        for key in sorted(
                conditionable_columns(fm),
                key=lambda(key): sort_key(fm[key]['name'])):
            self.column_box.addItem(fm[key]['name'], key)
        self.column_box.setCurrentIndex(0)

        self.column_box.currentIndexChanged.connect(self.init_action_box)
        self.action_box.currentIndexChanged.connect(self.init_value_box)

        for b in (self.column_box, self.action_box):
            b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
            b.setMinimumContentsLength(20)

    @dynamic_property
    def current_col(self):
        def fget(self):
            idx = self.column_box.currentIndex()
            return unicode(self.column_box.itemData(idx) or '')

        def fset(self, val):
            for idx in range(self.column_box.count()):
                c = unicode(self.column_box.itemData(idx) or '')
                if c == val:
                    self.column_box.setCurrentIndex(idx)
                    return
            raise ValueError('Column %r not found'%val)
        return property(fget=fget, fset=fset)

    @dynamic_property
    def current_action(self):
        def fget(self):
            idx = self.action_box.currentIndex()
            return unicode(self.action_box.itemData(idx) or '')

        def fset(self, val):
            for idx in range(self.action_box.count()):
                c = unicode(self.action_box.itemData(idx) or '')
                if c == val:
                    self.action_box.setCurrentIndex(idx)
                    return
            raise ValueError('Action %r not valid for current column'%val)
        return property(fget=fget, fset=fset)

    @property
    def current_val(self):
        ans = unicode(self.value_box.text()).strip()
        if self.current_col == 'languages':
            rmap = {lower(v):k for k, v in lang_map().iteritems()}
            ans = rmap.get(lower(ans), ans)
        return ans

    @dynamic_property
    def condition(self):

        def fget(self):
            c, a, v = (self.current_col, self.current_action,
                    self.current_val)
            if not c or not a:
                return None
            return (c, a, v)

        def fset(self, condition):
            c, a, v = condition
            if not v:
                v = ''
            v = v.strip()
            self.current_col = c
            self.current_action = a
            self.value_box.setText(v)

        return property(fget=fget, fset=fset)

    def init_action_box(self):
        self.action_box.blockSignals(True)
        self.action_box.clear()
        self.action_box.addItem('', '')
        col = self.current_col
        if col:
            m = self.fm[col]
            dt = m['datatype']
            if dt in self.action_map:
                actions = self.action_map[dt]
            else:
                if col == 'ondevice':
                    k = 'ondevice'
                elif col == 'identifiers':
                    k = 'identifiers'
                else:
                    k = 'multiple' if m['is_multiple'] else 'single'
                actions = self.action_map[k]

            for text, key in actions:
                self.action_box.addItem(text, key)
        self.action_box.setCurrentIndex(0)
        self.action_box.blockSignals(False)
        self.init_value_box()

    def init_value_box(self):
        self.value_box.setEnabled(True)
        self.value_box.setText('')
        self.value_box.setInputMask('')
        self.value_box.setValidator(None)
        col = self.current_col
        if not col:
            return
        action = self.current_action
        if not action:
            return
        m = self.fm[col]
        dt = m['datatype']
        tt = ''
        if col == 'identifiers':
            tt = _('Enter either an identifier type or an '
                    'identifier type and value of the form identifier:value')
        elif col == 'languages':
            tt = _('Enter a 3 letter ISO language code, like fra for French'
                    ' or deu for German or eng for English. You can also use'
                    ' the full language name, in which case calibre will try to'
                    ' automatically convert it to the language code.')
        elif dt in ('int', 'float', 'rating'):
            tt = _('Enter a number')
            v = QIntValidator if dt == 'int' else QDoubleValidator
            self.value_box.setValidator(v(self.value_box))
        elif dt == 'datetime':
            if action == 'count_days':
                self.value_box.setValidator(QIntValidator(self.value_box))
                tt = _('Enter the maximum days old the item can be. Zero is today. '
                       'Dates in the future always match')
            elif action == 'older count days':
                self.value_box.setValidator(QIntValidator(self.value_box))
                tt = _('Enter the minimum days old the item can be. Zero is today. '
                       'Dates in the future never match')
            elif action == 'older future days':
                self.value_box.setValidator(QIntValidator(self.value_box))
                tt = _('Enter the maximum days in the future the item can be. '
                       'Zero is today. Dates in the past always match')
            elif action == 'newer future days':
                self.value_box.setValidator(QIntValidator(self.value_box))
                tt = _('Enter the minimum days in the future the item can be. '
                       'Zero is today. Dates in the past never match')
            else:
                self.value_box.setInputMask('9999-99-99')
                tt = _('Enter a date in the format YYYY-MM-DD')
        else:
            tt = _('Enter a string.')
            if 'pattern' in action:
                tt = _('Enter a regular expression')
            elif m.get('is_multiple', False):
                tt += '\n' + _('You can match multiple values by separating'
                        ' them with %s')%m['is_multiple']['ui_to_list']
        self.value_box.setToolTip(tt)
        if action in ('is set', 'is not set', 'is true', 'is false',
                'is undefined'):
            self.value_box.setEnabled(False)
class InputLine(QWidget):
    
    HEIGHT = 30
    LABEL_WIDTH = 170
    INPUT_TEXT_WIDTH = 200
    BUTTON_WIDTH = 100
    BUTTON_BLOCK_X = 380
    ELEMENT_GAP = 5
    
    ERROR_WIDTH = 250
    ERROR_X = 595
    
    def __init__(self, parent):
        super().__init__(parent)
        self.initUI()
        
    def initUI(self):
                
        component_stylesheet = """
                                .QPushButton {
                                    font-weight: bold;
                                    font-size: 13px;
                                    background-color:#E0E0E0;
                                }
                                .QPushButton:pressed {
                                    background-color:#CCCCCC;
                                }
                                .QLabel {
                                    padding-top: 7px;
                                    font-weight: bold;
                                    font-size: 14px;
                                }
                                .QLineEdit {
                                    font-weight: bold;
                                    font-size: 14px;
                                }
                                .QLabel#error {
                                    color: red;
                                    font-size: 12px;
                                    font-style: italic;
                                    padding-top: 0px;
                                    padding-left: 6px;
                                }   
                            """       
               
        self.label = QLabel("", self)
        self.label.setStyleSheet(component_stylesheet)
        self.label.setAlignment(Qt.AlignRight)
        self.label.resize(InputLine.LABEL_WIDTH, InputLine.HEIGHT)
        self.label.move(0, 0)        
        
        self.text = QLineEdit(self)
        self.text.setStyleSheet(component_stylesheet)
        self.text.resize(InputLine.INPUT_TEXT_WIDTH, InputLine.HEIGHT)
        self.text.move(InputLine.LABEL_WIDTH + InputLine.ELEMENT_GAP, 0)
        
        self.ok = QPushButton("OK", self)
        self.ok.setStyleSheet(component_stylesheet)
        self.ok.resize(InputLine.BUTTON_WIDTH, InputLine.HEIGHT)
        self.ok.move(InputLine.BUTTON_BLOCK_X, 0)
        
        self.cancel = QPushButton("Cancel", self)
        self.cancel.setStyleSheet(component_stylesheet)
        self.cancel.resize(InputLine.BUTTON_WIDTH, InputLine.HEIGHT)
        self.cancel.move(InputLine.BUTTON_BLOCK_X + InputLine.BUTTON_WIDTH + InputLine.ELEMENT_GAP, 0)
    
        self.error = QLabel("", self)
        self.error.setObjectName("error")
        self.error.setStyleSheet(component_stylesheet)
        self.error.resize(InputLine.ERROR_WIDTH, InputLine.HEIGHT)
        self.error.move(InputLine.ERROR_X, 0)
    
    """ listeners which control what happens on ok an cancel button presses """
    def addOkListener(self, onOkEvent):
        self.ok.clicked.connect(onOkEvent)
    def addCancelListener(self, onCancelEvent):
        self.cancel.clicked.connect(onCancelEvent)
        
    """ utility methods of the widget """
    def getText(self):
        return self.text.text()
    def setText(self, text):
        self.text.setText(text)        
        
    def setLabelText(self, text):
        self.label.setText(text)
        
    def setErrorText(self, text):
        self.error.setText(text)
Exemple #53
0
class CollectionsGroupBox(DeviceOptionsGroupBox):

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

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

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

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

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

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

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

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

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

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

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

    @property
    def ignore_collections_names(self):
        return self.ignore_collections_names_edit.text().strip()
class FontFamilyDialog(QDialog):

    def __init__(self, current_family, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle(_('Choose font family'))
        self.setWindowIcon(QIcon(I('font.png')))
        from calibre.utils.fonts.scanner import font_scanner
        self.font_scanner = font_scanner

        self.m = QStringListModel(self)
        self.build_font_list()
        self.l = l = QGridLayout()
        self.setLayout(l)
        self.view = FontsView(self)
        self.view.setModel(self.m)
        self.view.setCurrentIndex(self.m.index(0))
        if current_family:
            for i, val in enumerate(self.families):
                if icu_lower(val) == icu_lower(current_family):
                    self.view.setCurrentIndex(self.m.index(i))
                    break
        self.view.doubleClicked.connect(self.accept, type=Qt.QueuedConnection)
        self.view.changed.connect(self.current_changed,
                type=Qt.QueuedConnection)
        self.faces = Typefaces(self)
        self.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.add_fonts_button = afb = self.bb.addButton(_('Add &fonts'),
                self.bb.ActionRole)
        afb.setIcon(QIcon(I('plus.png')))
        afb.clicked.connect(self.add_fonts)
        self.ml = QLabel(_('Choose a font family from the list below:'))
        self.search = QLineEdit(self)
        self.search.setPlaceholderText(_('Search'))
        self.search.returnPressed.connect(self.find)
        self.nb = QToolButton(self)
        self.nb.setIcon(QIcon(I('arrow-down.png')))
        self.nb.setToolTip(_('Find next'))
        self.pb = QToolButton(self)
        self.pb.setIcon(QIcon(I('arrow-up.png')))
        self.pb.setToolTip(_('Find previous'))
        self.nb.clicked.connect(self.find_next)
        self.pb.clicked.connect(self.find_previous)

        l.addWidget(self.ml, 0, 0, 1, 4)
        l.addWidget(self.search, 1, 0, 1, 1)
        l.addWidget(self.nb, 1, 1, 1, 1)
        l.addWidget(self.pb, 1, 2, 1, 1)
        l.addWidget(self.view, 2, 0, 1, 3)
        l.addWidget(self.faces, 1, 3, 2, 1)
        l.addWidget(self.bb, 3, 0, 1, 4)
        l.setAlignment(self.faces, Qt.AlignTop)

        self.resize(800, 600)

    def set_current(self, i):
        self.view.setCurrentIndex(self.m.index(i))

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Return:
            return
        return QDialog.keyPressEvent(self, e)

    def find(self, backwards=False):
        i = self.view.currentIndex().row()
        if i < 0:
            i = 0
        q = icu_lower(unicode(self.search.text())).strip()
        if not q:
            return
        r = (xrange(i-1, -1, -1) if backwards else xrange(i+1,
            len(self.families)))
        for j in r:
            f = self.families[j]
            if q in icu_lower(f):
                self.set_current(j)
                return

    def find_next(self):
        self.find()

    def find_previous(self):
        self.find(backwards=True)

    def build_font_list(self):
        try:
            self.families = list(self.font_scanner.find_font_families())
        except:
            self.families = []
            print ('WARNING: Could not load fonts')
            import traceback
            traceback.print_exc()
        self.families.insert(0, _('None'))
        self.m.setStringList(self.families)

    def add_fonts(self):
        families = add_fonts(self)
        if not families:
            return
        self.font_scanner.do_scan()
        self.m.beginResetModel()
        self.build_font_list()
        self.m.endResetModel()
        self.view.setCurrentIndex(self.m.index(0))
        if families:
            for i, val in enumerate(self.families):
                if icu_lower(val) == icu_lower(families[0]):
                    self.view.setCurrentIndex(self.m.index(i))
                    break

        info_dialog(self, _('Added fonts'),
                _('Added font families: %s')%(
                    ', '.join(families)), show=True)

    @property
    def font_family(self):
        idx = self.view.currentIndex().row()
        if idx == 0:
            return None
        return self.families[idx]

    def current_changed(self):
        fam = self.font_family
        self.faces.show_family(fam, self.font_scanner.fonts_for_family(fam)
                if fam else None)
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 = QLabel('')
        self.saved_searches_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        gl.addWidget(self.saved_searches_label, 2, 0, 1, 2)

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

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

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

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

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

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

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

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

        self.resize(self.sizeHint()+QSize(150, 25))

    def search_text_changed(self, txt):
        db = self.gui.current_db
        searches = [_('Saved searches recognized in the expression:')]
        txt = unicode(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.setText('\n'.join(searches))
        else:
            self.saved_searches_label.setText('')

    def name_text_edited(self, new_name):
        self.new_name = unicode(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(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(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(d.names.next())
                    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(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(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 #56
0
class ConfigWidget(QWidget):

    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        self.help_anchor = "configuration"
        
        title_layout = ImageTitleLayout(self, 'images/icon.png', 'Sony Utilities Options')
        layout.addLayout(title_layout)

#        c = plugin_prefs[STORE_NAME]
        library_config = get_library_config(self.plugin_action.gui.current_db)

        custom_column_group = QGroupBox(_('Custom Columns'), self)
        layout.addWidget(custom_column_group )
        options_layout = QGridLayout()
        custom_column_group.setLayout(options_layout)

        avail_text_columns   = self.get_text_custom_columns()
        avail_number_columns = self.get_number_custom_columns()
        avail_rating_columns = self.get_rating_custom_columns()
        avail_date_columns   = self.get_date_custom_columns()
#        debug_print("avail_rating_columns=", avail_rating_columns)
#        debug_print("default columns=", self.plugin_action.gui.library_view.model().orig_headers)
        current_Location_column  = library_config.get(KEY_CURRENT_LOCATION_CUSTOM_COLUMN, DEFAULT_LIBRARY_VALUES[KEY_CURRENT_LOCATION_CUSTOM_COLUMN])
        precent_read_column      = library_config.get(KEY_PERCENT_READ_CUSTOM_COLUMN, DEFAULT_LIBRARY_VALUES[KEY_PERCENT_READ_CUSTOM_COLUMN])
        rating_column            = library_config.get(KEY_RATING_CUSTOM_COLUMN, DEFAULT_LIBRARY_VALUES[KEY_RATING_CUSTOM_COLUMN])
        last_read_column         = library_config.get(KEY_LAST_READ_CUSTOM_COLUMN, DEFAULT_LIBRARY_VALUES[KEY_LAST_READ_CUSTOM_COLUMN])

        store_on_connect         = get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_STORE_ON_CONNECT)
        prompt_to_store          = get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_PROMPT_TO_STORE)
        store_if_more_recent     = get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_STORE_IF_MORE_RECENT)
        do_not_store_if_reopened = get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_DO_NOT_STORE_IF_REOPENED)

#         do_check_for_firmware_updates = get_plugin_pref(UPDATE_OPTIONS_STORE_NAME, KEY_DO_UPDATE_CHECK)
#         do_early_firmware_updates     = get_plugin_pref(UPDATE_OPTIONS_STORE_NAME, KEY_DO_EARLY_FIRMWARE_CHECK)
#         self.update_check_last_time   = get_plugin_pref(UPDATE_OPTIONS_STORE_NAME, KEY_LAST_FIRMWARE_CHECK_TIME)

        do_daily_backup          = get_plugin_pref(BACKUP_OPTIONS_STORE_NAME, KEY_DO_DAILY_BACKUP)
        dest_directory           = get_plugin_pref(BACKUP_OPTIONS_STORE_NAME, KEY_BACKUP_DEST_DIRECTORY)
        copies_to_keep           = get_plugin_pref(BACKUP_OPTIONS_STORE_NAME, KEY_BACKUP_COPIES_TO_KEEP)
#        debug_print("current_Location_column=%s, precent_read_column=%s, rating_column=%s" % (current_Location_column, precent_read_column, rating_column))

        current_Location_label = QLabel(_('Current Reading Location Column:'), self)
        current_Location_label.setToolTip(_("Select a custom column to store the current reading location. The column type must be 'text'. Leave this blank if you do not want to store or restore the current reading location."))
        self.current_Location_combo = CustomColumnComboBox(self, avail_text_columns, current_Location_column)
        current_Location_label.setBuddy(self.current_Location_combo)
        options_layout.addWidget(current_Location_label, 0, 0, 1, 1)
        options_layout.addWidget(self.current_Location_combo, 0, 1, 1, 1)
        
        percent_read_label = QLabel(_('Percent Read Column:'), self)
        percent_read_label.setToolTip(_("Column used to store the current percent read. The column type must be a 'integer'. Leave this blank if you do not want to store or restore the percentage read."))
        self.percent_read_combo = CustomColumnComboBox(self, avail_number_columns, precent_read_column)
        percent_read_label.setBuddy(self.percent_read_combo)
        options_layout.addWidget(percent_read_label, 2, 0, 1, 1)
        options_layout.addWidget(self.percent_read_combo, 2, 1, 1, 1)

        rating_label = QLabel(_('Rating Column:'), self)
        rating_label.setToolTip(_("Column used to store the rating. The column type must be a 'integer'. Leave this blank if you do not want to store or restore the rating."))
        self.rating_combo = CustomColumnComboBox(self, avail_rating_columns, rating_column)
        rating_label.setBuddy(self.rating_combo)
        options_layout.addWidget(rating_label, 3, 0, 1, 1)
        options_layout.addWidget(self.rating_combo, 3, 1, 1, 1)

        last_read_label = QLabel(_('Last Read Column:'), self)
        last_read_label.setToolTip(_("Column used to store when the book was last read. The column type must be a 'Date'. Leave this blank if you do not want to store the last read timestamp."))
        self.last_read_combo = CustomColumnComboBox(self, avail_date_columns, last_read_column)
        last_read_label.setBuddy(self.last_read_combo)
        options_layout.addWidget(last_read_label, 4, 0, 1, 1)
        options_layout.addWidget(self.last_read_combo, 4, 1, 1, 1)

        auto_store_group = QGroupBox(_('Store on connect'), self)
        layout.addWidget(auto_store_group )
        options_layout = QGridLayout()
        auto_store_group.setLayout(options_layout)

        self.store_on_connect_checkbox = QCheckBox(_("Store current bookmarks on connect"), self)
        self.store_on_connect_checkbox.setToolTip(_("When this is checked, the library will be updated with the current bookmark for all books on the device."))
        self.store_on_connect_checkbox.setCheckState(Qt.Checked if store_on_connect else Qt.Unchecked)
        self.store_on_connect_checkbox.clicked.connect(self.store_on_connect_checkbox_clicked)
        options_layout.addWidget(self.store_on_connect_checkbox, 0, 0, 1, 3)

        self.prompt_to_store_checkbox = QCheckBox(_("Prompt to store any changes"), self)
        self.prompt_to_store_checkbox.setToolTip(_("Enable this to be prompted to save the changed bookmarks after an automatic store is done."))
        self.prompt_to_store_checkbox.setCheckState(Qt.Checked if prompt_to_store else Qt.Unchecked)
        self.prompt_to_store_checkbox.setEnabled(store_on_connect)
        options_layout.addWidget(self.prompt_to_store_checkbox, 1, 0, 1, 1)

        self.store_if_more_recent_checkbox = QCheckBox(_("Only if more recent"), self)
        self.store_if_more_recent_checkbox.setToolTip(_("Only store the reading position if the last read timestamp on the device is more recent than in the library."))
        self.store_if_more_recent_checkbox.setCheckState(Qt.Checked if store_if_more_recent else Qt.Unchecked)
        self.store_if_more_recent_checkbox.setEnabled(store_on_connect)
        options_layout.addWidget(self.store_if_more_recent_checkbox, 1, 1, 1, 1)

        self.do_not_store_if_reopened_checkbox = QCheckBox(_("Not if finished in library"), self)
        self.do_not_store_if_reopened_checkbox.setToolTip(_("Do not store the reading position if the library has the book as finished. This is if the percent read is 100%."))
        self.do_not_store_if_reopened_checkbox.setCheckState(Qt.Checked if do_not_store_if_reopened else Qt.Unchecked)
        self.do_not_store_if_reopened_checkbox.setEnabled(store_on_connect)
        options_layout.addWidget(self.do_not_store_if_reopened_checkbox, 1, 2, 1, 1)

#         update_options_group = QGroupBox(_('Firmware Update Options'), self)
#         layout.addWidget(update_options_group)
#         options_layout = QGridLayout()
#         update_options_group.setLayout(options_layout)
# 
#         self.do_update_check = QCheckBox(_('Check for Sony firmware updates daily?'), self)
#         self.do_update_check.setToolTip(_('If this is selected the plugin will check for Sony firmware updates when your Sony device is plugged in, once per 24-hour period.'))
#         self.do_update_check.setCheckState(Qt.Checked if do_check_for_firmware_updates else Qt.Unchecked)
#         options_layout.addWidget(self.do_update_check, 0, 0, 1, 1)
# 
#         self.do_early_firmware_check = QCheckBox(_('Use early firmware adopter affiliate?'), self)
#         self.do_early_firmware_check.setToolTip(_('WARNING: THIS OPTION RISKS DOWNLOADING THE WRONG FIRMWARE FOR YOUR DEVICE! YOUR DEVICE MAY NOT FUNCTION PROPERLY IF THIS HAPPENS! Choose this option to attempt to download Sony firmware updates before they are officially available for your device.'))
#         self.do_early_firmware_check.setCheckState(Qt.Checked if do_early_firmware_updates else Qt.Unchecked)
#         options_layout.addWidget(self.do_early_firmware_check, 0, 1, 1, 1)

        backup_options_group = QGroupBox(_('Device Database Backup'), self)
        layout.addWidget(backup_options_group)
        options_layout = QGridLayout()
        backup_options_group.setLayout(options_layout)

        self.do_daily_backp_checkbox = QCheckBox(_('Backup the device database daily'), self)
        self.do_daily_backp_checkbox.setToolTip(_('If this is selected the plugin will backup the device database the first time it is connected each day.'))
        self.do_daily_backp_checkbox.setCheckState(Qt.Checked if do_daily_backup else Qt.Unchecked)
        self.do_daily_backp_checkbox.clicked.connect(self.do_daily_backp_checkbox_clicked)
        options_layout.addWidget(self.do_daily_backp_checkbox, 0, 0, 1, 3)

        self.dest_directory_label = QLabel(_("Destination:"), self)
        self.dest_directory_label.setToolTip(_("Select the destination the annotations files are to be backed up in."))
        self.dest_directory_edit = QLineEdit(self)
        self.dest_directory_edit.setMinimumSize(150, 0)
        self.dest_directory_edit.setText(dest_directory)
        self.dest_directory_label.setBuddy(self.dest_directory_edit)
        self.dest_pick_button = QPushButton(_("..."), self)
        self.dest_pick_button.setMaximumSize(24, 20)
        self.dest_pick_button.clicked.connect(self._get_dest_directory_name)
        options_layout.addWidget(self.dest_directory_label, 1, 0, 1, 1)
        options_layout.addWidget(self.dest_directory_edit, 1, 1, 1, 1)
        options_layout.addWidget(self.dest_pick_button, 1, 2, 1, 1)

        self.copies_to_keep_checkbox = QCheckBox(_('Copies to keep'), self)
        self.copies_to_keep_checkbox.setToolTip(_("Select this to limit the number of backup kept. If not set, the backup files must be manually deleted."))
        self.copies_to_keep_spin = QSpinBox(self)
        self.copies_to_keep_spin.setMinimum(2)
        self.copies_to_keep_spin.setToolTip(_("The number of backup copies of the database to keep. The minimum is 2."))
        options_layout.addWidget(self.copies_to_keep_checkbox, 1, 3, 1, 1)
        options_layout.addWidget(self.copies_to_keep_spin, 1, 4, 1, 1)
        self.copies_to_keep_checkbox.clicked.connect(self.copies_to_keep_checkbox_clicked)
        if copies_to_keep == -1:
            self.copies_to_keep_checkbox.setCheckState(not Qt.Checked)
        else:
            self.copies_to_keep_checkbox.setCheckState(Qt.Checked)
            self.copies_to_keep_spin.setProperty('value', copies_to_keep)

        self.do_daily_backp_checkbox_clicked(do_daily_backup)

        other_options_group = QGroupBox(_('Other Options'), self)
        layout.addWidget(other_options_group )
        options_layout = QGridLayout()
        other_options_group.setLayout(options_layout)

        library_default_label = QLabel(_('&Library Button default:'), self)
        library_default_label.setToolTip(_('If plugin is placed as a toolbar button, choose a default action when clicked on'))
        self.library_default_combo = KeyComboBox(self, self.plugin_action.library_actions_map, unicode(get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_BUTTON_ACTION_LIBRARY)))
        library_default_label.setBuddy(self.library_default_combo)
        options_layout.addWidget(library_default_label, 0, 0, 1, 1)
        options_layout.addWidget(self.library_default_combo, 0, 1, 1, 2)

        device_default_label = QLabel(_('&Device Button default:'), self)
        device_default_label.setToolTip(_('If plugin is placed as a toolbar button, choose a default action when clicked on'))
        self.device_default_combo = KeyComboBox(self, self.plugin_action.device_actions_map, unicode(get_plugin_pref(COMMON_OPTIONS_STORE_NAME, KEY_BUTTON_ACTION_DEVICE)))
        device_default_label.setBuddy(self.device_default_combo)
        options_layout.addWidget(device_default_label, 1, 0, 1, 1)
        options_layout.addWidget(self.device_default_combo, 1, 1, 1, 2)

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

    def store_on_connect_checkbox_clicked(self, checked):
        self.prompt_to_store_checkbox.setEnabled(checked)
        self.store_if_more_recent_checkbox.setEnabled(checked)
        self.do_not_store_if_reopened_checkbox.setEnabled(checked)

    def do_daily_backp_checkbox_clicked(self, checked):
        self.dest_directory_edit.setEnabled(checked)
        self.dest_pick_button.setEnabled(checked)
        self.dest_directory_label.setEnabled(checked)
        self.copies_to_keep_checkbox.setEnabled(checked)
        self.copies_to_keep_checkbox_clicked(checked and self.copies_to_keep_checkbox.checkState() == Qt.Checked)

    def copies_to_keep_checkbox_clicked(self, checked):
        self.copies_to_keep_spin.setEnabled(checked)

    # Called by Calibre before save_settings 
    def validate(self):
#        import traceback
#        traceback.print_stack()
        
        debug_print('BEGIN Validate')
        valid = True
        # Only save if we were able to get data to avoid corrupting stored data
#        if self.do_daily_backp_checkbox.checkState() == Qt.Checked and not len(self.dest_directory_edit.text()):
#            error_dialog(self, 'No destination directory',
#                            'If the automatic device backup is set, there must be a destination directory.',
#                            show=True, show_copy_button=False)
#            valid = False

        debug_print('END Validate, status = %s' % valid)
        return valid

    def save_settings(self):

        new_prefs = {}
        new_prefs[KEY_BUTTON_ACTION_DEVICE]     = unicode(self.device_default_combo.currentText())
        new_prefs[KEY_BUTTON_ACTION_LIBRARY]    = unicode(self.library_default_combo.currentText())
        new_prefs[KEY_STORE_ON_CONNECT]         = self.store_on_connect_checkbox.checkState() == Qt.Checked
        new_prefs[KEY_PROMPT_TO_STORE]          = self.prompt_to_store_checkbox.checkState() == Qt.Checked
        new_prefs[KEY_STORE_IF_MORE_RECENT]     = self.store_if_more_recent_checkbox.checkState() == Qt.Checked
        new_prefs[KEY_DO_NOT_STORE_IF_REOPENED] = self.do_not_store_if_reopened_checkbox.checkState() == Qt.Checked
        plugin_prefs[COMMON_OPTIONS_STORE_NAME] = new_prefs

        new_update_prefs = {}
#         new_update_prefs[KEY_DO_UPDATE_CHECK]          = self.do_update_check.checkState() == Qt.Checked
#         new_update_prefs[KEY_DO_EARLY_FIRMWARE_CHECK]  = self.do_early_firmware_check.checkState() == Qt.Checked
#         new_update_prefs[KEY_LAST_FIRMWARE_CHECK_TIME] = self.update_check_last_time
        plugin_prefs[UPDATE_OPTIONS_STORE_NAME]        = new_update_prefs

        backup_prefs = {}
        backup_prefs[KEY_DO_DAILY_BACKUP]       = self.do_daily_backp_checkbox.checkState() == Qt.Checked
        backup_prefs[KEY_BACKUP_DEST_DIRECTORY] = unicode(self.dest_directory_edit.text())
        backup_prefs[KEY_BACKUP_COPIES_TO_KEEP] = int(unicode(self.copies_to_keep_spin.value())) if self.copies_to_keep_checkbox.checkState() == Qt.Checked else -1 
        plugin_prefs[BACKUP_OPTIONS_STORE_NAME] = backup_prefs

        db = self.plugin_action.gui.current_db
        library_config = get_library_config(db)
        library_config[KEY_CURRENT_LOCATION_CUSTOM_COLUMN] = self.current_Location_combo.get_selected_column()
        library_config[KEY_PERCENT_READ_CUSTOM_COLUMN]     = self.percent_read_combo.get_selected_column()
        library_config[KEY_RATING_CUSTOM_COLUMN]           = self.rating_combo.get_selected_column()
        library_config[KEY_LAST_READ_CUSTOM_COLUMN]        = self.last_read_combo.get_selected_column()
        set_library_config(db, library_config)

    def get_number_custom_columns(self):
        column_types = ['float','int']
        return self.get_custom_columns(column_types)

    def get_rating_custom_columns(self):
        column_types = ['rating','int']
        custom_columns = self.get_custom_columns(column_types)
        ratings_column_name = self.plugin_action.gui.library_view.model().orig_headers['rating']
        custom_columns['rating'] = {'name': ratings_column_name}
        return custom_columns

    def get_text_custom_columns(self):
        column_types = ['text']
        return self.get_custom_columns(column_types)

    def get_date_custom_columns(self):
        column_types = ['datetime']
        return self.get_custom_columns(column_types)

    def get_custom_columns(self, column_types):
        custom_columns = self.plugin_action.gui.library_view.model().custom_columns
        available_columns = {}
        for key, column in custom_columns.iteritems():
            typ = column['datatype']
            if typ in column_types and not column['is_multiple']:
                available_columns[key] = column
        return available_columns

    def help_link_activated(self, url):
        self.plugin_action.show_help(anchor="configuration")

    def edit_shortcuts(self):
        d = KeyboardConfigDialog(self.plugin_action.gui, self.plugin_action.action_spec[0])
        if d.exec_() == d.Accepted:
            self.plugin_action.gui.keyboard.finalize()

    def _get_dest_directory_name(self):
        path = choose_dir(self, 'backup annotations destination dialog','Choose destination directory')
        if path:
            self.dest_directory_edit.setText(path)
Exemple #57
0
class CalibreBookBrainzPluginDialog(QDialog):
    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()

    def exporttitlefromselected(self):
        rows = self.gui.current_view().selectionModel().selectedRows()
        if len(rows) == 0:
            self.search_space.setText("")
        else:
            mi = self.gui.library_view.model().db.get_metadata(rows[0].row())
            self.search_space.setText(mi.title)

    def search(self):

        text = self.search_space.text()
        print(text)
        self.listWidget.clear()
        self.listWidget.setFocus()
        try:
            url = "https://bookbrainz.org/ws/search/?q=\"" + text + "\"&mode=\"search\""
            hits = request_get(url)['hits']
        except:
            return
        numQueries = len(hits)
        act = 0
        for i in range(numQueries):
            enttype = hits[i]['_source']['_type']
            if not enttype in ['Publication', 'Work', 'Edition']:
                continue
            print(hits[i])
            item = QListWidgetItem("%i. %s BBID : %i" % ((act + 1), hits[i]['_source']['default_alias']['name'], 1))
            Qcol = QColor()
            if i % 2 == 0:
                Qcol.setRed(240)
                Qcol.setGreen(255)
                Qcol.setBlue(255)
            else:
                Qcol.setRed(220)
                Qcol.setGreen(255)
                Qcol.setBlue(240)
            item.setBackground(QBrush(Qcol))
            self.listWidget.addItem(item)
            act += 1

        self.listWidget.setFocus()
        self.searchExecutionButton.setFocus()

    def about(self):
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About the Calibre Book Brainz Plugin',
                          text.decode('utf-8'))

    def config(self):
        self.do_user_config(parent=self)
        # Apply the changes
        self.label.setText(prefs['hello_world_msg'])
class BookConfigWidget(QDialog):
    '''Creates book specific preferences dialog'''

    # title case given words except for articles in the middle
    # i.e the lord ruler would become The Lord Ruler but john the great would become John the Great
    ARTICLES = ['The', 'For', 'De', 'And', 'Or', 'Of', 'La']
    TITLE_CASE = lambda self, words: ' '.join([word.lower() if word in self.ARTICLES and index != 0
                                               else word for index, word in enumerate(words.title().split())])
    def __init__(self, parent, book_settings):
        QDialog.__init__(self, parent)
        self.resize(500, 500)
        self.setWindowTitle('title - author')

        self._index = 0
        self._book_settings = book_settings

        v_layout = QVBoxLayout(self)

        # add ASIN and Goodreads url text boxes and update buttons
        asin_browser_button, goodreads_browser_button = self._initialize_general(v_layout)

        # add scrollable area for aliases
        v_layout.addWidget(QLabel('Aliases:'))
        self._scroll_area = QScrollArea()
        v_layout.addWidget(self._scroll_area)

        # add status box
        self._status = QLabel('')
        v_layout.addWidget(self._status)

        previous_button = next_button = None
        if len(self._book_settings) > 1:
            previous_button = QPushButton('Previous')
            previous_button.setEnabled(False)
            previous_button.setFixedWidth(100)
            next_button = QPushButton('Next')
            next_button.setFixedWidth(100)
            previous_button.clicked.connect(lambda: self.previous_clicked(previous_button, next_button,
                                                                          asin_browser_button, goodreads_browser_button))
            next_button.clicked.connect(lambda: self.next_clicked(previous_button, next_button,
                                                                  asin_browser_button, goodreads_browser_button))
        self._initialize_navigation_buttons(v_layout, previous_button, next_button)

        self.setLayout(v_layout)
        self.show_book_prefs(asin_browser_button, goodreads_browser_button)
        self.show()

    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 sample xray label, line edit, and button to dialog
        self._sample_xray_edit = QLineEdit('')
        self._sample_xray_edit.textEdited.connect(lambda: self.edit_sample_xray(self._sample_xray_edit.text()))
        sample_xray_layout = QHBoxLayout(None)
        sample_xray_label = QLabel('X-Ray or JSON:')
        sample_xray_label.setFixedWidth(100)
        sample_xray_button = QPushButton('Browse...')
        sample_xray_button.clicked.connect(self.browse_sample_xray)
        sample_xray_button.setToolTip('Browse for a sample x-ray file or JSON to be used')
        sample_xray_layout.addWidget(sample_xray_label)
        sample_xray_layout.addWidget(self._sample_xray_edit)
        sample_xray_layout.addWidget(sample_xray_button)
        v_layout.addLayout(sample_xray_layout)

        # Add the update buttons to dialog
        search_buttons_layout = QHBoxLayout(None)
        search_asin_button = QPushButton('Search for ASIN')
        search_asin_button.setFixedWidth(225)
        search_asin_button.clicked.connect(lambda: self.search_for_asin_clicked(asin_browser_button))
        search_buttons_layout.addWidget(search_asin_button)
        search_goodreads_url_button = QPushButton('Search for Goodreads URL')
        search_goodreads_url_button.setFixedWidth(225)
        search_goodreads_url_button.clicked.connect(lambda: self.search_for_goodreads_url(goodreads_browser_button))
        search_buttons_layout.addWidget(search_goodreads_url_button)
        v_layout.addLayout(search_buttons_layout)

        update_buttons_layout = QHBoxLayout(None)
        self._update_from_url_button = QPushButton('Update Aliases from URL')
        self._update_from_url_button.setFixedWidth(225)
        self._update_from_url_button.clicked.connect(self.update_aliases_from_url)
        update_buttons_layout.addWidget(self._update_from_url_button)
        self._update_from_file_button = QPushButton('Update Aliases from Input File')
        self._update_from_file_button.setFixedWidth(225)
        self._update_from_file_button.clicked.connect(self.update_aliases_from_file)
        update_buttons_layout.addWidget(self._update_from_file_button)
        v_layout.addLayout(update_buttons_layout)

        return asin_browser_button, goodreads_browser_button

    def _initialize_navigation_buttons(self, v_layout, previous_button, next_button):
        '''Add previous, ok, cancel, and next buttons'''
        buttons_layout = QHBoxLayout(None)
        buttons_layout.setAlignment(Qt.AlignRight)

        if len(self._book_settings) > 1:
            buttons_layout.addWidget(previous_button)

        ok_button = QPushButton('OK')
        ok_button.setFixedWidth(100)
        ok_button.clicked.connect(self.ok_clicked)
        buttons_layout.addWidget(ok_button)

        cancel_button = QPushButton('Cancel')
        cancel_button.setFixedWidth(100)
        cancel_button.clicked.connect(self.cancel_clicked)
        buttons_layout.addWidget(cancel_button)

        if len(self._book_settings) > 1:
            buttons_layout.addWidget(next_button)

        v_layout.addLayout(buttons_layout)

    @property
    def book(self):
        return self._book_settings[self._index]

    def set_status_and_repaint(self, message):
        '''Sets the status text and redraws the status text box'''
        self._status.setText(message)
        self._status.repaint()

    def edit_asin(self, val, asin_browser_button):
        '''Set asin edit to specified value; update asin browser button accordingly'''
        self.book.asin = val
        if val == '':
            asin_browser_button.setEnabled(False)
        else:
            asin_browser_button.setEnabled(True)

    def edit_goodreads_url(self, val, goodreads_browser_button):
        '''Sets book's goodreads_url to val and warns if the url is invalid; update goodreads browser button accordingly'''
        self.book.goodreads_url = val
        if val == '':
            goodreads_browser_button.setEnabled(False)
            if self._status.text() == 'Warning: Invalid Goodreads URL. URL must have goodreads as the domain.':
                self._status.setText('')
        else:
            goodreads_browser_button.setEnabled(True)
            if 'goodreads.com' not in val:
                self._status.setText('Warning: Invalid Goodreads URL. URL must have goodreads as the domain.')

    def edit_sample_xray(self, val):
        '''Sets book's sample x-ray to val and warns if the file path is invalid'''
        self.book.sample_xray = val
        if os.path.isfile(val):
            if not val.lower().endwith('.json') and not val.lower().endswith('.asc'):
                return
            self.update_aliases_from_file()

    def search_for_asin_clicked(self, asin_browser_button):
        '''Searches for current book's ASIN on amazon'''
        asin = None
        self.set_status_and_repaint('Searching for ASIN...')
        if self.book.title != 'Unknown' and self.book.author != 'Unknown':
            asin = self.book.search_for_asin_on_amazon(self.book.title_and_author)
        if asin:
            self._status.setText('ASIN found.')
            asin_browser_button.setEnabled(True)
            self.book.asin = asin
            self._asin_edit.setText(asin)
        else:
            self._status.setText('ASIN not found.')
            asin_browser_button.setEnabled(False)
            self._asin_edit.setText('')

    def browse_amazon_url(self):
        '''Opens Amazon page for current book's ASIN using user's local store'''
        # Try to use the nearest Amazon store to the user.
        # If this fails we'll default to .com, the user will have to manually
        # edit the preferences file to fix it (it is a simple text file).
        if not prefs['tld']:
            import json
            from collections import defaultdict
            from urllib2 import urlopen, URLError

            try:
                country = json.loads(urlopen('http://ipinfo.io/json').read())['country']
            except (URLError, KeyError):
                country = 'unknown'
            country_tld = defaultdict(lambda: 'com', {'AU': 'com.au', 'BR': 'com.br', 'CA': 'ca', 'CN': 'cn', 'FR': 'fr',
                                                      'DE': 'de', 'IN': 'in', 'IT': 'it', 'JP': 'co.jp', 'MX': 'com.mx',
                                                      'NL': 'nl', 'ES': 'es', 'GB': 'co.uk', 'US': 'com'})
            prefs['tld'] = country_tld[country]
        webbrowser.open('https://www.amazon.{0}/gp/product/{1}/'.format(prefs['tld'], self._asin_edit.text()))

    def browse_goodreads_url(self):
        '''Opens url for current book's goodreads url'''
        webbrowser.open(self._goodreads_url_edit.text())

    def browse_sample_xray(self):
        """Browse for a sample xray file to use during x-ray creation"""
        file_dialog = QFileDialog(self)
        sample_file = file_dialog.getOpenFileName(caption='Choose sample x-ray to use:',
                                                  filter='X-Ray or JSON (*.asc *.json)')[0]
        self.book.sample_xray = sample_file
        self._sample_xray_edit.setText(sample_file)
        if sample_file:
            self.update_aliases_from_file()

    def search_for_goodreads_url(self, goodreads_browser_button):
        '''Searches for goodreads url using asin first then title and author if asin doesn't exist'''
        url = None
        self.set_status_and_repaint('Searching for Goodreads url...')
        if self.book.asin:
            url = self.book.search_for_goodreads_url(self.book.asin)
        if not url and self.book.title != 'Unknown' and self.book.author != 'Unknown':
            url = self.book.search_for_goodreads_url(self.book.title_and_author)
        if url:
            self._status.setText('Goodreads url found.')
            self._update_from_url_button.setEnabled(True)
            goodreads_browser_button.setEnabled(True)
            self.book.goodreads_url = url
            self._goodreads_url_edit.setText(url)
        else:
            self._status.setText('Goodreads url not found.')
            self._update_from_url_button.setEnabled(False)
            goodreads_browser_button.setEnabled(False)
            self._goodreads_url_edit.setText('')

    def update_aliases_from_url(self):
        '''Update aliases using goodreads'''
        if 'goodreads.com' not in self._goodreads_url_edit.text():
            self._status.setText('Error: Invalid Goodreads URL. URL must have goodreads as the domain.')
            return
        self.update_aliases_from_goodreads()

    def update_aliases_from_file(self):
        '''Update aliases on the preferences dailog using the information in the specified file'''
        self.set_status_and_repaint('Updating aliases...')
        if os.path.exists(self.book.sample_xray):
            self.book.update_aliases(self.book.sample_xray, source_type=os.path.splitext(self.book.sample_xray)[1][1:])
            self.update_aliases_on_gui()
            self._status.setText('Aliases updated.')
        else:
            self._status.setText('Error: Input file not found.')

    def update_aliases_from_goodreads(self):
        '''Updates aliases on the preferences dialog using the information on the current goodreads url'''
        try:
            self.set_status_and_repaint('Updating aliases...')
            self.book.update_aliases(self._goodreads_url_edit.text())
            self.update_aliases_on_gui()
            self._status.setText('Aliases updated.')
        except PageDoesNotExist:
            self._status.setText('Invalid Goodreads url.')

    def edit_aliases(self, term, val):
        '''Sets book's aliases to tuple (term, val)'''
        self.book.set_aliases(term, val)

    def previous_clicked(self, previous_button, next_button, asin_browser_button, goodreads_browser_button):
        '''Goes to previous book'''
        self._status.setText('')
        self._index -= 1
        next_button.setEnabled(True)
        if self._index == 0:
            previous_button.setEnabled(False)
        self.show_book_prefs(asin_browser_button, goodreads_browser_button)

    def ok_clicked(self):
        '''Saves book's settings using current settings'''
        for book in self._book_settings:
            book.save()
        self.close()

    def cancel_clicked(self):
        '''Closes dialog without saving settings'''
        self.close()

    def next_clicked(self, previous_button, next_button, asin_browser_button,
                     goodreads_browser_button):
        '''Goes to next book'''
        self._status.setText('')
        self._index += 1
        previous_button.setEnabled(True)
        if self._index == len(self._book_settings) - 1:
            next_button.setEnabled(False)
        self.show_book_prefs(asin_browser_button, goodreads_browser_button)

    def show_book_prefs(self, asin_browser_button, goodreads_browser_button):
        '''Shows current book's preferences'''
        self.setWindowTitle(self.book.title_and_author)

        self._asin_edit.setText(self.book.asin)
        if self._asin_edit.text() == '':
            asin_browser_button.setEnabled(False)
        else:
            asin_browser_button.setEnabled(True)

        self._goodreads_url_edit.setText(self.book.goodreads_url)
        if self._goodreads_url_edit.text() == '':
            goodreads_browser_button.setEnabled(False)
        else:
            goodreads_browser_button.setEnabled(True)

        self._sample_xray_edit.setText(self.book.sample_xray)

        self.update_aliases_on_gui()

    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)
Exemple #59
0
class ItemEdit(QWidget):

    def __init__(self, parent, prefs=None):
        QWidget.__init__(self, parent)
        self.prefs = prefs or gprefs
        self.setLayout(QVBoxLayout())

        self.la = la = QLabel('<b>'+_(
            'Select a destination for the Table of Contents entry'))
        self.layout().addWidget(la)
        self.splitter = sp = QSplitter(self)
        self.layout().addWidget(sp)
        self.layout().setStretch(1, 10)
        sp.setOpaqueResize(False)
        sp.setChildrenCollapsible(False)

        self.dest_list = dl = QListWidget(self)
        dl.setMinimumWidth(250)
        dl.currentItemChanged.connect(self.current_changed)
        sp.addWidget(dl)

        w = self.w = QWidget(self)
        l = w.l = QGridLayout()
        w.setLayout(l)
        self.view = WebView(self)
        self.view.elem_clicked.connect(self.elem_clicked)
        l.addWidget(self.view, 0, 0, 1, 3)
        sp.addWidget(w)

        self.search_text = s = QLineEdit(self)
        s.setPlaceholderText(_('Search for text...'))
        l.addWidget(s, 1, 0)
        self.ns_button = b = QPushButton(QIcon(I('arrow-down.png')), _('Find &next'), self)
        b.clicked.connect(self.find_next)
        l.addWidget(b, 1, 1)
        self.ps_button = b = QPushButton(QIcon(I('arrow-up.png')), _('Find &previous'), self)
        l.addWidget(b, 1, 2)
        b.clicked.connect(self.find_previous)

        self.f = f = QFrame()
        f.setFrameShape(f.StyledPanel)
        f.setMinimumWidth(250)
        l = f.l = QVBoxLayout()
        f.setLayout(l)
        sp.addWidget(f)

        f.la = la = QLabel('<p>'+_(
            'Here you can choose a destination for the Table of Contents\' entry'
            ' to point to. First choose a file from the book in the left-most panel. The'
            ' file will open in the central panel.<p>'

            'Then choose a location inside the file. To do so, simply click on'
            ' the place in the central panel that you want to use as the'
            ' destination. As you move the mouse around the central panel, a'
            ' thick green line appears, indicating the precise location'
            ' that will be selected when you click.'))
        la.setStyleSheet('QLabel { margin-bottom: 20px }')
        la.setWordWrap(True)
        l.addWidget(la)

        f.la2 = la = QLabel('<b>'+_('&Name of the ToC entry:'))
        l.addWidget(la)
        self.name = QLineEdit(self)
        la.setBuddy(self.name)
        l.addWidget(self.name)

        self.base_msg = '<b>'+_('Currently selected destination:')+'</b>'
        self.dest_label = la = QLabel(self.base_msg)
        la.setWordWrap(True)
        la.setStyleSheet('QLabel { margin-top: 20px }')
        l.addWidget(la)

        l.addStretch()

        state = self.prefs.get('toc_edit_splitter_state', None)
        if state is not None:
            sp.restoreState(state)

    def keyPressEvent(self, ev):
        if ev.key() in (Qt.Key_Return, Qt.Key_Enter) and self.search_text.hasFocus():
            # Prevent pressing enter in the search box from triggering the dialog's accept() method
            ev.accept()
            return
        return super(ItemEdit, self).keyPressEvent(ev)

    def find(self, forwards=True):
        text = unicode(self.search_text.text()).strip()
        flags = QWebPage.FindFlags(0) if forwards else QWebPage.FindBackward
        d = self.dest_list
        if d.count() == 1:
            flags |= QWebPage.FindWrapsAroundDocument
        if not self.view.findText(text, flags) and text:
            if d.count() == 1:
                return error_dialog(self, _('No match found'),
                    _('No match found for: %s')%text, show=True)

            delta = 1 if forwards else -1
            current = unicode(d.currentItem().data(Qt.DisplayRole) or '')
            next_index = (d.currentRow() + delta)%d.count()
            next = unicode(d.item(next_index).data(Qt.DisplayRole) or '')
            msg = '<p>'+_('No matches for %(text)s found in the current file [%(current)s].'
                          ' Do you want to search in the %(which)s file [%(next)s]?')
            msg = msg%dict(text=text, current=current, next=next,
                           which=_('next') if forwards else _('previous'))
            if question_dialog(self, _('No match found'), msg):
                self.pending_search = self.find_next if forwards else self.find_previous
                d.setCurrentRow(next_index)

    def find_next(self):
        return self.find()

    def find_previous(self):
        return self.find(forwards=False)

    def load(self, container):
        self.container = container
        spine_names = [container.abspath_to_name(p) for p in
                       container.spine_items]
        spine_names = [n for n in spine_names if container.has_name(n)]
        self.dest_list.addItems(spine_names)

    def current_changed(self, item):
        name = self.current_name = unicode(item.data(Qt.DisplayRole) or '')
        self.current_frag = None
        path = self.container.name_to_abspath(name)
        # Ensure encoding map is populated
        root = self.container.parsed(name)
        nasty = root.xpath('//*[local-name()="head"]/*[local-name()="p"]')
        if nasty:
            body = root.xpath('//*[local-name()="body"]')
            if not body:
                return error_dialog(self, _('Bad markup'),
                             _('This book has severely broken markup, its ToC cannot be edited.'), show=True)
            for x in reversed(nasty):
                body[0].insert(0, x)
            self.container.commit_item(name, keep_parsed=True)
        encoding = self.container.encoding_map.get(name, None) or 'utf-8'

        load_html(path, self.view, codec=encoding,
                  mime_type=self.container.mime_map[name])
        self.view.load_js()
        self.dest_label.setText(self.base_msg + '<br>' + _('File:') + ' ' +
                                name + '<br>' + _('Top of the file'))
        if hasattr(self, 'pending_search'):
            f = self.pending_search
            del self.pending_search
            f()

    def __call__(self, item, where):
        self.current_item, self.current_where = item, where
        self.current_name = None
        self.current_frag = None
        self.name.setText(_('(Untitled)'))
        dest_index, frag = 0, None
        if item is not None:
            if where is None:
                self.name.setText(item.data(0, Qt.DisplayRole) or '')
                self.name.setCursorPosition(0)
            toc = item.data(0, Qt.UserRole)
            if toc.dest:
                for i in xrange(self.dest_list.count()):
                    litem = self.dest_list.item(i)
                    if unicode(litem.data(Qt.DisplayRole) or '') == toc.dest:
                        dest_index = i
                        frag = toc.frag
                        break

        self.dest_list.blockSignals(True)
        self.dest_list.setCurrentRow(dest_index)
        self.dest_list.blockSignals(False)
        item = self.dest_list.item(dest_index)
        self.current_changed(item)
        if frag:
            self.current_frag = frag
            QTimer.singleShot(1, self.show_frag)

    def show_frag(self):
        self.view.show_frag(self.current_frag)
        QTimer.singleShot(1, self.check_frag)

    def check_frag(self):
        pos = self.view.scroll_frac
        if pos == 0:
            self.current_frag = None
        self.update_dest_label()

    def get_loctext(self, frac):
        frac = int(round(frac * 100))
        if frac == 0:
            loctext = _('Top of the file')
        else:
            loctext =  _('Approximately %d%% from the top')%frac
        return loctext

    def elem_clicked(self, tag, frac, elem_id, loc, totals):
        self.current_frag = elem_id or (loc, totals)
        base = _('Location: A &lt;%s&gt; tag inside the file')%tag
        loctext = base + ' [%s]'%self.get_loctext(frac)
        self.dest_label.setText(self.base_msg + '<br>' +
                    _('File:') + ' ' + self.current_name + '<br>' + loctext)

    def update_dest_label(self):
        val = self.view.scroll_frac
        self.dest_label.setText(self.base_msg + '<br>' +
                    _('File:') + ' ' + self.current_name + '<br>' +
                                self.get_loctext(val))

    @property
    def result(self):
        return (self.current_item, self.current_where, self.current_name,
                self.current_frag, unicode(self.name.text()))
Exemple #60
0
class ConfigWidget(QWidget):

    # GUI definition
    def __init__(self):
        QWidget.__init__(self)
        self.l = QVBoxLayout()
        self.setLayout(self.l)

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

        self.label_exe = QLabel(_('&Prince executable:'))
        self.ll.addWidget(self.label_exe)

        self.exe = QLineEdit(self)
        self.exe.setText(prefs['prince_exe'])
        self.exe.setToolTip(_('<qt>Executable for the Prince program (command-line interface)</qt>'))
        self.ll.addWidget(self.exe)
        self.label_exe.setBuddy(self.exe)

        self.browse = QPushButton(_('&Browse') + '...', self)
        self.browse.setToolTip(_('<qt>Search the Prince executable in your computer</qt>'))
        self.browse.clicked.connect(self.select_exe)
        self.ll.addWidget(self.browse)

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

        self.label_fmts = QLabel(_('Preferred &formats:'))
        self.lll.addWidget(self.label_fmts)

        self.fmts = QLineEdit(self)
        self.fmts.setText(','.join(prefs['formats']))
        self.fmts.setToolTip(_('<qt>Comma-separated list of preferred formats to use as source, the first that matches will be used</qt>'))
        self.lll.addWidget(self.fmts)
        self.label_fmts.setBuddy(self.fmts)

        self.add_book = QCheckBox(_('&Add PDF to the book record'))
        self.add_book.setToolTip(_('<qt>Add the converted PDF to the selected book record</qt>'))
        self.add_book.setChecked(prefs['add_book'])
        self.l.addWidget(self.add_book)

        self.show_css = QCheckBox(_('&Show CSS in the Convert dialog'))
        self.show_css.setToolTip(_('<qt>Show by default the stylesheets in the Convert dialog</qt>'))
        self.show_css.setChecked(prefs['show_CSS'])
        self.l.addWidget(self.show_css)

        self.css_layout = QVBoxLayout()

        self.llll = QHBoxLayout()
        self.css_layout.addLayout(self.llll)

        self.css_list = QComboBox()
        self.css_list.setToolTip(_('<qt>List of custom stylesheets defined. Select one to edit</qt>'))
        self.css_list.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.CSS_list = prefs['custom_CSS_list'].copy()
        self.default_CSS = prefs['default_CSS']
        if 'custom_CSS' in prefs:
            self.CSS_list[_('old')] = prefs['custom_CSS']
            self.default_CSS = _('old')
        if self.default_CSS not in self.CSS_list:
            self.default_CSS = sorted(self.CSS_list, key=lambda x: x.lower())[0]
        for key in sorted(self.CSS_list, key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(self.default_CSS))
        self.css_list.currentIndexChanged.connect(self.set_css)
        self.llll.addWidget(self.css_list)

        self.css_rename = QPushButton(_('Re&name'))
        self.css_rename.setToolTip(_('<qt>Rename the current stylesheet to the name on the right</qt>'))
        self.css_rename.clicked.connect(self.rename_css)
        self.css_rename.setEnabled(False)
        self.llll.addWidget(self.css_rename)

        self.css_name = QLineEdit(self)
        self.css_name.setToolTip(_('<qt>Name for the new or renamed stylesheet</qt>'))
        self.css_name.setText(self.css_list.currentText())
        self.css_name.textChanged.connect(self.check_names)
        self.llll.addWidget(self.css_name)

        self.css_add = QPushButton(_('A&dd'))
        self.css_add.setToolTip(_('<qt>Add a new empty stylesheet with the name on the left</qt>'))
        self.css_add.clicked.connect(self.add_css)
        self.css_add.setEnabled(False)
        self.llll.addWidget(self.css_add)

        self.css_remove = QPushButton(_('Re&move'))
        self.css_remove.setToolTip(_('<qt>Remove the current stylesheet</qt>'))
        self.css_remove.clicked.connect(self.remove_css)
        self.llll.addWidget(self.css_remove)

        self.css = TextEditWithTooltip()
        self.css.setLineWrapMode(TextEditWithTooltip.NoWrap)
        self.css.load_text(self.CSS_list[unicode(self.css_list.currentText())],'css')
        self.css.setToolTip(_('<qt>Custom stylesheet that will be applied, if selected, to all Prince PDF conversions</qt>'))
        self.css_layout.addWidget(self.css)

        self.css_templates = QLabel(_('Book metadata can be used in the stylesheet. Anything between %(s1)s and %(s2)s will be processed as a calibre template. For instance, %(s3)s in the stylesheet will be replaced with the book title in the conversion.') % \
          {'s1':'<span style="font-family:monospace ; font-weight:bold">@{@</span>', \
           's2':'<span style="font-family:monospace ; font-weight:bold">@}@</span>', \
           's3':'<span style="font-family:monospace ; font-weight:bold">@{@{title}@}@</span>'})
        self.css_templates.setWordWrap(True)
        self.css_layout.addWidget(self.css_templates)

        self.css_box = QGroupBox(_('&Custom CSS:'))
        self.css_box.setLayout(self.css_layout)
        self.l.addWidget(self.css_box)

        self.lllll = QHBoxLayout()
        self.lllll.setAlignment(Qt.AlignLeft)
        self.l.addLayout(self.lllll)

        self.defaults = QPushButton(_('&Restore defaults'))
        self.defaults.setToolTip(_('<qt>Restore the default settings</qt>'))
        self.defaults.clicked.connect(self.restore_defaults)
        self.lllll.addWidget(self.defaults, alignment=Qt.AlignLeft)

        self.warning = QLabel(_('<b>Warning</b>: Deletes modified stylesheets'))
        self.lllll.addWidget(self.warning)

        self.adjustSize()

    def select_exe(self):
        '''
        Create a dialog to select the Prince executable
        '''
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        filename = dialog.getOpenFileName(self, _('Select Prince executable'), '', '')
        if filename:
            try:
                self.exe.setText(filename)
            except(TypeError):
                self.exe.setText(filename[0])

    def restore_defaults(self):
        '''
        Restore the default settings
        '''
        self.exe.setText(prefs.defaults['prince_exe'])
        self.fmts.setText(','.join(prefs.defaults['formats']).lower())
        self.show_css.setChecked(prefs.defaults['show_CSS'])
        self.add_book.setChecked(prefs.defaults['add_book'])
        self.css_list.currentIndexChanged.disconnect()
        self.css_list.clear()
        self.CSS_list = prefs.defaults['custom_CSS_list'].copy()
        self.default_CSS = prefs.defaults['default_CSS']
        for key in sorted(self.CSS_list, key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(self.default_CSS))
        self.css_name.setText(self.default_CSS)
        self.css.load_text(self.CSS_list[unicode(self.css_list.currentText())],'css')
        self.css_list.currentIndexChanged.connect(self.set_css)

    def save_settings(self):
        '''
        Save the current settings
        '''
        prefs['prince_exe'] = unicode(self.exe.text())
        prefs['formats'] = unicode(self.fmts.text().lower()).split(',')
        prefs['show_CSS'] = self.show_css.isChecked()
        prefs['add_book'] = self.add_book.isChecked()
        self.set_css()
        prefs['default_CSS'] = self.default_CSS
        prefs['custom_CSS_list'] = self.CSS_list.copy()
        if 'custom_CSS' in prefs:
            del prefs['custom_CSS']

    def set_css(self):
        '''
        Fill the CSS text box with the selected stylesheet
        '''
        self.CSS_list[self.default_CSS] = unicode(self.css.toPlainText())
        self.default_CSS = unicode(self.css_list.currentText())
        self.css.load_text(self.CSS_list[self.default_CSS],'css')
        self.css_name.setText(self.css_list.currentText())

    def add_css(self):
        '''
        Add a new stylesheet
        '''
        from calibre.gui2 import error_dialog

        name = unicode(self.css_name.text())
        if name in self.CSS_list:
            error_dialog(self, _('Cannot add stylesheet'), _('A stylesheet with the name "%s" is already defined, use a different name.') % name, show=True)
        else:
            self.CSS_list[name] = ''
            self.css_list.addItem(name, name)
            self.css_list.setCurrentIndex(self.css_list.findText(name))
            self.css_add.setEnabled(False)
            self.css_rename.setEnabled(False)

    def remove_css(self):
        '''
        Remove an existing stylesheet
        '''
        from calibre.gui2 import error_dialog

        if (self.css_list.count() > 1):
            self.css_list.currentIndexChanged.disconnect()
            self.css_list.removeItem(self.css_list.currentIndex())
            del self.CSS_list[self.default_CSS]
            self.default_CSS = unicode(self.css_list.currentText())
            self.css.load_text(self.CSS_list[self.default_CSS],'css')
            self.css_list.currentIndexChanged.connect(self.set_css)
            self.css_name.setText(self.css_list.currentText())
        else:
            error_dialog(self, _('Cannot delete the last stylesheet'), _('The last stylesheet cannot be removed. You can rename it and/or remove its contents.'), show=True)

    def rename_css(self):
        '''
        Rename a stylesheet
        '''
        from calibre.gui2 import error_dialog

        name = unicode(self.css_name.text())
        if name in self.CSS_list:
            error_dialog(self, _('Cannot rename stylesheet'), _('A stylesheet with the name "%s" is already defined, use a different name.') % name, show=True)
        else:
            self.CSS_list[name] = self.CSS_list.pop(self.default_CSS)
            self.css_list.setItemText(self.css_list.currentIndex(),name)
            self.default_CSS = name

    def check_names(self, text):
        name = unicode(text)
        if name in self.CSS_list:
            self.css_add.setEnabled(False)
            self.css_rename.setEnabled(False)
        else:
            self.css_add.setEnabled(True)
            self.css_rename.setEnabled(True)