def __init__(self, gui, interface_action, books): ''' :param gui: Parent gui :param interface_action: InterfaceActionObject (InterfacePluginAction class from action.py) :param books: list of Kobo book ''' self.books = books self.gui = gui self.interface_action = interface_action self.books = books SizePersistedDialog.__init__(self, gui, PLUGIN_NAME + 'plugin:selections dialog') self.setWindowTitle(_(PLUGIN_NAME + ' v' + PLUGIN_VERSION)) self.setMinimumWidth(300) self.setMinimumHeight(300) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'images/obok.png', _('Obok DeDRM')) layout.addLayout(title_layout) help_label = QLabel(_('<a href="http://www.foo.com/">Help</a>'), self) help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_label.setAlignment(Qt.AlignRight) help_label.linkActivated.connect(self._help_link_activated) title_layout.addWidget(help_label) title_layout.setAlignment(Qt.AlignTop) layout.addSpacing(5) main_layout = QHBoxLayout() layout.addLayout(main_layout) # self.listy = QListWidget() # self.listy.setSelectionMode(QAbstractItemView.ExtendedSelection) # main_layout.addWidget(self.listy) # self.listy.addItems(books) self.books_table = BookListTableWidget(self) main_layout.addWidget(self.books_table) layout.addSpacing(10) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self._ok_clicked) button_box.rejected.connect(self.reject) self.select_all_button = button_box.addButton(_("Select All"), QDialogButtonBox.ResetRole) self.select_all_button.setToolTip(_("Select all books to add them to the calibre library.")) self.select_all_button.clicked.connect(self._select_all_clicked) self.select_drm_button = button_box.addButton(_("All with DRM"), QDialogButtonBox.ResetRole) self.select_drm_button.setToolTip(_("Select all books with DRM.")) self.select_drm_button.clicked.connect(self._select_drm_clicked) self.select_free_button = button_box.addButton(_("All DRM free"), QDialogButtonBox.ResetRole) self.select_free_button.setToolTip(_("Select all books without DRM.")) self.select_free_button.clicked.connect(self._select_free_clicked) layout.addWidget(button_box) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() self.books_table.populate_table(self.books)
def _init_controls(self): layout = QVBoxLayout(self) self.setLayout(layout) ml = QHBoxLayout() layout.addLayout(ml, 1) self.keys_list = QListWidget(self) self.keys_list.setSelectionMode(QAbstractItemView.SingleSelection) self.keys_list.setFixedWidth(150) self.keys_list.setAlternatingRowColors(True) ml.addWidget(self.keys_list) self.value_text = QTextEdit(self) self.value_text.setTabStopWidth(24) self.value_text.setReadOnly(False) ml.addWidget(self.value_text, 1) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self._apply_changes) button_box.rejected.connect(self.reject) self.clear_button = button_box.addButton('Clear', QDialogButtonBox.ResetRole) self.clear_button.setIcon(get_icon('trash.png')) self.clear_button.setToolTip('Clear all settings for this plugin') self.clear_button.clicked.connect(self._clear_settings) layout.addWidget(button_box)
def init_UI(self): """create both buttons, arrange them and connect them """ if self.direction == Qt.Horizontal: layout = QHBoxLayout() spacer_width = self.stretch spacer_height = 1 else: layout = QVBoxLayout() spacer_width = 1 spacer_height = self.stretch self.setLayout(layout) self.confirm_btn = ConfirmResetButton("Confirm all changes", "confirm", self.widgets, self.log, self) self.confirm_btn.clicked.connect(self.on_data_changed) layout.addWidget(self.confirm_btn) if self.stretch: layout.addSpacerItem(QSpacerItem(spacer_width, spacer_height, QSizePolicy.Expanding, QSizePolicy.Expanding)) self.reset_btn = ConfirmResetButton("Reset all changes", "reset", self.widgets, self.log, self) self.reset_btn.clicked.connect(self.on_data_changed) layout.addWidget(self.reset_btn) for widget in self.widgets: widget.model.dataChanged.connect(self.on_data_changed) self.confirm_btn.clicked.connect(self.reset_btn.normalize) self.reset_btn.clicked.connect(self.confirm_btn.normalize)
def initialize(self, item): """ Initialize Actions QWidget, with ack and downtime buttons """ self.item = item layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.acknowledge_btn.setIcon(QIcon(settings.get_image('acknowledge'))) self.acknowledge_btn.setFixedSize(80, 20) self.acknowledge_btn.clicked.connect(self.add_acknowledge) self.acknowledge_btn.setToolTip(_('Acknowledge the current item')) layout.addWidget(self.acknowledge_btn) self.downtime_btn.setIcon(QIcon(settings.get_image('downtime'))) self.downtime_btn.setFixedSize(80, 20) self.downtime_btn.clicked.connect(self.add_downtime) self.downtime_btn.setToolTip(_('Schedule a Downtime on current item')) layout.addWidget(self.downtime_btn) layout.setAlignment(Qt.AlignCenter)
def setup_ui(self): from calibre.gui2.preferences.look_feel import DisplayedFields, move_field_up, move_field_down self.l = QVBoxLayout(self) self.field_display_order = fdo = QListView(self) self.model = DisplayedFields(self.db, fdo, pref_name='popup_book_display_fields') self.model.initialize() fdo.setModel(self.model) fdo.setAlternatingRowColors(True) del self.db self.l.addWidget(QLabel('Select displayed metadata')) h = QHBoxLayout() h.addWidget(fdo) v = QVBoxLayout() self.mub = b = QToolButton(self) b.clicked.connect(partial(move_field_up, fdo, self.model)) b.setIcon(QIcon(I('arrow-up.png'))) b.setToolTip(_('Move the selected field up')) v.addWidget(b), v.addStretch(10) self.mud = b = QToolButton(self) b.setIcon(QIcon(I('arrow-down.png'))) b.setToolTip(_('Move the selected field down')) b.clicked.connect(partial(move_field_down, fdo, self.model)) v.addWidget(b) h.addLayout(v) self.l.addLayout(h) self.l.addWidget(QLabel('<p>' + _( 'Note that <b>comments</b> will always be displayed at the end, regardless of the order you assign here'))) b = self.bb.addButton(_('Restore &defaults'), self.bb.ActionRole) b.clicked.connect(self.restore_defaults) self.l.addWidget(self.bb) self.setMinimumHeight(500)
class BarTitle(QWidget): # {{{ def __init__(self, parent=None): QWidget.__init__(self, parent) self._layout = QHBoxLayout() self.setLayout(self._layout) self._layout.addStretch(10) self.icon = QLabel('') self._layout.addWidget(self.icon) self.title = QLabel('') self.title.setStyleSheet('QLabel { font-weight: bold }') self.title.setAlignment(Qt.AlignLeft | Qt.AlignCenter) self._layout.addWidget(self.title) self._layout.addStretch(10) def show_plugin(self, plugin): self.pmap = QPixmap(plugin.icon).scaled(ICON_SIZE, ICON_SIZE, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.icon.setPixmap(self.pmap) self.title.setText(plugin.gui_name) tt = plugin.description self.setStatusTip(tt) tt = textwrap.fill(tt) self.setToolTip(tt) self.setWhatsThis(tt)
def setup_ui(self, parent): cm = self.col_metadata self.make_widgets(parent, DateTimeEdit) self.widgets.append(QLabel("")) w = QWidget(parent) self.widgets.append(w) l = QHBoxLayout() l.setContentsMargins(0, 0, 0, 0) w.setLayout(l) l.addStretch(1) self.today_button = QPushButton(_("Set '%s' to today") % cm["name"], parent) l.addWidget(self.today_button) self.clear_button = QPushButton(_("Clear '%s'") % cm["name"], parent) l.addWidget(self.clear_button) l.addStretch(2) w = self.main_widget format = cm["display"].get("date_format", "") if not format: format = "dd MMM yyyy" w.setDisplayFormat(format) w.setCalendarPopup(True) w.setMinimumDateTime(UNDEFINED_QDATETIME) w.setSpecialValueText(_("Undefined")) self.today_button.clicked.connect(w.set_to_today) self.clear_button.clicked.connect(w.set_to_clear)
def __init__(self, parent=None,): QDialog.__init__(self, parent) self.parent = parent self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION)) layout = QVBoxLayout(self) self.setLayout(layout) data_group_box = QGroupBox(u"", self) layout.addWidget(data_group_box) data_group_box_layout = QVBoxLayout() data_group_box.setLayout(data_group_box_layout) key_group = QHBoxLayout() data_group_box_layout.addLayout(key_group) key_group.addWidget(QLabel(u"PID:", self)) self.key_ledit = QLineEdit("", self) self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") key_group.addWidget(self.key_ledit) self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) layout.addWidget(self.button_box) self.resize(self.sizeHint())
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())
def __init__(self, parent=None,): QDialog.__init__(self, parent) self.parent = parent self.setWindowTitle(u"{0} {1}: Add New Kindle for Android Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION)) layout = QVBoxLayout(self) self.setLayout(layout) data_group_box = QGroupBox(u"", self) layout.addWidget(data_group_box) data_group_box_layout = QVBoxLayout() data_group_box.setLayout(data_group_box_layout) key_group = QHBoxLayout() data_group_box_layout.addLayout(key_group) key_group.addWidget(QLabel(u"Kindle for Android Serial Number:", self)) self.key_ledit = QLineEdit("", self) self.key_ledit.setToolTip(u"Enter a Kindle for ANdroid serial number. These can be found using the androidkindlekey.py script.") key_group.addWidget(self.key_ledit) key_label = QLabel(_(''), self) key_label.setAlignment(Qt.AlignHCenter) data_group_box_layout.addWidget(key_label) self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) layout.addWidget(self.button_box) self.resize(self.sizeHint())
def get_search_widget(self): """ Create and return the search QWidget :return: search QWidget :rtype: QWidget """ widget = QWidget() layout = QHBoxLayout() layout.setSpacing(0) widget.setLayout(layout) # Search label search_lbl = QLabel(_('Search Host')) search_lbl.setObjectName('bordertitle') search_lbl.setFixedHeight(25) search_lbl.setToolTip(_('Search Host')) layout.addWidget(search_lbl) # QLineEdit self.line_search.setFixedHeight(search_lbl.height()) layout.addWidget(self.line_search) self.create_line_search([]) return widget
class CursorPositionWidget(QWidget): # {{{ def __init__(self, parent): QWidget.__init__(self, parent) self.l = QHBoxLayout(self) self.setLayout(self.l) self.la = QLabel('') self.l.addWidget(self.la) self.l.setContentsMargins(0, 0, 0, 0) f = self.la.font() f.setBold(False) self.la.setFont(f) def update_position(self, line=None, col=None, character=None): if line is None: self.la.setText('') else: try: name = character_name(character) if character and tprefs['editor_show_char_under_cursor'] else None except Exception: name = None text = _('Line: {0} : {1}').format(line, col) if not name: name = {'\t':'TAB'}.get(character, None) if name and tprefs['editor_show_char_under_cursor']: text = name + ' : ' + text self.la.setText(text)
def make_widgets(self, parent, main_widget_class, extra_label_text=''): w = QWidget(parent) self.widgets = [QLabel('&'+self.col_metadata['name']+':', w), w] l = QHBoxLayout() l.setContentsMargins(0, 0, 0, 0) w.setLayout(l) self.main_widget = main_widget_class(w) l.addWidget(self.main_widget) l.setStretchFactor(self.main_widget, 10) self.a_c_checkbox = QCheckBox(_('Apply changes'), w) l.addWidget(self.a_c_checkbox) self.ignore_change_signals = True # connect to the various changed signals so we can auto-update the # apply changes checkbox if hasattr(self.main_widget, 'editTextChanged'): # editable combobox widgets self.main_widget.editTextChanged.connect(self.a_c_checkbox_changed) if hasattr(self.main_widget, 'textChanged'): # lineEdit widgets self.main_widget.textChanged.connect(self.a_c_checkbox_changed) if hasattr(self.main_widget, 'currentIndexChanged'): # combobox widgets self.main_widget.currentIndexChanged[int].connect(self.a_c_checkbox_changed) if hasattr(self.main_widget, 'valueChanged'): # spinbox widgets self.main_widget.valueChanged.connect(self.a_c_checkbox_changed) if hasattr(self.main_widget, 'dateTimeChanged'): # dateEdit widgets self.main_widget.dateTimeChanged.connect(self.a_c_checkbox_changed)
def setup_ui(self, parent): cm = self.col_metadata self.make_widgets(parent, DateTimeEdit) self.widgets.append(QLabel('')) w = QWidget(parent) self.widgets.append(w) l = QHBoxLayout() l.setContentsMargins(0, 0, 0, 0) w.setLayout(l) l.addStretch(1) self.today_button = QPushButton(_('Set \'%s\' to today')%cm['name'], parent) l.addWidget(self.today_button) self.clear_button = QPushButton(_('Clear \'%s\'')%cm['name'], parent) l.addWidget(self.clear_button) l.addStretch(2) w = self.main_widget format = cm['display'].get('date_format','') if not format: format = 'dd MMM yyyy' w.setDisplayFormat(format) w.setCalendarPopup(True) w.setMinimumDateTime(UNDEFINED_QDATETIME) w.setSpecialValueText(_('Undefined')) self.today_button.clicked.connect(w.set_to_today) self.clear_button.clicked.connect(w.set_to_clear)
def __init__(self): QWidget.__init__(self) self.l = QVBoxLayout() self.setLayout(self.l) self.cbox1 = QCheckBox("Reformatting") self.cbox1.setChecked(prefs["reformat"]) self.l.addWidget(self.cbox1) self.cbox5 = QCheckBox("Paragraph by Ending mark") self.cbox5.setChecked(prefs["para_by_mark"]) self.l.addWidget(self.cbox5) self.cbox2 = QCheckBox("Pretty Quote char") self.cbox2.setChecked(prefs["pretty_quote"]) self.l.addWidget(self.cbox2) self.cbox3 = QCheckBox("Guess Chapter") self.cbox3.setChecked(prefs["guess_chapter"]) self.l.addWidget(self.cbox3) self.cbox4 = QCheckBox("Allow Empty Paragraph") self.cbox4.setChecked(prefs["insert_empty_paragraph"]) self.l.addWidget(self.cbox4) cl = QHBoxLayout() cl.addWidget(QLabel("Broken Word over lines")) self.combo1 = QComboBox() wbrk_list = ["None", "Pattern", "Naver"] self.combo1.addItems(wbrk_list) self.combo1.setCurrentIndex(wbrk_list.index(prefs["correct_word_break"])) cl.addWidget(self.combo1) self.l.addLayout(cl)
def create_color_button(key, text): b = ColorButton(data, key, text, self) b.changed.connect(self.changed), l.addWidget(b) bc = QToolButton(self) bc.setIcon(QIcon(I('clear_left.png'))) bc.setToolTip(_('Remove color')) bc.clicked.connect(b.clear) h = QHBoxLayout() h.addWidget(b), h.addWidget(bc) return h
def setup_ui(self, parent): self.make_widgets(parent, EditWithComplete) values = self.all_values = list(self.db.all_custom(num=self.col_id)) values.sort(key=sort_key) self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon) self.main_widget.setMinimumContentsLength(25) self.widgets.append(QLabel('', parent)) w = QWidget(parent) layout = QHBoxLayout(w) layout.setContentsMargins(0, 0, 0, 0) self.remove_series = QCheckBox(parent) self.remove_series.setText(_('Clear series')) layout.addWidget(self.remove_series) self.idx_widget = QCheckBox(parent) self.idx_widget.setText(_('Automatically number books')) self.idx_widget.setToolTip('<p>' + _( 'If not checked, the series number for the books will be set to 1. ' 'If checked, selected books will be automatically numbered, ' 'in the order you selected them. So if you selected ' 'Book A and then Book B, Book A will have series number 1 ' 'and Book B series number 2.') + '</p>') layout.addWidget(self.idx_widget) self.force_number = QCheckBox(parent) self.force_number.setText(_('Force numbers to start with ')) self.force_number.setToolTip('<p>' + _( 'Series will normally be renumbered from the highest ' 'number in the database for that series. Checking this ' 'box will tell calibre to start numbering from the value ' 'in the box') + '</p>') layout.addWidget(self.force_number) self.series_start_number = QDoubleSpinBox(parent) self.series_start_number.setMinimum(0.0) self.series_start_number.setMaximum(9999999.0) self.series_start_number.setProperty("value", 1.0) layout.addWidget(self.series_start_number) self.series_increment = QDoubleSpinBox(parent) self.series_increment.setMinimum(0.00) self.series_increment.setMaximum(99999.0) self.series_increment.setProperty("value", 1.0) self.series_increment.setToolTip('<p>' + _( 'The amount by which to increment the series number ' 'for successive books. Only applicable when using ' 'force series numbers.') + '</p>') self.series_increment.setPrefix('+') layout.addWidget(self.series_increment) layout.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.widgets.append(w) self.idx_widget.stateChanged.connect(self.a_c_checkbox_changed) self.force_number.stateChanged.connect(self.a_c_checkbox_changed) self.series_start_number.valueChanged.connect(self.a_c_checkbox_changed) self.series_increment.valueChanged.connect(self.a_c_checkbox_changed) self.remove_series.stateChanged.connect(self.a_c_checkbox_changed) self.main_widget self.ignore_change_signals = False
def __init__(self, parent=None): QDialog.__init__(self, parent) self.parent = parent self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION)) layout = QVBoxLayout(self) self.setLayout(layout) try: if iswindows or isosx: from calibre_plugins.dedrm.adobekey import adeptkeys defaultkeys = adeptkeys() else: # linux from wineutils import WineGetKeys scriptpath = os.path.join(parent.parent.alfdir, u"adobekey.py") defaultkeys = WineGetKeys(scriptpath, u".der", parent.getwineprefix()) self.default_key = defaultkeys[0] except: traceback.print_exc() self.default_key = u"" self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) if len(self.default_key) > 0: data_group_box = QGroupBox(u"", self) layout.addWidget(data_group_box) data_group_box_layout = QVBoxLayout() data_group_box.setLayout(data_group_box_layout) key_group = QHBoxLayout() data_group_box_layout.addLayout(key_group) key_group.addWidget(QLabel(u"Unique Key Name:", self)) self.key_ledit = QLineEdit(u"default_key", self) self.key_ledit.setToolTip( u"<p>Enter an identifying name for the current default Adobe Digital Editions key." ) key_group.addWidget(self.key_ledit) self.button_box.accepted.connect(self.accept) else: default_key_error = QLabel( u"The default encryption key for Adobe Digital Editions could not be found.", self ) default_key_error.setAlignment(Qt.AlignHCenter) layout.addWidget(default_key_error) # if no default, bot buttons do the same self.button_box.accepted.connect(self.reject) self.button_box.rejected.connect(self.reject) layout.addWidget(self.button_box) self.resize(self.sizeHint())
def __init__(self, gui, header, prefs, icon, books, save_size_name='epubmerge:update list dialog'): SizePersistedDialog.__init__(self, gui, save_size_name) self.gui = gui self.setWindowTitle(header) self.setWindowIcon(icon) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'images/icon.png', header) layout.addLayout(title_layout) books_layout = QHBoxLayout() layout.addLayout(books_layout) self.books_table = StoryListTableWidget(self) books_layout.addWidget(self.books_table) button_layout = QVBoxLayout() books_layout.addLayout(button_layout) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) self.move_up_button = QtGui.QToolButton(self) self.move_up_button.setToolTip(_('Move selected books up the list')) self.move_up_button.setIcon(QIcon(I('arrow-up.png'))) self.move_up_button.clicked.connect(self.books_table.move_rows_up) button_layout.addWidget(self.move_up_button) self.remove_button = QtGui.QToolButton(self) self.remove_button.setToolTip(_('Remove selected books from the list')) self.remove_button.setIcon(get_icon('list_remove.png')) self.remove_button.clicked.connect(self.remove_from_list) button_layout.addWidget(self.remove_button) self.move_down_button = QtGui.QToolButton(self) self.move_down_button.setToolTip(_('Move selected books down the list')) self.move_down_button.setIcon(QIcon(I('arrow-down.png'))) self.move_down_button.clicked.connect(self.books_table.move_rows_down) button_layout.addWidget(self.move_down_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem1) options_layout = QHBoxLayout() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) options_layout.addWidget(button_box) layout.addLayout(options_layout) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() self.books_table.populate_table(books)
class DaysOfWeek(Base): HELP = _('''\ Download this periodical every week on the specified days after the specified time. For example, if you choose: Monday after 9:00 AM, then the periodical will be download every Monday as soon after 9:00 AM as possible. ''') def __init__(self, parent=None): Base.__init__(self, parent) self.days = [ QCheckBox(force_unicode(calendar.day_abbr[d]), self) for d in xrange(7) ] for i, cb in enumerate(self.days): row = i % 2 col = i // 2 self.l.addWidget(cb, row, col, 1, 1) self.time = QTimeEdit(self) self.time.setDisplayFormat('hh:mm AP') if canonicalize_lang(get_lang()) in {'deu', 'nds'}: self.time.setDisplayFormat('HH:mm') self.hl = QHBoxLayout() self.l1 = QLabel(_('&Download after:')) self.l1.setBuddy(self.time) self.hl.addWidget(self.l1) self.hl.addWidget(self.time) self.l.addLayout(self.hl, 1, 3, 1, 1) self.initialize() def initialize(self, typ=None, val=None): if typ is None: typ = 'day/time' val = (-1, 6, 0) if typ == 'day/time': val = convert_day_time_schedule(val) days_of_week, hour, minute = val for i, d in enumerate(self.days): d.setChecked(i in days_of_week) self.time.setTime(QTime(hour, minute)) @property def schedule(self): days_of_week = tuple( [i for i, d in enumerate(self.days) if d.isChecked()]) t = self.time.time() hour, minute = t.hour(), t.minute() return 'days_of_week', (days_of_week, int(hour), int(minute))
def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""): QDialog.__init__(self,parent) self.parent = parent self.key_type_name = key_type_name self.plugin_keys = plugin_keys self.create_key = create_key self.keyfile_ext = keyfile_ext self.json_file = (keyfile_ext == u"k4i") self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) # Start Qt Gui dialog layout layout = QVBoxLayout(self) self.setLayout(layout) keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) layout.addWidget(keys_group_box) keys_group_box_layout = QHBoxLayout() keys_group_box.setLayout(keys_group_box_layout) self.listy = QListWidget(self) self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name)) self.listy.setSelectionMode(QAbstractItemView.SingleSelection) self.populate_list() keys_group_box_layout.addWidget(self.listy) button_layout = QVBoxLayout() keys_group_box_layout.addLayout(button_layout) self._add_key_button = QtGui.QToolButton(self) self._add_key_button.setIcon(QIcon(I('plus.png'))) self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name)) self._add_key_button.clicked.connect(self.add_key) button_layout.addWidget(self._add_key_button) self._delete_key_button = QtGui.QToolButton(self) self._delete_key_button.setToolTip(_(u"Delete highlighted key")) self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) self._delete_key_button.clicked.connect(self.delete_key) button_layout.addWidget(self._delete_key_button) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) layout.addSpacing(5) migrate_layout = QHBoxLayout() layout.addLayout(migrate_layout) migrate_layout.addStretch() self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.close) migrate_layout.addWidget(self.button_box) self.resize(self.sizeHint())
def __init__(self, parent): QWidget.__init__(self, parent) layout = QHBoxLayout() layout.setSpacing(5) layout.setContentsMargins(0, 0, 0, 0) self.tags_box = EditWithComplete(parent) layout.addWidget(self.tags_box, stretch=1000) self.editor_button = QToolButton(self) self.editor_button.setToolTip(_('Open Item Editor')) self.editor_button.setIcon(QIcon(I('chapters.png'))) layout.addWidget(self.editor_button) self.setLayout(layout)
def __init__(self, parent, values): QWidget.__init__(self, parent) layout = QHBoxLayout() layout.setSpacing(5) layout.setContentsMargins(0, 0, 0, 0) self.tags_box = EditWithComplete(parent) self.tags_box.update_items_cache(values) layout.addWidget(self.tags_box, stretch=3) self.checkbox = QCheckBox(_('Remove all tags'), parent) layout.addWidget(self.checkbox) layout.addStretch(1) self.setLayout(layout) self.checkbox.stateChanged[int].connect(self.box_touched)
def initialize(self): """ Initialize QWidget """ layout = QHBoxLayout() self.setLayout(layout) self.services_title.setObjectName('itemtitle') layout.addWidget(self.services_title) layout.setAlignment(self.services_title, Qt.AlignLeft) icons_widget = QWidget() icons_layout = QHBoxLayout() icons_widget.setLayout(icons_layout) for icon in Service.get_available_icons(): state = icon.replace('services_', '').upper() icon_pixmap = QIcon(settings.get_image(icon)) self.states_btns[state].setIcon(icon_pixmap) self.states_btns[state].setFixedSize(20, 20) self.states_btns[state].setToolTip(state) self.states_btns[state].setCheckable(True) self.states_btns[state].setObjectName('services') icons_layout.addWidget(self.states_btns[state]) self.nb_labels[state].setObjectName(get_icon_name_from_state('service', state)) icons_layout.addWidget(self.nb_labels[state]) layout.addWidget(icons_widget) layout.setAlignment(icons_widget, Qt.AlignRight)
def setup_ui(self, parent): self.make_widgets(parent, EditWithComplete) values = self.all_values = list(self.db.all_custom(num=self.col_id)) values.sort(key=sort_key) self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon) self.main_widget.setMinimumContentsLength(25) self.widgets.append(QLabel('', parent)) w = QWidget(parent) layout = QHBoxLayout(w) layout.setContentsMargins(0, 0, 0, 0) self.remove_series = QCheckBox(parent) self.remove_series.setText(_('Remove series')) layout.addWidget(self.remove_series) self.idx_widget = QCheckBox(parent) self.idx_widget.setText(_('Automatically number books')) layout.addWidget(self.idx_widget) self.force_number = QCheckBox(parent) self.force_number.setText(_('Force numbers to start with ')) layout.addWidget(self.force_number) self.series_start_number = QSpinBox(parent) self.series_start_number.setMinimum(1) self.series_start_number.setMaximum(9999999) self.series_start_number.setProperty("value", 1) layout.addWidget(self.series_start_number) layout.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.widgets.append(w) self.idx_widget.stateChanged.connect(self.check_changed_checkbox) self.force_number.stateChanged.connect(self.check_changed_checkbox) self.series_start_number.valueChanged.connect(self.check_changed_checkbox) self.remove_series.stateChanged.connect(self.check_changed_checkbox) self.ignore_change_signals = False
def create_row2(row, widget, button=None, front_button=None): row += 1 ql = BuddyLabel(widget) if front_button: ltl = QHBoxLayout() ltl.addWidget(front_button) ltl.addWidget(ql) l.addLayout(ltl, row, 0, 1, 1) else: l.addWidget(ql, row, 0, 1, 1) l.addWidget(widget, row, 1, 1, 2 if button is None else 1) if button is not None: l.addWidget(button, row, 2, 1, 1) if button is not None: sto(widget, button)
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()
def initialize(self): """ Initialize QWidget """ layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.toggle_btn.setText(_('ON')) self.toggle_btn.setFixedSize(80, 20) self.toggle_btn.setCheckable(True) self.toggle_btn.setChecked(True) self.toggle_btn.setObjectName('True') self.toggle_btn.clicked.connect(self.update_btn_state) layout.addWidget(self.toggle_btn)
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())
def __init__(self, title = None, zoom = False, parent = None): super(CurveWidget, self).__init__(parent) self.setObjectName('CurveWidget') self.setFixedSize(300, 300) self.setStyleSheet('QWidget#CurveWidget{background-color:rgba(100,100,100,200);}') self._enableDBClick = False self._showNormal = True self._curves = [] # self.initialize(zoom) # TODO horiLayoutMain = QHBoxLayout(self) tableWidget = QTableWidget(self); horiLayoutMain.addWidget(tableWidget)
class TDockWidget(QDockWidget): def __init__(self, title="", parent=None, flags=Qt.WindowFlags(), bind_widget=None, close_slot=None, toggle_slot=None): QDockWidget.__init__(self, title, parent, flags) self.installEventFilter(self) self.main_win = parent # default stlyesheets for title bars self.title_stylesheet = "QWidget {background: rgb(68,68,68);}" self.button_style = "QPushButton:hover:!pressed {background: grey;}" from TigGUI.Images.ControlDialog import ImageControlDialog from TigGUI.Plot.SkyModelPlot import ToolDialog from TigGUI.Plot.SkyModelPlot import LiveImageZoom if bind_widget is not None: self.bind_widget = bind_widget if bind_widget is not None: if isinstance(bind_widget, ToolDialog): self.tdock_style = "ToolDialog {border: 1.5px solid rgb(68,68,68);}" elif isinstance(bind_widget, ImageControlDialog): self.tdock_style = "ImageControlDialog {border: 1.5px solid rgb(68,68,68);}" # set default sizes for QDockWidgets self.btn_w = 28 self.btn_h = 28 self.icon_size = QSize(20, 20) self.font_size = 8 # setup custom title bar for profiles dockable self.dock_title_bar = QWidget() self.dock_title_bar.setContentsMargins(0, 0, 0, 0) self.dock_title_bar.setStyleSheet(self.title_stylesheet) self.dock_title_bar.setBaseSize(0, 0) self.dock_title_layout = QHBoxLayout() self.dock_title_layout.setContentsMargins(0, 0, 0, 0) self.dock_title_layout.setSpacing(0) self.dock_title_bar.setLayout(self.dock_title_layout) # custom close button self.close_button = QPushButton() self.close_button.setStyleSheet(self.button_style) self.close_button.setMaximumWidth(self.btn_w) self.close_button.setMaximumHeight(self.btn_h) self.close_button.setContentsMargins(0, 0, 0, 0) self.close_button.setBaseSize(0, 0) self.close_icon = self.dock_title_bar.style().standardIcon(QStyle.SP_TitleBarCloseButton) self.close_button.setIcon(self.close_icon) self.close_button.setToolTip("Close") # custom toggle button self.toggle_button = QPushButton() self.toggle_button.setStyleSheet(self.button_style) self.toggle_button.setMaximumWidth(self.btn_w) self.toggle_button.setMaximumHeight(self.btn_h) self.toggle_button.setContentsMargins(0, 0, 0, 0) self.toggle_button.setBaseSize(0, 0) self.toggle_icon = self.dock_title_bar.style().standardIcon(QStyle.SP_TitleBarShadeButton) self.toggle_button.setIcon(self.toggle_icon) self.toggle_button.setToolTip("Dock/float widget") # tigger logo self.image0 = pixmaps.tigger_logo.pm() self.title_icon = QLabel() self.title_icon.setContentsMargins(0, 0, 0, 0) self.title_icon.setBaseSize(0, 0) self.title_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.title_icon.setScaledContents(True) self.title_icon.setPixmap(self.image0) self.title_icon.setAlignment(Qt.AlignCenter) self.title_icon.setMaximumSize(self.icon_size) # set dock widget title self.title_font = QFont() self.title_font.setBold(True) self.title_font.setPointSize(self.font_size) if bind_widget is not None: if isinstance(bind_widget, ImageControlDialog): self.dock_title = QLabel(f"{title}: Control Dialog") else: self.dock_title = QLabel(title) self.dock_title.setFont(self.title_font) self.dock_title.setAlignment(Qt.AlignCenter) self.dock_title.setContentsMargins(0, 0, 0, 0) self.dock_title.setBaseSize(0, 0) self.dock_title.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) # add dock widget title items to layout self.dock_title_layout.addWidget(self.title_icon) self.dock_title_layout.addWidget(self.dock_title) self.dock_title_layout.addWidget(self.toggle_button) self.dock_title_layout.addWidget(self.close_button) # set up profiles as dockable self.setStyleSheet(self.tdock_style) self.setWidget(bind_widget) self.setFeatures(QDockWidget.AllDockWidgetFeatures) if bind_widget is not None: if isinstance(bind_widget, ToolDialog): self.setAllowedAreas(Qt.AllDockWidgetAreas) elif isinstance(bind_widget, ImageControlDialog): self.setAllowedAreas(Qt.RightDockWidgetArea | Qt.LeftDockWidgetArea) self.setTitleBarWidget(self.dock_title_bar) self.setFloating(False) # get current sizeHints() if bind_widget is not None: self.setBaseSize(bind_widget.sizeHint()) if isinstance(bind_widget, LiveImageZoom): bind_widget.livezoom_resize_signal.connect(self._resizeDockWidget) if close_slot is not None: self.close_button.clicked.connect(close_slot) if toggle_slot is not None: self.toggle_button.clicked.connect(toggle_slot) def _resizeDockWidget(self, qsize): # live zoom signal slot to resize dockwidget and dock areas self.setMinimumSize(qsize) self.main_win.resizeDocks([self], [qsize.width()], Qt.Horizontal) self.main_win.resizeDocks([self], [qsize.height()], Qt.Vertical) # hack to stop QDockWidget responding to drag events for undocking - work around for Qt bug def eventFilter(self, source, event): # event seq 2, 5, 3 - mouse press, mouse move, mouse release if event.type() == QEvent.MouseButtonPress: label = self.childAt(event.pos()) if not label: return super(TDockWidget, self).eventFilter(source, event) if isinstance(label, QLabel): if not self.isFloating(): fake_mouse_event = QMouseEvent(QEvent.MouseButtonRelease, event.pos(), event.button(), event.buttons(), event.modifiers()) super(TDockWidget, self).event(fake_mouse_event) return True return super(TDockWidget, self).eventFilter(source, event)
def setup_ui(self): self.l = l = QGridLayout(self) self.setLayout(l) self.la1 = la = QLabel(_('&Existing images in the book')) la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) l.addWidget(la, 0, 0, 1, 2) if self.for_browsing: la.setVisible(False) self.view = v = QListView(self) v.setViewMode(v.IconMode) v.setFlow(v.LeftToRight) v.setSpacing(4) v.setResizeMode(v.Adjust) v.setUniformItemSizes(True) pi = plugins['progress_indicator'][0] if hasattr(pi, 'set_no_activate_on_click'): pi.set_no_activate_on_click(v) v.activated.connect(self.activated) v.doubleClicked.connect(self.activated) self.d = ImageDelegate(v) v.setItemDelegate(self.d) self.model = Images(self.view) self.fm = fm = QSortFilterProxyModel(self.view) self.fm.setDynamicSortFilter(self.for_browsing) fm.setSourceModel(self.model) fm.setFilterCaseSensitivity(False) v.setModel(fm) l.addWidget(v, 1, 0, 1, 2) v.pressed.connect(self.pressed) la.setBuddy(v) self.filter = f = QLineEdit(self) f.setPlaceholderText(_('Search for image by file name')) l.addWidget(f, 2, 0) self.cb = b = QToolButton(self) b.setIcon(QIcon(I('clear_left.png'))) b.clicked.connect(f.clear) l.addWidget(b, 2, 1) f.textChanged.connect(self.filter_changed) if self.for_browsing: self.bb.clear() self.bb.addButton(self.bb.Close) b = self.refresh_button = self.bb.addButton( _('&Refresh'), self.bb.ActionRole) b.clicked.connect(self.refresh) b.setIcon(QIcon(I('view-refresh.png'))) b.setToolTip(_('Refresh the displayed images')) self.setAttribute(Qt.WA_DeleteOnClose, False) else: b = self.import_button = self.bb.addButton(_('&Import image'), self.bb.ActionRole) b.clicked.connect(self.import_image) b.setIcon(QIcon(I('view-image.png'))) b.setToolTip(_('Import an image from elsewhere in your computer')) b = self.paste_button = self.bb.addButton(_('&Paste image'), self.bb.ActionRole) b.clicked.connect(self.paste_image) b.setIcon(QIcon(I('edit-paste.png'))) b.setToolTip(_('Paste an image from the clipboard')) self.fullpage = f = QCheckBox(_('Full page image'), self) f.setToolTip( _('Insert the image so that it takes up an entire page when viewed in a reader' )) f.setChecked(tprefs['insert_full_screen_image']) self.preserve_aspect_ratio = a = QCheckBox( _('Preserve aspect ratio')) a.setToolTip( _('Preserve the aspect ratio of the inserted image when rendering it full paged' )) a.setChecked(tprefs['preserve_aspect_ratio_when_inserting_image']) f.toggled.connect( lambda: (tprefs.set('insert_full_screen_image', f.isChecked()), a.setVisible(f.isChecked()))) a.toggled.connect(lambda: tprefs.set( 'preserve_aspect_ratio_when_inserting_image', a.isChecked())) a.setVisible(f.isChecked()) h = QHBoxLayout() l.addLayout(h, 3, 0, 1, -1) h.addWidget(f), h.addStretch(10), h.addWidget(a) l.addWidget(self.bb, 4, 0, 1, 2)
class ComicalibreDialog(QDialog): """ The main dialog for users to enter options before starting. """ def __init__(self, gui, icon, do_user_config): """ Initialize the gui dialog. """ QDialog.__init__(self, gui) self.gui = gui self.icon = icon self.do_user_config = do_user_config self.db = gui.current_db self.create_gui() def start_process(self, process_type): """ Starts the processing worker and progress bar. """ prefs["comic_vine_api_key"] = self.api_msg.text() prefs["tags_to_add"] = self.tags_msg.text() self.worker = ComicalibreWork(self.gui) self.result_text.setText("Processing...") self.title_start.setEnabled(False) self.series_start.setEnabled(False) self.ids_start.setEnabled(False) keep_tags = self.keep_tags_cb.isChecked() errors = self.worker.process(self.progress_bar, process_type, keep_tags) self.title_start.setEnabled(True) self.series_start.setEnabled(True) self.ids_start.setEnabled(True) results = "Finished!" + os.linesep for error in errors: results = results + error + os.linesep self.result_text.setText(results) def title_process(self): self.start_process(0) def series_process(self): self.start_process(1) def ids_process(self): self.start_process(2) def create_gui(self): """ Layout arrangement for the dialog and its input widgets. """ self.layout = QVBoxLayout() self.layout.setSpacing(20) self.setLayout(self.layout) # Create an editable box for user to input Comic Vine API Key. self.api_layout = QHBoxLayout() self.api_msg = QLineEdit(self) self.api_msg.setFixedWidth(350) self.api_msg.setText(prefs["comic_vine_api_key"]) self.api_label = QLabel("Comic Vine API Key") self.api_label.setBuddy(self.api_msg) self.api_layout.addWidget(self.api_label) self.api_layout.addWidget(self.api_msg) # Create an editable box for user to input Tags to add to all books. self.tags_layout = QHBoxLayout() self.tags_msg = QLineEdit(self) self.tags_msg.setText(prefs["tags_to_add"]) self.tags_label = QLabel("Tags To Add") self.tags_label.setBuddy(self.tags_msg) self.tags_layout.addWidget(self.tags_label) self.tags_layout.addWidget(self.tags_msg) # Add the fields to the main layout. self.layout.addLayout(self.api_layout) self.layout.addLayout(self.tags_layout) # Option to keep current tags. self.keep_tags_cb = QCheckBox("Keep existing tags while adding new.", self) self.layout.addWidget(self.keep_tags_cb) # Separate the buttons from the input. self.btn_sep = QFrame() self.btn_sep.setFrameShape(QFrame.HLine) self.btn_sep.setFrameShadow(QFrame.Sunken) self.layout.addWidget(self.btn_sep) # Create a start button to kick off the processing with title. self.title_start = QPushButton("Using Title - Hover For Details", self) self.title_start.setToolTip( "This expects the title of a book to have a " "specific formatted string containing volume " "ID and issue#. e.g." + os.linesep + "Desired " "Title --- v1234 n0124" + os.linesep + "Where " "--- is required and the number after v " "matches Comic Vine's volume ID. The number " "after n is the issue number.") self.title_start.clicked.connect(self.title_process) self.layout.addWidget(self.title_start) # Create a start button to kick off the processing with series. self.series_start = QPushButton("Using Series - Hover For Details", self) self.series_start.setToolTip( "This expects the series name to match the " "Comic Vine volume ID and the series number " "equals issue number.") self.series_start.clicked.connect(self.series_process) self.layout.addWidget(self.series_start) # Create a start button to kick off the processing with CV IDs. self.ids_start = QPushButton("Using IDs - Hover For Details", self) self.ids_start.setToolTip( "This expects two custom columns with lookup " "comicvineissueid and comicvinevolumeid. " "These must match Comic Vine's IDs for the " "issue and the volume.") self.ids_start.clicked.connect(self.ids_process) self.layout.addWidget(self.ids_start) # Separate the progress and results. self.result_sep = QFrame() self.result_sep.setFrameShape(QFrame.HLine) self.result_sep.setFrameShadow(QFrame.Sunken) self.layout.addWidget(self.result_sep) # Create progress bar. self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setMinimumWidth(485) self.layout.addWidget(self.progress_bar) # Create results text area. self.result_box = QGroupBox() self.result_box.setTitle("Results") self.result_text = QLabel("Run Comicalibre to see results.") self.result_scroll = QScrollArea() self.result_scroll.setWidget(self.result_text) self.result_scroll.setWidgetResizable(True) self.result_layout = QVBoxLayout() self.result_layout.addWidget(self.result_scroll) self.result_box.setLayout(self.result_layout) self.layout.addWidget(self.result_box) self.setWindowTitle("Comicalibre") self.setWindowIcon(self.icon) self.resize(self.sizeHint())
def __initUI(self): self.__figure, self.__axe1 = plt.subplots() self.__axe2 = self.__axe1.twinx() self.__figure.subplots_adjust(left=0.1,right=0.9,bottom=0.14,top=0.92) self.__canvas = FigureCanvas(self.__figure) self.__toolbar = NavigationToolbar(self.__canvas, self) self.__btnPlot1.clicked.connect(self.PlotZ1) self.__btnPlot2.clicked.connect(self.PlotZ2) self.__btnClear1.clicked.connect(self.ClearAxe1) self.__btnClear2.clicked.connect(self.ClearAxe2) self.__btnClear.clicked.connect(self.ClearAxes) self.__btnCSV.clicked.connect(self.ExportCSV) self.__btnCSV.setEnabled(False) mess = '''Type in a Python expression like: Y-Y.mean() In this expression you can use use: - the position vector X or Y, - the vecolity vector VX or VX, - the time vector T''' self.__lineZ1Edit.setToolTip(mess) self.__lineZ2Edit.setToolTip(mess) self.__lineZ1Edit.setFixedWidth(200) self.__lineZ2Edit.setFixedWidth(200) vbox = QVBoxLayout() self.setLayout(vbox) # Ligne 1 : tracé de l'image self.setLayout(vbox) hbox = QHBoxLayout() hbox.addWidget(self.__labelZ1Edit) hbox.addWidget(self.__lineZ1Edit) hbox.addWidget(self.__labelZ1label) hbox.addWidget(self.__lineZ1label) hbox.addStretch() hbox.addWidget(self.__btnClear1) hbox.addWidget(self.__btnPlot1) vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.__labelZ2Edit) hbox.addWidget(self.__lineZ2Edit) hbox.addWidget(self.__labelZ2label) hbox.addWidget(self.__lineZ2label) hbox.addStretch() hbox.addWidget(self.__btnClear2) hbox.addWidget(self.__btnPlot2) vbox.addLayout(hbox) vbox.addWidget(self.__canvas) hbox = QHBoxLayout() hbox.addWidget(self.__toolbar) hbox.addStretch() hbox.addWidget(self.__btnClear) hbox.addWidget(self.__btnCSV) vbox.addLayout(hbox)
def setup_ui(self, ): layout = QVBoxLayout(self) self.setLayout(layout) help_layout = QHBoxLayout() layout.addLayout(help_layout) # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. help_label = QLabel('<a href="http://www.foo.com/">Plugin Help</a>', self) help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_label.setAlignment(Qt.AlignRight) help_label.linkActivated.connect(self.help_link_activated) help_layout.addWidget(help_label) self.edu_quotes = QCheckBox(_('Smarten Quotation marks'), self) layout.addWidget(self.edu_quotes) self.edu_quotes.setChecked(self.prefs['edu_quotes']) self.edu_quotes.stateChanged.connect(self.quotes_gui_changes) exceptions_group_box = QGroupBox('', self) layout.addWidget(exceptions_group_box) exceptions_group_box_layout = QVBoxLayout() exceptions_group_box.setLayout(exceptions_group_box_layout) self.use_file = QCheckBox(_('Use custom apostrophe exceptions file'), self) exceptions_group_box_layout.addWidget(self.use_file) if not self.edu_quotes.isChecked(): self.use_file.setDisabled(True) else: self.use_file.setChecked(self.prefs['use_file']) self.use_file.stateChanged.connect(self.use_file_gui_changes) path_layout = QHBoxLayout() exceptions_group_box_layout.addLayout(path_layout) self.file_path = QLineEdit('', self) if not self.edu_quotes.isChecked() and not self.use_file.isChecked(): self.file_path.setReadOnly(True) else: self.file_path.setText(self.prefs['file_path']) self.file_path.setReadOnly(True) path_layout.addWidget(self.file_path) self.file_button = QPushButton('...', self) self.file_button.clicked.connect(self.getFile) path_layout.addWidget(self.file_button) if not self.edu_quotes.isChecked() and not self.use_file.isChecked(): self.file_button.setDisabled(True) combo_layout = QVBoxLayout() layout.addLayout(combo_layout) label = QLabel(_('(em|en)-dash settings'), self) combo_layout.addWidget(label) self.dashes_combo = QComboBox() combo_layout.addWidget(self.dashes_combo) values = [ _('Do not educate dashes'), _('-- = emdash (no endash support)'), _('-- = emdash | --- = endash'), _('--- = emdash | -- = endash') ] self.dashes_combo.addItems(values) self.dashes_combo.setCurrentIndex(self.prefs['dashes']) # self.dashes_combo.currentIndexChanged.connect(self.update_gui) self.ellipses = QCheckBox(_('Smarten ellipses'), self) layout.addWidget(self.ellipses) self.ellipses.setChecked(self.prefs['ellipses']) self.unicode = QCheckBox( _('Educate with unicode characters (instead of entities)'), self) layout.addWidget(self.unicode) self.unicode.setChecked(self.prefs['unicode']) layout.addSpacing(10) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self._ok_clicked) button_box.rejected.connect(self.reject) layout.addWidget(button_box)
def setup_ui(self): # {{{ self.setWindowModality(Qt.ApplicationModal) self.setWindowIcon(QIcon(I('column.png'))) self.vl = l = QVBoxLayout(self) self.heading_label = la = QLabel('') l.addWidget(la) self.shortcuts = s = QLabel('') s.setWordWrap(True) s.linkActivated.connect(self.shortcut_activated) text = '<p>'+_('Quick create:') for col, name in [('isbn', _('ISBN')), ('formats', _('Formats')), ('yesno', _('Yes/No')), ('tags', _('Tags')), ('series', ngettext('Series', 'Series', 1)), ('rating', _('Rating')), ('people', _("Names")), ('text', _('Short text'))]: text += ' <a href="col:%s">%s</a>,'%(col, name) text = text[:-1] s.setText(text) l.addWidget(s) self.g = g = QGridLayout() l.addLayout(g) l.addStretch(10) self.button_box = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) bb.accepted.connect(self.accept), bb.rejected.connect(self.reject) l.addWidget(bb) def add_row(text, widget): if text is None: f = g.addWidget if isinstance(widget, QWidget) else g.addLayout f(widget, g.rowCount(), 0, 1, -1) return row = g.rowCount() la = QLabel(text) g.addWidget(la, row, 0, 1, 1) if isinstance(widget, QWidget): la.setBuddy(widget) g.addWidget(widget, row, 1, 1, 1) else: widget.setContentsMargins(0, 0, 0, 0) g.addLayout(widget, row, 1, 1, 1) for i in range(widget.count()): w = widget.itemAt(i).widget() if isinstance(w, QWidget): la.setBuddy(w) break return la # Lookup name self.column_name_box = cnb = QLineEdit(self) cnb.setToolTip(_("Used for searching the column. Must contain only digits and lower case letters.")) add_row(_("&Lookup name"), cnb) # Heading self.column_heading_box = chb = QLineEdit(self) chb.setToolTip(_("Column heading in the library view and category name in the Tag browser")) add_row(_("Column &heading"), chb) # Column Type h = QHBoxLayout() self.column_type_box = ctb = QComboBox(self) ctb.setMinimumWidth(70) ctb.setToolTip(_("What kind of information will be kept in the column.")) h.addWidget(ctb) self.use_decorations = ud = QCheckBox(_("Show &checkmarks"), self) ud.setToolTip(_("Show check marks in the GUI. Values of 'yes', 'checked', and 'true'\n" "will show a green check. Values of 'no', 'unchecked', and 'false' will show a red X.\n" "Everything else will show nothing.")) h.addWidget(ud) self.is_names = ins = QCheckBox(_("Contains names"), self) ins.setToolTip(_("Check this box if this column contains names, like the authors column.")) h.addWidget(ins) add_row(_("&Column type"), h) # Description self.description_box = d = QLineEdit(self) d.setToolTip(_("Optional text describing what this column is for")) add_row(_("D&escription"), d) # Date/number formatting h = QHBoxLayout() self.format_box = fb = QLineEdit(self) h.addWidget(fb) self.format_default_label = la = QLabel('') la.setOpenExternalLinks(True), la.setWordWrap(True) h.addWidget(la) self.format_label = add_row('', h) # Template self.composite_box = cb = TemplateLineEditor(self) self.composite_default_label = cdl = QLabel(_("Default: (nothing)")) cb.setToolTip(_("Field template. Uses the same syntax as save templates.")) cdl.setToolTip(_("Similar to save templates. For example, %s") % "{title} {isbn}") h = QHBoxLayout() h.addWidget(cb), h.addWidget(cdl) self.composite_label = add_row(_("&Template"), h) # Comments properties self.comments_heading_position = ct = QComboBox(self) for k, text in ( ('hide', _('No heading')), ('above', _('Show heading above the text')), ('side', _('Show heading to the side of the text')) ): ct.addItem(text, k) ct.setToolTip(_('Choose whether or not the column heading is shown in the Book\n' 'details panel and, if shown, where')) self.comments_heading_position_label = add_row(_('Column heading'), ct) self.comments_type = ct = QComboBox(self) for k, text in ( ('html', 'HTML'), ('short-text', _('Short text, like a title')), ('long-text', _('Plain text')), ('markdown', _('Plain text formatted using markdown')) ): ct.addItem(text, k) ct.setToolTip(_('Choose how the data in this column is interpreted.\n' 'This controls how the data is displayed in the Book details panel\n' 'and how it is edited.')) self.comments_type_label = add_row(_('Interpret this column as:') + ' ', ct) # Values for enum type l = QGridLayout() self.enum_box = eb = QLineEdit(self) eb.setToolTip(_( "A comma-separated list of permitted values. The empty value is always\n" "included, and is the default. For example, the list 'one,two,three' has\n" "four values, the first of them being the empty value.")) self.enum_default_label = la = QLabel(_("Values")) la.setBuddy(eb) l.addWidget(eb), l.addWidget(la, 0, 1) self.enum_colors = ec = QLineEdit(self) ec.setToolTip(_("A list of color names to use when displaying an item. The\n" "list must be empty or contain a color for each value.")) self.enum_colors_label = la = QLabel(_('Colors')) la.setBuddy(ec) l.addWidget(ec), l.addWidget(la, 1, 1) self.enum_label = add_row(_('&Values'), l) # Rating allow half stars self.allow_half_stars = ahs = QCheckBox(_('Allow half stars')) ahs.setToolTip(_('Allow half star ratings, for example: ') + '★★★⯨') add_row(None, ahs) # Composite display properties l = QHBoxLayout() self.composite_sort_by_label = la = QLabel(_("&Sort/search column by")) self.composite_sort_by = csb = QComboBox(self) la.setBuddy(csb), csb.setToolTip(_("How this column should handled in the GUI when sorting and searching")) l.addWidget(la), l.addWidget(csb) self.composite_make_category = cmc = QCheckBox(_("Show in Tag browser")) cmc.setToolTip(_("If checked, this column will appear in the Tag browser as a category")) l.addWidget(cmc) self.composite_contains_html = cch = QCheckBox(_("Show as HTML in Book details")) cch.setToolTip('<p>' + _( 'If checked, this column will be displayed as HTML in ' 'Book details and the Content server. This can be used to ' 'construct links with the template language. For example, ' 'the template ' '<pre><big><b>{title}</b></big>' '{series:| [|}{series_index:| [|]]}</pre>' 'will create a field displaying the title in bold large ' 'characters, along with the series, for example <br>"<big><b>' 'An Oblique Approach</b></big> [Belisarius [1]]". The template ' '<pre><a href="https://www.beam-ebooks.de/ebook/{identifiers' ':select(beam)}">Beam book</a></pre> ' 'will generate a link to the book on the Beam e-books site.') + '</p>') l.addWidget(cch) add_row(None, l) # Default value self.default_value = dv = QLineEdit(self) dv.setToolTip('<p>' + _('Default value when a new book is added to the ' 'library. For Date columns enter the word "Now", or the date as ' 'yyyy-mm-dd. For Yes/No columns enter "Yes" or "No". For Text with ' 'a fixed set of values enter one of the permitted values. For ' 'Rating columns enter a number between 0 and 5.') + '</p>') self.default_value_label = add_row(_('Default value'), dv) self.resize(self.sizeHint())
def do_layout(self): self.central_widget.clear() self.labels = [] sto = QWidget.setTabOrder self.central_widget.tabBar().setVisible(False) tab0 = QWidget(self) self.central_widget.addTab(tab0, _("&Metadata")) l = QGridLayout() tab0.setLayout(l) # Basic metadata in col 0 tl = QGridLayout() gb = QGroupBox(_('Basic metadata'), tab0) l.addWidget(gb, 0, 0, 1, 1) gb.setLayout(tl) self.button_box_layout.insertWidget(1, self.fetch_metadata_button) self.button_box_layout.insertWidget(2, self.config_metadata_button) sto(self.button_box, self.fetch_metadata_button) sto(self.fetch_metadata_button, self.config_metadata_button) sto(self.config_metadata_button, self.title) def create_row(row, widget, tab_to, button=None, icon=None, span=1): ql = BuddyLabel(widget) tl.addWidget(ql, row, 1, 1, 1) tl.addWidget(widget, row, 2, 1, 1) if button is not None: tl.addWidget(button, row, 3, span, 1) if icon is not None: button.setIcon(QIcon(I(icon))) if tab_to is not None: if button is not None: sto(widget, button) sto(button, tab_to) else: sto(widget, tab_to) tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 2, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, icon='auto_author_sort.png') create_row(1, self.title_sort, self.authors) create_row(2, self.authors, self.author_sort, button=self.deduce_author_sort_button, span=2, icon='auto_author_sort.png') create_row(3, self.author_sort, self.series) create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate, button=self.clear_ratings_button) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') create_row(9, self.publisher, self.languages) create_row(10, self.languages, self.timestamp) create_row(11, self.timestamp, self.identifiers, button=self.timestamp.clear_button, icon='trash.png') create_row(12, self.identifiers, self.comments, button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) sto(self.manage_authors_button, self.tags_editor_button) sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1, 1) # Custom metadata in col 1 w = getattr(self, 'custom_metadata_widgets_parent', None) if w is not None: gb = QGroupBox(_('Custom metadata'), tab0) gbl = QVBoxLayout() gb.setLayout(gbl) sr = QScrollArea(gb) sr.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) sr.setWidgetResizable(True) sr.setFrameStyle(QFrame.NoFrame) sr.setWidget(w) gbl.addWidget(sr) l.addWidget(gb, 0, 1, 1, 1) sp = QSizePolicy() sp.setVerticalStretch(10) sp.setHorizontalPolicy(QSizePolicy.Minimum) sp.setVerticalPolicy(QSizePolicy.Expanding) gb.setSizePolicy(sp) self.set_custom_metadata_tab_order() # comments span col 0 & 1 w = QGroupBox(_('Comments'), tab0) sp = QSizePolicy() sp.setVerticalStretch(10) sp.setHorizontalPolicy(QSizePolicy.Expanding) sp.setVerticalPolicy(QSizePolicy.Expanding) w.setSizePolicy(sp) lb = QHBoxLayout() w.setLayout(lb) lb.addWidget(self.comments) l.addWidget(w, 1, 0, 1, 2) # Cover & formats in col 3 gb = QGroupBox(_('Cover'), tab0) lb = QGridLayout() gb.setLayout(lb) lb.addWidget(self.cover, 0, 0, 1, 3, alignment=Qt.AlignCenter) sto(self.manage_authors_button, self.cover.buttons[0]) for i, b in enumerate(self.cover.buttons[:3]): lb.addWidget(b, 1, i, 1, 1) sto(b, self.cover.buttons[i + 1]) hl = QHBoxLayout() for b in self.cover.buttons[3:]: hl.addWidget(b) sto(self.cover.buttons[-2], self.cover.buttons[-1]) lb.addLayout(hl, 2, 0, 1, 3) l.addWidget(gb, 0, 2, 1, 1) l.addWidget(self.formats_manager, 1, 2, 1, 1) sto(self.cover.buttons[-1], self.formats_manager) self.formats_manager.formats.setMaximumWidth(10000) self.formats_manager.formats.setIconSize(QSize(32, 32))
def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None): QWidget.__init__(self, parent) self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name self.toolbar1 = QToolBar(self) self.toolbar2 = QToolBar(self) self.toolbar3 = QToolBar(self) for i in range(1, 4): t = getattr(self, 'toolbar%d'%i) t.setIconSize(QSize(18, 18)) self.editor = EditorWidget(self) self.editor.data_changed.connect(self.data_changed) self.set_base_url = self.editor.set_base_url self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(self.tabs.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('&Normal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_'+x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list'%x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(w.InstantPopup) self.toolbar2.addAction(self.editor.action_insert_link) self.toolbar2.addAction(self.editor.action_insert_hr) # }}} # toolbar3 {{{ for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.data_changed.connect(self.wyswyg_dirtied)
class SearchTheInternet(QWidget): changed_signal = pyqtSignal() def __init__(self, parent): QWidget.__init__(self, parent) self.sa = QScrollArea(self) self.lw = QWidget(self) self.l = QVBoxLayout(self.lw) self.sa.setWidget(self.lw), self.sa.setWidgetResizable(True) self.gl = gl = QVBoxLayout(self) self.la = QLabel(_( 'Add new locations to search for books or authors using the "Search the internet" feature' ' of the Content server. The URLs should contain {author} which will be' ' replaced by the author name and, for book URLs, {title} which will' ' be replaced by the book title.')) self.la.setWordWrap(True) gl.addWidget(self.la) self.h = QHBoxLayout() gl.addLayout(self.h) self.add_url_button = b = QPushButton(QIcon(I('plus.png')), _('&Add URL')) b.clicked.connect(self.add_url) self.h.addWidget(b) self.export_button = b = QPushButton(_('Export URLs')) b.clicked.connect(self.export_urls) self.h.addWidget(b) self.import_button = b = QPushButton(_('Import URLs')) b.clicked.connect(self.import_urls) self.h.addWidget(b) self.clear_button = b = QPushButton(_('Clear')) b.clicked.connect(self.clear) self.h.addWidget(b) self.h.addStretch(10) gl.addWidget(self.sa, stretch=10) self.items = [] def genesis(self): self.current_urls = search_the_net_urls() or [] @property def current_urls(self): return [item.as_dict for item in self.items if not item.is_empty] def append_item(self, item_as_dict): self.items.append(URLItem(item_as_dict, self)) self.l.addWidget(self.items[-1]) def clear(self): [(self.l.removeWidget(w), w.setParent(None), w.deleteLater()) for w in self.items] self.items = [] self.changed_signal.emit() @current_urls.setter def current_urls(self, val): self.clear() for entry in val: self.append_item(entry) def add_url(self): self.items.append(URLItem(None, self)) self.l.addWidget(self.items[-1]) QTimer.singleShot(100, self.scroll_to_bottom) def scroll_to_bottom(self): sb = self.sa.verticalScrollBar() if sb: sb.setValue(sb.maximum()) self.items[-1].name_widget.setFocus(Qt.OtherFocusReason) @property def serialized_urls(self): return json.dumps(self.current_urls, indent=2) def commit(self): for item in self.items: if not item.validate(): return False cu = self.current_urls if cu: with lopen(search_the_net_urls.path, 'wb') as f: f.write(self.serialized_urls) else: try: os.remove(search_the_net_urls.path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise return True def export_urls(self): path = choose_save_file( self, 'search-net-urls', _('Choose URLs file'), filters=[(_('URL files'), ['json'])], initial_filename='search-urls.json') if path: with lopen(path, 'wb') as f: f.write(self.serialized_urls) def import_urls(self): paths = choose_files(self, 'search-net-urls', _('Choose URLs file'), filters=[(_('URL files'), ['json'])], all_files=False, select_only_single_file=True) if paths: with lopen(paths[0], 'rb') as f: items = json.loads(f.read()) [self.append_item(x) for x in items] self.changed_signal.emit()
def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext=u""): QDialog.__init__(self, parent) self.parent = parent self.key_type_name = key_type_name self.plugin_keys = plugin_keys self.create_key = create_key self.keyfile_ext = keyfile_ext self.json_file = (keyfile_ext == u"k4i") self.setWindowTitle("{0} {1}: Manage {2}s".format( PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) # Start Qt Gui dialog layout layout = QVBoxLayout(self) self.setLayout(layout) keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) layout.addWidget(keys_group_box) keys_group_box_layout = QHBoxLayout() keys_group_box.setLayout(keys_group_box_layout) self.listy = QListWidget(self) self.listy.setToolTip( u"{0}s that will be used to decrypt ebooks".format( self.key_type_name)) self.listy.setSelectionMode(QAbstractItemView.SingleSelection) self.populate_list() keys_group_box_layout.addWidget(self.listy) button_layout = QVBoxLayout() keys_group_box_layout.addLayout(button_layout) self._add_key_button = QtGui.QToolButton(self) self._add_key_button.setIcon(QIcon(I('plus.png'))) self._add_key_button.setToolTip(u"Create new {0}".format( self.key_type_name)) self._add_key_button.clicked.connect(self.add_key) button_layout.addWidget(self._add_key_button) self._delete_key_button = QtGui.QToolButton(self) self._delete_key_button.setToolTip(_(u"Delete highlighted key")) self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) self._delete_key_button.clicked.connect(self.delete_key) button_layout.addWidget(self._delete_key_button) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) layout.addSpacing(5) migrate_layout = QHBoxLayout() layout.addLayout(migrate_layout) migrate_layout.addStretch() self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.close) migrate_layout.addWidget(self.button_box) self.resize(self.sizeHint())
def setup_ui(self): DELETE_STR = _('Delete') MODIFY_STR = _('Modify') NO_ATTRIB_STR = _('No attributes ("naked" tag)') self.NO_CHANGE_STR = _('No change') layout = QVBoxLayout(self) self.setLayout(layout) help_layout = QHBoxLayout() layout.addLayout(help_layout) # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. help_label = QLabel('<a href="http://www.foo.com/">Plugin Help</a>', self) help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_label.setAlignment(Qt.AlignRight) help_label.linkActivated.connect(self.help_link_activated) help_layout.addWidget(help_label) action_layout = QHBoxLayout() layout.addLayout(action_layout) label = QLabel(_('Action type:'), self) action_layout.addWidget(label) self.action_combo = QComboBox() action_layout.addWidget(self.action_combo) self.action_combo.addItems([DELETE_STR, MODIFY_STR]) self.action_combo.currentIndexChanged.connect(self.update_gui) tag_layout = QHBoxLayout() layout.addLayout(tag_layout) label = QLabel(_('Tag name:'), self) tag_layout.addWidget(label) self.tag_combo = QComboBox() tag_layout.addWidget(self.tag_combo) self.tag_combo.addItems(self.taglist) self.tag_combo.currentIndexChanged.connect(self.update_gui) attr_layout = QHBoxLayout() layout.addLayout(attr_layout) label = QLabel(_('Having the attribute:'), self) attr_layout.addWidget(label) self.attr_combo = QComboBox() attr_layout.addWidget(self.attr_combo) self.attr_combo.addItems(self.prefs['attrs']) self.attr_combo.addItem(NO_ATTRIB_STR) self.attr_combo.currentIndexChanged.connect(self.update_gui) srch_layout = QHBoxLayout() layout.addLayout(srch_layout) label = QLabel(_("Whose value is (no quotes):"), self) srch_layout.addWidget(label) self.srch_txt = QLineEdit('', self) srch_layout.addWidget(self.srch_txt) self.srch_method = QCheckBox(_('Regex'), self) srch_layout.addWidget(self.srch_method) newtag_layout = QHBoxLayout() layout.addLayout(newtag_layout) label = QLabel(_('Change tag to:'), self) newtag_layout.addWidget(label) self.newtag_combo = QComboBox() newtag_layout.addWidget(self.newtag_combo) self.newtag_combo.addItem(self.NO_CHANGE_STR) self.newtag_combo.addItems(self.prefs['{}_changes'.format( unicode(self.tag_combo.currentText()))]) if self.action_combo.currentIndex() == 0: self.newtag_combo.setDisabled(True) newattr_layout = QVBoxLayout() layout.addLayout(newattr_layout) label = QLabel(_('New attribute string to insert (entire):'), self) newattr_layout.addWidget(label) self.newattr_txt = QLineEdit('', self) newattr_layout.addWidget(self.newattr_txt) self.copy_attr = QCheckBox(_('Copy existing attribute string'), self) self.copy_attr.stateChanged.connect(self.update_txt_box) newattr_layout.addWidget(self.copy_attr) if self.action_combo.currentIndex() == 0: self.copy_attr.setDisabled(True) self.newattr_txt.setDisabled(True) layout.addSpacing(10) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self._ok_clicked) button_box.rejected.connect(self.reject) layout.addWidget(button_box)
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)
class HashcrackerTab(QWidget): def __init__(self, console): super().__init__() self.layout = QVBoxLayout(self) self.titleText = QLabel("<H1>Hashcracker</H1>\nHash hier einfügen") self.layout.addWidget(self.titleText) self.hashField = QLineEdit() self.layout.addWidget(self.hashField) self.hashSelectionLabel = QLabel("Wähle Hashfunktion aus") self.layout.addWidget(self.hashSelectionLabel) self.selectHash = QComboBox(self) self.selectHash.addItems(["SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "MD5"]) self.selectHash.setCurrentText("SHA-512") self.layout.addWidget(self.selectHash) self.hboxText = QHBoxLayout() self.bruteforceLabel = QLabel("<H2>Bruteforce</H2>") self.listLabel = QLabel("<H2>Passwort Liste</H2>") self.rtLabel = QLabel("<H2>Ranbowtable Crack</H2>") self.hboxText.addWidget(self.bruteforceLabel) self.hboxText.addWidget(self.listLabel) self.hboxText.addWidget(self.rtLabel) self.layout.addLayout(self.hboxText) self.hboxAction = QHBoxLayout() self.bruteforceCharset = QLineEdit("Charset") self.hboxAction.addWidget(self.bruteforceCharset) self.listSelect = QPushButton("Wähle Datei aus") self.hboxAction.addWidget(self.listSelect) self.rtSelect = QPushButton("Wähle Ranbowtable aus") self.hboxAction.addWidget(self.rtSelect) self.layout.addLayout(self.hboxAction) self.hboxCrackButton = QHBoxLayout() self.bruteforceCrack = QPushButton("Crack Bruteforce") self.hboxCrackButton.addWidget(self.bruteforceCrack) self.listCrack = QPushButton("Crack List") self.hboxCrackButton.addWidget(self.listCrack) self.rainbowCrack = QPushButton("Crack Rainbowtable") self.hboxCrackButton.addWidget(self.rainbowCrack) self.layout.addLayout(self.hboxCrackButton) self.layout.addStretch(1)
def __init__(self, parent=None): BasicSettings.__init__(self, parent) self.dictionaries_changed = self.snippets_changed = False self.l = l = QFormLayout(self) self.setLayout(l) fc = FontFamilyChooser(self) self('editor_font_family', widget=fc, getter=attrgetter('font_family'), setter=lambda x, val: setattr(x, 'font_family', val)) fc.family_changed.connect(self.emit_changed) l.addRow(_('Editor font family:'), fc) fs = self('editor_font_size') fs.setMinimum(8), fs.setSuffix(' pt'), fs.setMaximum(50) l.addRow(_('Editor font &size:'), fs) choices = self.theme_choices() theme = self.choices_widget('editor_theme', choices, 'auto', 'auto') self.custom_theme_button = b = QPushButton( _('Create/edit &custom color schemes')) b.clicked.connect(self.custom_theme) h = QHBoxLayout() h.addWidget(theme), h.addWidget(b) l.addRow(_('&Color scheme:'), h) l.labelForField(h).setBuddy(theme) tw = self('editor_tab_stop_width') tw.setMinimum(2), tw.setSuffix(_(' characters')), tw.setMaximum(20) l.addRow(_('W&idth of tabs:'), tw) self.tb = b = QPushButton(_('Change &templates')) l.addRow(_('Templates for new files:'), b) connect_lambda(b.clicked, self, lambda self: TemplatesDialog(self).exec_()) lw = self('editor_line_wrap') lw.setText(_('&Wrap long lines in the editor')) l.addRow(lw) lw = self('replace_entities_as_typed') lw.setText(_('&Replace HTML entities as they are typed')) lw.setToolTip('<p>' + _( 'With this option, every time you type in a complete html entity, such as &hellip;' ' it is automatically replaced by its corresponding character. The replacement' ' happens only when the trailing semi-colon is typed.')) l.addRow(lw) lw = self('auto_close_tags') lw.setText(_('Auto close t&ags when typing </')) lw.setToolTip('<p>' + prepare_string_for_xml( _('With this option, every time you type </ the current HTML closing tag is auto-completed' ))) l.addRow(lw) lw = self('editor_show_char_under_cursor') lw.setText( _('Show the &name of the current character before the cursor along with the line and column number' )) l.addRow(lw) lw = self('pretty_print_on_open') lw.setText( _('Beautify individual &files automatically when they are opened')) lw.setToolTip('<p>' + _( 'This will cause the beautify current file action to be performed automatically every' ' time you open a HTML/CSS/etc. file for editing.')) l.addRow(lw) lw = self('inline_spell_check') lw.setText(_('Show &misspelled words underlined in the code view')) lw.setToolTip('<p>' + _( 'This will cause spelling errors to be highlighted in the code view' ' for easy correction as you type.')) l.addRow(lw) lw = self('editor_accepts_drops') lw.setText(_('Allow drag and drop &editing of text')) lw.setToolTip('<p>' + _( 'Allow using drag and drop to move text around in the editor.' ' It can be useful to turn this off if you have a misbehaving touchpad.' )) l.addRow(lw) self.dictionaries = d = QPushButton(_('Manage &spelling dictionaries'), self) d.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) d.clicked.connect(self.manage_dictionaries) l.addRow(d) self.snippets = s = QPushButton(_('Manage sni&ppets'), self) s.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) s.clicked.connect(self.manage_snippets) l.addRow(s)
def do_layout(self): self.central_widget.clear() self.tabs = [] self.labels = [] sto = QWidget.setTabOrder self.on_drag_enter.connect(self.handle_drag_enter) self.tabs.append(DragTrackingWidget(self, self.on_drag_enter)) self.central_widget.addTab(self.tabs[0], _("&Metadata")) self.tabs[0].l = QGridLayout() self.tabs[0].setLayout(self.tabs[0].l) self.tabs.append(QWidget(self)) self.central_widget.addTab(self.tabs[1], _("&Cover and formats")) self.tabs[1].l = QGridLayout() self.tabs[1].setLayout(self.tabs[1].l) # accept drop events so we can automatically switch to the second tab to # drop covers and formats self.tabs[0].setAcceptDrops(True) # Tab 0 tab0 = self.tabs[0] tl = QGridLayout() gb = QGroupBox(_('&Basic metadata'), self.tabs[0]) self.tabs[0].l.addWidget(gb, 0, 0, 1, 1) gb.setLayout(tl) self.button_box_layout.insertWidget(1, self.fetch_metadata_button) self.button_box_layout.insertWidget(2, self.config_metadata_button) sto(self.button_box, self.fetch_metadata_button) sto(self.fetch_metadata_button, self.config_metadata_button) sto(self.config_metadata_button, self.title) def create_row(row, widget, tab_to, button=None, icon=None, span=1): ql = BuddyLabel(widget) tl.addWidget(ql, row, 1, 1, 1) tl.addWidget(widget, row, 2, 1, 1) if button is not None: tl.addWidget(button, row, 3, span, 1) if icon is not None: button.setIcon(QIcon(I(icon))) if tab_to is not None: if button is not None: sto(widget, button) sto(button, tab_to) else: sto(widget, tab_to) tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 1, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, icon='auto_author_sort.png') create_row(1, self.title_sort, self.authors) create_row(2, self.authors, self.author_sort, button=self.deduce_author_sort_button, span=2, icon='auto_author_sort.png') create_row(3, self.author_sort, self.series) create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate, button=self.clear_ratings_button) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') create_row(9, self.publisher, self.languages) create_row(10, self.languages, self.timestamp) create_row(11, self.timestamp, self.identifiers, button=self.timestamp.clear_button, icon='trash.png') create_row(12, self.identifiers, self.comments, button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) sto(self.manage_authors_button, self.tags_editor_button) sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1, 1) w = getattr(self, 'custom_metadata_widgets_parent', None) if w is not None: gb = QGroupBox(_('C&ustom metadata'), tab0) gbl = QVBoxLayout() gb.setLayout(gbl) sr = QScrollArea(tab0) sr.setWidgetResizable(True) sr.setFrameStyle(QFrame.NoFrame) sr.setWidget(w) gbl.addWidget(sr) self.tabs[0].l.addWidget(gb, 0, 1, 1, 1) sto(self.identifiers, gb) w = QGroupBox(_('&Comments'), tab0) sp = QSizePolicy() sp.setVerticalStretch(10) sp.setHorizontalPolicy(QSizePolicy.Expanding) sp.setVerticalPolicy(QSizePolicy.Expanding) w.setSizePolicy(sp) l = QHBoxLayout() w.setLayout(l) l.addWidget(self.comments) tab0.l.addWidget(w, 1, 0, 1, 2) # Tab 1 tab1 = self.tabs[1] wsp = QWidget(tab1) wgl = QVBoxLayout() wsp.setLayout(wgl) # right-hand side of splitter gb = QGroupBox(_('Change cover'), tab1) l = QGridLayout() gb.setLayout(l) for i, b in enumerate(self.cover.buttons[:3]): l.addWidget(b, 0, i, 1, 1) sto(b, self.cover.buttons[i + 1]) hl = QHBoxLayout() for b in self.cover.buttons[3:]: hl.addWidget(b) sto(self.cover.buttons[-2], self.cover.buttons[-1]) l.addLayout(hl, 1, 0, 1, 3) wgl.addWidget(gb) wgl.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addWidget(self.formats_manager) self.splitter = QSplitter(Qt.Horizontal, tab1) tab1.l.addWidget(self.splitter) self.splitter.addWidget(self.cover) self.splitter.addWidget(wsp) self.formats_manager.formats.setMaximumWidth(10000) self.formats_manager.formats.setIconSize(QSize(64, 64))
def _initialize_controls(self): self.setWindowTitle(_('User plugins')) self.setWindowIcon(QIcon(I('plugins/plugin_updater.png'))) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'plugins/plugin_updater.png', _('User Plugins')) layout.addLayout(title_layout) header_layout = QHBoxLayout() layout.addLayout(header_layout) self.filter_combo = PluginFilterComboBox(self) self.filter_combo.setMinimumContentsLength(20) self.filter_combo.currentIndexChanged[int].connect(self._filter_combo_changed) header_layout.addWidget(QLabel(_('Filter list of plugins')+':', self)) header_layout.addWidget(self.filter_combo) header_layout.addStretch(10) # filter plugins by name header_layout.addWidget(QLabel(_('Filter by name')+':', self)) self.filter_by_name_lineedit = QLineEdit(self) self.filter_by_name_lineedit.setText("") self.filter_by_name_lineedit.textChanged.connect(self._filter_name_lineedit_changed) header_layout.addWidget(self.filter_by_name_lineedit) self.plugin_view = QTableView(self) self.plugin_view.horizontalHeader().setStretchLastSection(True) self.plugin_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.plugin_view.setSelectionMode(QAbstractItemView.SingleSelection) self.plugin_view.setAlternatingRowColors(True) self.plugin_view.setSortingEnabled(True) self.plugin_view.setIconSize(QSize(28, 28)) layout.addWidget(self.plugin_view) details_layout = QHBoxLayout() layout.addLayout(details_layout) forum_label = self.forum_label = QLabel('') forum_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) forum_label.linkActivated.connect(self._forum_label_activated) details_layout.addWidget(QLabel(_('Description')+':', self), 0, Qt.AlignLeft) details_layout.addWidget(forum_label, 1, Qt.AlignRight) self.description = QLabel(self) self.description.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.description.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.description.setMinimumHeight(40) self.description.setWordWrap(True) layout.addWidget(self.description) self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.reject) self.finished.connect(self._finished) self.install_button = self.button_box.addButton(_('&Install'), QDialogButtonBox.AcceptRole) self.install_button.setToolTip(_('Install the selected plugin')) self.install_button.clicked.connect(self._install_clicked) self.install_button.setEnabled(False) self.configure_button = self.button_box.addButton(' '+_('&Customize plugin ')+' ', QDialogButtonBox.ResetRole) self.configure_button.setToolTip(_('Customize the options for this plugin')) self.configure_button.clicked.connect(self._configure_clicked) self.configure_button.setEnabled(False) layout.addWidget(self.button_box)
class AnnotationsAppearance(SizePersistedDialog): ''' Dialog for managing CSS rules, including Preview window ''' if isosx: FONT = QFont('Monaco', 12) elif iswindows: FONT = QFont('Lucida Console', 9) elif islinux: FONT = QFont('Monospace', 9) FONT.setStyleHint(QFont.TypeWriter) def __init__(self, parent, icon, prefs): self.parent = parent self.prefs = prefs self.icon = icon super(AnnotationsAppearance, self).__init__(parent, 'appearance_dialog') self.setWindowTitle(_('Modify appearance')) self.setWindowIcon(icon) self.l = QVBoxLayout(self) self.setLayout(self.l) # Add a label for description #self.description_label = QLabel(_("Descriptive text here")) #self.l.addWidget(self.description_label) # Add a group box, vertical layout for preview window self.preview_gb = QGroupBox(self) self.preview_gb.setTitle(_("Preview")) self.preview_vl = QVBoxLayout(self.preview_gb) self.l.addWidget(self.preview_gb) self.wv = QWebView() self.wv.setHtml('<p></p>') self.wv.setMinimumHeight(100) self.wv.setMaximumHeight(16777215) self.wv.setGeometry(0, 0, 200, 100) self.wv.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.preview_vl.addWidget(self.wv) # Create a group box, horizontal layout for the table self.css_table_gb = QGroupBox(self) self.css_table_gb.setTitle(_("Annotation elements")) self.elements_hl = QHBoxLayout(self.css_table_gb) self.l.addWidget(self.css_table_gb) # Add the group box to the main layout self.elements_table = AnnotationElementsTable( self, 'annotation_elements_tw') self.elements_hl.addWidget(self.elements_table) self.elements_table.initialize() # Options self.options_gb = QGroupBox(self) self.options_gb.setTitle(_("Options")) self.options_gl = QGridLayout(self.options_gb) self.l.addWidget(self.options_gb) current_row = 0 # <hr/> separator # addWidget(widget, row, col, rowspan, colspan) self.hr_checkbox = QCheckBox( _('Add horizontal rule between annotations')) self.hr_checkbox.stateChanged.connect(self.hr_checkbox_changed) self.hr_checkbox.setCheckState( JSONConfig('plugins/annotations').get('appearance_hr_checkbox', False)) self.options_gl.addWidget(self.hr_checkbox, current_row, 0, 1, 4) current_row += 1 # Timestamp self.timestamp_fmt_label = QLabel(_("Timestamp format:")) self.options_gl.addWidget(self.timestamp_fmt_label, current_row, 0) self.timestamp_fmt_le = QLineEdit( JSONConfig('plugins/annotations').get( 'appearance_timestamp_format', default_timestamp), parent=self) self.timestamp_fmt_le.textEdited.connect(self.timestamp_fmt_changed) self.timestamp_fmt_le.setFont(self.FONT) self.timestamp_fmt_le.setObjectName('timestamp_fmt_le') self.timestamp_fmt_le.setToolTip(_('Format string for timestamp')) self.timestamp_fmt_le.setMaximumWidth(16777215) self.timestamp_fmt_le.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.options_gl.addWidget(self.timestamp_fmt_le, current_row, 1) self.timestamp_fmt_reset_tb = QToolButton(self) self.timestamp_fmt_reset_tb.setToolTip(_("Reset to default")) self.timestamp_fmt_reset_tb.setIcon(QIcon(I('trash.png'))) self.timestamp_fmt_reset_tb.clicked.connect( self.reset_timestamp_to_default) self.options_gl.addWidget(self.timestamp_fmt_reset_tb, current_row, 2) self.timestamp_fmt_help_tb = QToolButton(self) self.timestamp_fmt_help_tb.setToolTip(_("Format string reference")) self.timestamp_fmt_help_tb.setIcon(QIcon(I('help.png'))) self.timestamp_fmt_help_tb.clicked.connect(self.show_help) self.options_gl.addWidget(self.timestamp_fmt_help_tb, current_row, 3) # Button box bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.l.addWidget(bb) # Spacer self.spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.l.addItem(self.spacerItem) # Sizing sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.resize_dialog() def hr_checkbox_changed(self, state): self.prefs.set('appearance_hr_checkbox', state) self.elements_table.preview_css() def reset_timestamp_to_default(self): from calibre_plugins.annotations.appearance import default_timestamp self.timestamp_fmt_le.setText(default_timestamp) self.timestamp_fmt_changed() def show_help(self): ''' Display strftime help file ''' help_html = get_resources('help/timestamp_formats.html') print("1 - %s" % help_html) help_html = help_html.decode('utf-8') print("2 - %s" % help_html) hv = HelpView(self, self.icon, self.prefs, html=help_html, title=_("Timestamp formats")) hv.show() def sizeHint(self): return QtCore.QSize(600, 200) def timestamp_fmt_changed(self): self.prefs.set('appearance_timestamp_format', str(self.timestamp_fmt_le.text())) self.elements_table.preview_css()
def __init__(self, parent): QWidget.__init__(self, parent) self.parent = parent self._layout = QVBoxLayout() self.setLayout(self._layout) self._layout.setContentsMargins(0, 0, 0, 0) # Set up the find box & button search_layout = QHBoxLayout() self._layout.addLayout(search_layout) self.item_search = HistoryLineEdit(parent) self.item_search.setMinimumContentsLength(5) self.item_search.setSizeAdjustPolicy( self.item_search.AdjustToMinimumContentsLengthWithIcon) try: self.item_search.lineEdit().setPlaceholderText( _('Find item in tag browser')) except: pass # Using Qt < 4.7 self.item_search.setToolTip( _('Search for items. This is a "contains" search; items containing the\n' 'text anywhere in the name will be found. You can limit the search\n' 'to particular categories using syntax similar to search. For example,\n' 'tags:foo will find foo in any tag, but not in authors etc. Entering\n' '*foo will filter all categories at once, showing only those items\n' 'containing the text "foo"')) search_layout.addWidget(self.item_search) # Not sure if the shortcut should be translatable ... sc = QShortcut(QKeySequence(_('ALT+f')), parent) sc.activated.connect(self.set_focus_to_find_box) self.search_button = QToolButton() self.search_button.setText(_('F&ind')) self.search_button.setToolTip(_('Find the first/next matching item')) search_layout.addWidget(self.search_button) self.expand_button = QToolButton() self.expand_button.setText('-') self.expand_button.setToolTip(_('Collapse all categories')) search_layout.addWidget(self.expand_button) search_layout.setStretch(0, 10) search_layout.setStretch(1, 1) search_layout.setStretch(2, 1) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.initialize('tag_browser_search') self.item_search.lineEdit().returnPressed.connect(self.do_find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive) parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self.expand_button.clicked.connect(self.tags_view.collapseAll) self._layout.addWidget(parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.StyledPanel) l.setAutoFillBackground(True) l.setText( '<p><b>' + _('No More Matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10, 20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect( self.not_found_label_timer_event, type=Qt.QueuedConnection) parent.alter_tb = l = QPushButton(parent) l.setText(_('Alter Tag Browser')) l.setIcon(QIcon(I('tags.png'))) l.m = QMenu() l.setMenu(l.m) self._layout.addWidget(l) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate((_('Sort by name'), _('Sort by number of books'), _('Sort by average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip(_('Set the sort order for entries in the Tag Browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate( (_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag Browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip( _('All of these category_managers are available by right-clicking ' 'on items in the tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m)
class ConfigWidget(QWidget): def __init__(self): QWidget.__init__(self) self.l = QVBoxLayout() self.l.setContentsMargins(0, 0, 0, 0) self.setLayout(self.l) self.help_msg = QLabel(''' <h2 style="text-align: center">Get Started</h2> <p> To start syncing your library you will need to create an account to retrieve<br> your API key. </p> ''') self.l.addWidget(self.help_msg) self.form = QFormLayout() self.form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) self.l.addLayout(self.form) self.link = QLabel('<a href="{0}">{0}</a>'.format(prefs['api_base'] + '/api-key')) self.link.setOpenExternalLinks(True) self.form.addRow('Visit:', self.link) self.api_key = QLineEdit(self) self.api_key.setText(prefs['api_key']) self.form.addRow('API Key:', self.api_key) self.debug = QCheckBox(self) self.debug.setChecked(prefs['debug']) self.form.addRow('Debug Logging:', self.debug) self.update_metadata_layout = QHBoxLayout() self.update_metadata_layout.setContentsMargins(0, 0, 0, 0) self.update_metadata = QCheckBox(self) self.update_metadata.setChecked(prefs['update_metadata']) self.update_metadata_layout.addWidget(self.update_metadata) self.update_metadata_hint = QLabel('(sync all metadata changes made)') self.update_metadata_layout.addWidget(self.update_metadata_hint) self.form.addRow('Update Metadata:', self.update_metadata_layout) self.threads = QComboBox(self) for n in range(3): self.threads.addItem(str(pow(2, n))) self.threads.setCurrentText(str(prefs['threads'])) self.form.addRow('Sync Threads:', self.threads) self.bookshelves_custom_column = QComboBox(self) self.bookshelves_custom_column.addItem('') for key, meta in get_current_db().new_api.field_metadata.custom_iteritems(): if meta['datatype'] == 'text': self.bookshelves_custom_column.addItem(key) self.bookshelves_custom_column.setCurrentText(prefs['bookshelves_custom_column']) self.form.addRow('Bookshelves Column:', self.bookshelves_custom_column) def save_settings(self): prefs['api_key'] = unicode(self.api_key.text()) prefs['debug'] = self.debug.isChecked() prefs['update_metadata'] = self.update_metadata.isChecked() prefs['threads'] = int(self.threads.currentText()) prefs['bookshelves_custom_column'] = unicode(self.bookshelves_custom_column.currentText())
def __init__(self, parent_dialog, plugin_action): self.parent_dialog = parent_dialog self.plugin_action = plugin_action QWidget.__init__(self) self.l = QVBoxLayout() self.setLayout(self.l) label = QLabel(_('These settings control the basic features of the plugin.')) label.setWordWrap(True) self.l.addWidget(label) self.l.addSpacing(5) self.titlenavpoints = QCheckBox(_('Insert Table of Contents entry for each title?'),self) self.titlenavpoints.setToolTip(_('''If set, a new TOC entry will be made for each title and it's existing TOC nested underneath it.''')) self.titlenavpoints.setChecked(prefs['titlenavpoints']) self.l.addWidget(self.titlenavpoints) self.flattentoc = QCheckBox(_('Flatten Table of Contents?'),self) self.flattentoc.setToolTip(_('Remove nesting and make TOC all on one level.')) self.flattentoc.setChecked(prefs['flattentoc']) self.l.addWidget(self.flattentoc) self.includecomments = QCheckBox(_("Include Books' Comments?"),self) self.includecomments.setToolTip(_('''Include all the merged books' comments in the new book's comments. Default is a list of included titles only.''')) self.includecomments.setChecked(prefs['includecomments']) self.l.addWidget(self.includecomments) self.keepmeta = QCheckBox(_('Keep UnMerge Metadata?'),self) self.keepmeta.setToolTip(_('''If set, a copy of the original metadata for each merged book will be included, allowing for UnMerge. This includes your calibre custom columns. Leave off if you plan to distribute the epub to others.''')) self.keepmeta.setChecked(prefs['keepmeta']) self.l.addWidget(self.keepmeta) # self.showunmerge = QCheckBox(_('Show UnMerge Option?'),self) # self.showunmerge.setToolTip(_('''If set, the UnMerge Epub option will be shown on the EpubMerge menu. # Only Epubs merged with 'Keep UnMerge Metadata' can be UnMerged.''')) # self.showunmerge.setChecked(prefs['showunmerge']) # self.l.addWidget(self.showunmerge) horz = QHBoxLayout() horz.addWidget(QLabel(_("Add tags to merged books:"))) self.mergetags = QLineEdit(self) self.mergetags.setText(prefs['mergetags']) self.mergetags.setToolTip(_('Tags you enter here will be added to all new merged books')) horz.addWidget(self.mergetags) self.l.addLayout(horz) horz = QHBoxLayout() horz.addWidget(QLabel(_("Merged Book Word:"))) self.mergeword = QLineEdit(self) self.mergeword.setText(prefs['mergeword']) self.mergeword.setToolTip(_('''Word use to describe merged books in default title and summary. For people who don't like the word Anthology.''')) ## Defaults back to Anthology if cleared. horz.addWidget(self.mergeword) self.l.addLayout(horz) self.l.addSpacing(15) label = QLabel(_("These controls aren't plugin settings as such, but convenience buttons for setting Keyboard shortcuts and getting all the EpubMerge confirmation dialogs back again.")) label.setWordWrap(True) self.l.addWidget(label) self.l.addSpacing(5) keyboard_shortcuts_button = QPushButton(_('Keyboard shortcuts...'), self) keyboard_shortcuts_button.setToolTip(_('Edit the keyboard shortcuts associated with this plugin')) keyboard_shortcuts_button.clicked.connect(parent_dialog.edit_shortcuts) self.l.addWidget(keyboard_shortcuts_button) reset_confirmation_button = QPushButton(_('Reset disabled &confirmation dialogs'), self) reset_confirmation_button.setToolTip(_('Reset all show me again dialogs for the EpubMerge plugin')) reset_confirmation_button.clicked.connect(self.reset_dialogs) self.l.addWidget(reset_confirmation_button) view_prefs_button = QPushButton(_('View library preferences...'), self) view_prefs_button.setToolTip(_('View data stored in the library database for this plugin')) view_prefs_button.clicked.connect(self.view_prefs) self.l.addWidget(view_prefs_button) self.l.insertStretch(-1)
def __init__(self, gui, header, prefs, icon, books, save_size_name='epubmerge:update list dialog'): SizePersistedDialog.__init__(self, gui, save_size_name) self.gui = gui self.setWindowTitle(header) self.setWindowIcon(icon) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'images/icon.png', header) layout.addLayout(title_layout) books_layout = QHBoxLayout() layout.addLayout(books_layout) self.books_table = StoryListTableWidget(self) books_layout.addWidget(self.books_table) button_layout = QVBoxLayout() books_layout.addLayout(button_layout) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) self.move_up_button = QtGui.QToolButton(self) self.move_up_button.setToolTip(_('Move selected books up the list')) self.move_up_button.setIcon(QIcon(I('arrow-up.png'))) self.move_up_button.clicked.connect(self.books_table.move_rows_up) button_layout.addWidget(self.move_up_button) self.remove_button = QtGui.QToolButton(self) self.remove_button.setToolTip(_('Remove selected books from the list')) self.remove_button.setIcon(get_icon('list_remove.png')) self.remove_button.clicked.connect(self.remove_from_list) button_layout.addWidget(self.remove_button) self.move_down_button = QtGui.QToolButton(self) self.move_down_button.setToolTip( _('Move selected books down the list')) self.move_down_button.setIcon(QIcon(I('arrow-down.png'))) self.move_down_button.clicked.connect(self.books_table.move_rows_down) button_layout.addWidget(self.move_down_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem1) options_layout = QHBoxLayout() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) options_layout.addWidget(button_box) layout.addLayout(options_layout) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() self.books_table.populate_table(books)
class Diff(Dialog): revert_requested = pyqtSignal() line_activated = pyqtSignal(object, object, object) def __init__(self, revert_button_msg=None, parent=None, show_open_in_editor=False, show_as_window=False): self.context = 3 self.beautify = False self.apply_diff_calls = [] self.show_open_in_editor = show_open_in_editor self.revert_button_msg = revert_button_msg Dialog.__init__(self, _('Differences between books'), 'diff-dialog', parent=parent) if show_as_window: self.setWindowFlags(Qt.Window) self.view.line_activated.connect(self.line_activated) def sizeHint(self): geom = QApplication.instance().desktop().availableGeometry(self) return QSize(int(0.9 * geom.width()), int(0.8 * geom.height())) def setup_ui(self): self.setWindowIcon(QIcon(I('diff.png'))) self.stacks = st = QStackedLayout(self) self.busy = BusyWidget(self) self.w = QWidget(self) st.addWidget(self.busy), st.addWidget(self.w) self.setLayout(st) self.l = l = QGridLayout() self.w.setLayout(l) self.view = v = DiffView(self, show_open_in_editor=self.show_open_in_editor) l.addWidget(v, l.rowCount(), 0, 1, -1) r = l.rowCount() self.bp = b = QToolButton(self) b.setIcon(QIcon(I('back.png'))) b.clicked.connect(partial(self.view.next_change, -1)) b.setToolTip(_('Go to previous change') + ' [p]') b.setText(_('&Previous change')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 0) self.bn = b = QToolButton(self) b.setIcon(QIcon(I('forward.png'))) b.clicked.connect(partial(self.view.next_change, 1)) b.setToolTip(_('Go to next change') + ' [n]') b.setText(_('&Next change')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 1) self.search = s = HistoryLineEdit2(self) s.initialize('diff_search_history') l.addWidget(s, r, 2) s.setPlaceholderText(_('Search for text')) s.returnPressed.connect(partial(self.do_search, False)) self.sbn = b = QToolButton(self) b.setIcon(QIcon(I('arrow-down.png'))) b.clicked.connect(partial(self.do_search, False)) b.setToolTip(_('Find next match')) b.setText(_('Next &match')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 3) self.sbp = b = QToolButton(self) b.setIcon(QIcon(I('arrow-up.png'))) b.clicked.connect(partial(self.do_search, True)) b.setToolTip(_('Find previous match')) b.setText(_('P&revious match')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 4) self.lb = b = QRadioButton(_('Left panel'), self) b.setToolTip(_('Perform search in the left panel')) l.addWidget(b, r, 5) self.rb = b = QRadioButton(_('Right panel'), self) b.setToolTip(_('Perform search in the right panel')) l.addWidget(b, r, 6) b.setChecked(True) self.pb = b = QToolButton(self) b.setIcon(QIcon(I('config.png'))) b.setText(_('&Options')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) b.setToolTip(_('Change how the differences are displayed')) b.setPopupMode(b.InstantPopup) m = QMenu(b) b.setMenu(m) cm = self.cm = QMenu(_('Lines of context around each change')) for i in (3, 5, 10, 50): cm.addAction( _('Show %d lines of context') % i, partial(self.change_context, i)) cm.addAction(_('Show all text'), partial(self.change_context, None)) self.beautify_action = m.addAction('', self.toggle_beautify) self.set_beautify_action_text() m.addMenu(cm) l.addWidget(b, r, 7) self.hl = QHBoxLayout() l.addLayout(self.hl, l.rowCount(), 0, 1, -1) self.names = QLabel('') self.hl.addWidget(self.names, r) self.bb.setStandardButtons(self.bb.Close) if self.revert_button_msg is not None: self.rvb = b = self.bb.addButton(self.revert_button_msg, self.bb.ActionRole) b.setIcon(QIcon(I('edit-undo.png'))), b.setAutoDefault(False) b.clicked.connect(self.revert_requested) b.clicked.connect(self.reject) self.bb.button(self.bb.Close).setDefault(True) self.hl.addWidget(self.bb, r) self.view.setFocus(Qt.OtherFocusReason) def break_cycles(self): self.view = None for x in ('revert_requested', 'line_activated'): try: getattr(self, x).disconnect() except: pass def do_search(self, reverse): text = unicode(self.search.text()) if not text.strip(): return v = self.view.view.left if self.lb.isChecked( ) else self.view.view.right v.search(text, reverse=reverse) def change_context(self, context): if context == self.context: return self.context = context self.refresh() def refresh(self): with self: self.view.clear() for args, kwargs in self.apply_diff_calls: kwargs['context'] = self.context kwargs['beautify'] = self.beautify self.view.add_diff(*args, **kwargs) self.view.finalize() def toggle_beautify(self): self.beautify = not self.beautify self.set_beautify_action_text() self.refresh() def set_beautify_action_text(self): self.beautify_action.setText( _('Beautify files before comparing them') if not self.beautify else _('Do not beautify files before comparing')) def __enter__(self): self.stacks.setCurrentIndex(0) self.busy.pi.startAnimation() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers) def __exit__(self, *args): self.busy.pi.stopAnimation() self.stacks.setCurrentIndex(1) QApplication.restoreOverrideCursor() def set_names(self, names): if isinstance(names, tuple): self.names.setText('%s <--> %s' % names) else: self.names.setText('') def ebook_diff(self, path1, path2, names=None): self.set_names(names) with self: identical = self.apply_diff(_('The books are identical'), *ebook_diff(path1, path2)) self.view.finalize() if identical: self.reject() def container_diff(self, left, right, identical_msg=None, names=None): self.set_names(names) with self: identical = self.apply_diff(identical_msg or _('No changes found'), *container_diff(left, right)) self.view.finalize() if identical: self.reject() def file_diff(self, left, right, identical_msg=None): with self: identical = self.apply_diff( identical_msg or _('The files are identical'), *file_diff(left, right)) self.view.finalize() if identical: self.reject() def dir_diff(self, left, right, identical_msg=None): with self: identical = self.apply_diff( identical_msg or _('The directories are identical'), *dir_diff(left, right)) self.view.finalize() if identical: self.reject() def apply_diff(self, identical_msg, cache, syntax_map, changed_names, renamed_names, removed_names, added_names): self.view.clear() self.apply_diff_calls = calls = [] def add(args, kwargs): self.view.add_diff(*args, **kwargs) calls.append((args, kwargs)) if len(changed_names) + len(renamed_names) + len(removed_names) + len( added_names) < 1: info_dialog(self, _('No changes found'), identical_msg, show=True) return True kwargs = lambda name: { 'context': self.context, 'beautify': self.beautify, 'syntax': syntax_map.get(name, None) } if isinstance(changed_names, dict): for name, other_name in sorted( changed_names.iteritems(), key=lambda x: numeric_sort_key(x[0])): args = (name, other_name, cache.left(name), cache.right(other_name)) add(args, kwargs(name)) else: for name in sorted(changed_names, key=numeric_sort_key): args = (name, name, cache.left(name), cache.right(name)) add(args, kwargs(name)) for name in sorted(added_names, key=numeric_sort_key): args = (_('[%s was added]') % name, name, None, cache.right(name)) add(args, kwargs(name)) for name in sorted(removed_names, key=numeric_sort_key): args = (name, _('[%s was removed]') % name, cache.left(name), None) add(args, kwargs(name)) for name, new_name in sorted(renamed_names.iteritems(), key=lambda x: numeric_sort_key(x[0])): args = (name, new_name, None, None) add(args, kwargs(name)) def keyPressEvent(self, ev): if not self.view.handle_key(ev): if ev.key() in (Qt.Key_Enter, Qt.Key_Return): return # The enter key is used by the search box, so prevent it closing the dialog if ev.key() == Qt.Key_Slash: return self.search.setFocus(Qt.OtherFocusReason) if ev.matches(QKeySequence.Copy): text = self.view.view.left.selected_text + self.view.view.right.selected_text if text: QApplication.clipboard().setText(text) return if ev.matches(QKeySequence.FindNext): self.sbn.click() return if ev.matches(QKeySequence.FindPrevious): self.sbp.click() return return Dialog.keyPressEvent(self, ev)
def __init__(self, parent): QWidget.__init__(self, parent) self.l = l = QGridLayout(self) l.setContentsMargins(0, 0, 0, 0) self.setLayout(l) self.bookmarks_list = bl = BookmarksList(self) bl.itemChanged.connect(self.item_changed) l.addWidget(bl, 0, 0, 1, -1) bl.itemClicked.connect(self.item_activated) bl.bookmark_activated.connect(self.item_activated) bl.changed.connect(lambda: self.edited.emit(self.get_bookmarks())) bl.ac_edit.triggered.connect(self.edit_bookmark) bl.ac_delete.triggered.connect(self.delete_bookmark) self.la = la = QLabel(_('Double click to edit the bookmarks')) la.setWordWrap(True) l.addWidget(la, l.rowCount(), 0, 1, -1) self.button_new = b = QPushButton(QIcon(I('bookmarks.png')), _('&New'), self) b.clicked.connect(self.create_requested) b.setToolTip(_('Create a new bookmark at the current location')) l.addWidget(b) self.button_delete = b = QPushButton(QIcon(I('trash.png')), _('&Remove'), self) b.setToolTip(_('Remove the currently selected bookmark')) b.clicked.connect(self.delete_bookmark) l.addWidget(b, l.rowCount() - 1, 1) self.button_prev = b = QPushButton(QIcon(I('back.png')), _('P&revious'), self) b.clicked.connect(self.bookmarks_list.previous_bookmark) l.addWidget(b) self.button_next = b = QPushButton(QIcon(I('forward.png')), _('Nex&t'), self) b.clicked.connect(self.bookmarks_list.next_bookmark) l.addWidget(b, l.rowCount() - 1, 1) la = QLabel(_('&Sort by:')) self.sort_by = sb = QComboBox(self) la.setBuddy(sb) sb.addItem(_('Title'), 'title') sb.addItem(_('Position in book'), 'pos') sb.addItem(_('Date'), 'timestamp') sb.setToolTip(_('Change how the bookmarks are sorted')) i = sb.findData(vprefs['bookmarks_sort']) if i > -1: sb.setCurrentIndex(i) h = QHBoxLayout() h.addWidget(la), h.addWidget(sb, 10) l.addLayout(h, l.rowCount(), 0, 1, 2) sb.currentIndexChanged.connect(self.sort_by_changed) self.button_export = b = QPushButton(_('E&xport'), self) b.clicked.connect(self.export_bookmarks) l.addWidget(b, l.rowCount(), 0) self.button_import = b = QPushButton(_('&Import'), self) b.clicked.connect(self.import_bookmarks) l.addWidget(b, l.rowCount() - 1, 1)
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 styles 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 styles 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 style 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 style</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 style 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 style</qt>')) self.css_remove.clicked.connect(self.remove_css) self.llll.addWidget(self.css_remove) self.llll_ = QHBoxLayout() self.css_layout.addLayout(self.llll_) self.label_args = QLabel(_('Addi&tional command-line arguments:')) self.llll_.addWidget(self.label_args) self.args = QLineEdit(self) # Make sure custom_CSS_list and custom_args_list have the same keys if 'custom_args_list' in prefs: self.args_list = prefs['custom_args_list'].copy() else: self.args_list = {} for key in self.CSS_list: if not key in self.args_list: self.args_list[key] = '' for key in self.args_list: if not key in self.CSS_list: del self.args_list[key] self.args.setText(self.args_list[unicode(self.css_list.currentText())]) self.args.setToolTip( _('<qt>Additional command-line arguments used in conversions with this style</qt>' )) self.llll_.addWidget(self.args) self.label_args.setBuddy(self.args) self.css = TextEditWithTooltip(self, expected_geometry=(80, 20)) 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 styles:')) 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 styles')) 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.args_list = prefs.defaults['custom_args_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.args.setText(self.args_list[unicode(self.css_list.currentText())]) 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() prefs['custom_args_list'] = self.args_list.copy() if 'custom_CSS' in prefs: del prefs['custom_CSS'] def set_css(self): ''' Fill the CSS text box with the selected stylesheet, and similarly for command-line arguments ''' self.CSS_list[self.default_CSS] = unicode(self.css.toPlainText()) self.args_list[self.default_CSS] = unicode(self.args.text()) self.default_CSS = unicode(self.css_list.currentText()) self.css.load_text(self.CSS_list[self.default_CSS], 'css') self.args.setText(self.args_list[self.default_CSS]) self.css_name.setText(self.css_list.currentText()) def add_css(self): ''' Add a new style ''' from calibre.gui2 import error_dialog name = unicode(self.css_name.text()) if name in self.CSS_list: error_dialog( self, _('Cannot add style'), _('A style with the name "%s" is already defined, use a different name.' ) % name, show=True) else: self.CSS_list[name] = '' self.args_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 style ''' 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] del self.args_list[self.default_CSS] self.default_CSS = unicode(self.css_list.currentText()) self.css.load_text(self.CSS_list[self.default_CSS], 'css') self.args.setText(self.args_list[self.default_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 style'), _('The last style cannot be removed. You can rename it and/or remove its contents.' ), show=True) def rename_css(self): ''' Rename a style ''' from calibre.gui2 import error_dialog name = unicode(self.css_name.text()) if name in self.CSS_list: error_dialog( self, _('Cannot rename style'), _('A style 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.args_list[name] = self.args_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)
def __init__(self, parent, books, list_name): SizePersistedDialog.__init__(self, parent, 'reading list plugin:edit list dialog') self.setWindowTitle('Edit List') layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'images/reading_list.png', '\'%s\' list books' % list_name) layout.addLayout(title_layout) books_layout = QHBoxLayout() layout.addLayout(books_layout) self.books_table = EditListTableWidget(self) books_layout.addWidget(self.books_table) button_layout = QVBoxLayout() books_layout.addLayout(button_layout) # move to top button self.move_top_button = QtGui.QToolButton(self) self.move_top_button.setToolTip( 'Move selected books to the top of the list') self.move_top_button.setIcon( get_icon('images/arrow_up_double_bar.png')) self.move_top_button.clicked.connect(self.books_table.move_to_top) button_layout.addWidget(self.move_top_button) # move up 10 rows button self.move_10_up_button = QtGui.QToolButton(self) self.move_10_up_button.setToolTip( 'Move selected books 10 rows up the list') self.move_10_up_button.setIcon(get_icon('images/arrow_up_double.png')) self.move_10_up_button.clicked.connect( self.books_table.move_10_rows_up) button_layout.addWidget(self.move_10_up_button) # move up one row button self.move_up_button = QtGui.QToolButton(self) self.move_up_button.setToolTip('Move selected books up the list') self.move_up_button.setIcon(get_icon('images/arrow_up_single.png')) self.move_up_button.clicked.connect(self.books_table.move_rows_up) button_layout.addWidget(self.move_up_button) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) # remove from list button self.remove_button = QtGui.QToolButton(self) self.remove_button.setToolTip('Remove selected books from the list') self.remove_button.setIcon(get_icon('list_remove.png')) self.remove_button.clicked.connect(self.remove_from_list) button_layout.addWidget(self.remove_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) # move down one row button button_layout.addItem(spacerItem1) self.move_down_button = QtGui.QToolButton(self) self.move_down_button.setToolTip('Move selected books down the list') self.move_down_button.setIcon(get_icon('images/arrow_down_single.png')) self.move_down_button.clicked.connect(self.books_table.move_rows_down) button_layout.addWidget(self.move_down_button) # move down 10 rows button self.move_10_down_button = QtGui.QToolButton(self) self.move_10_down_button.setToolTip( 'Move selected books 10 rows down the list') #self.move_10_down_button.setIcon(QIcon(I('arrow-down.png'))) self.move_10_down_button.setIcon( get_icon('images/arrow_down_double.png')) self.move_10_down_button.clicked.connect( self.books_table.move_10_rows_down) button_layout.addWidget(self.move_10_down_button) # move to bottom button self.move_bottom_button = QtGui.QToolButton(self) self.move_bottom_button.setToolTip( 'Move selected books to the bottom of the list') #self.move_bottom_button.setIcon(QIcon(I('arrow-down.png'))) self.move_bottom_button.setIcon( get_icon('images/arrow_down_double_bar.png')) self.move_bottom_button.clicked.connect( self.books_table.move_to_bottom) button_layout.addWidget(self.move_bottom_button) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) layout.addWidget(button_box) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() self.books_table.populate_table(books)
class Config(QDialog): ''' Configuration dialog for single book conversion. If accepted, has the following important attributes output_format - Output format (without a leading .) input_format - Input format (without a leading .) opf_path - Path to OPF file with user specified metadata cover_path - Path to user specified cover (can be None) recommendations - A pickled list of 3 tuples in the same format as the recommendations member of the Input/Output plugins. ''' def __init__(self, parent, db, book_id, preferred_input_format=None, preferred_output_format=None): QDialog.__init__(self, parent) self.widgets = [] self.setupUi() self.opt_individual_saved_settings.setVisible(False) self.db, self.book_id = db, book_id self.setup_input_output_formats(self.db, self.book_id, preferred_input_format, preferred_output_format) self.setup_pipeline() self.input_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.output_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.groups.setSpacing(5) self.groups.activated[(QModelIndex)].connect(self.show_pane) self.groups.clicked[(QModelIndex)].connect(self.show_pane) self.groups.entered[(QModelIndex)].connect(self.show_group_help) rb = self.buttonBox.button(self.buttonBox.RestoreDefaults) rb.setText(_('Restore &defaults')) rb.clicked.connect(self.restore_defaults) self.groups.setMouseTracking(True) geom = gprefs.get('convert_single_dialog_geom', None) if geom: QApplication.instance().safe_restore_geometry(self, geom) else: self.resize(self.sizeHint()) def setupUi(self): self.setObjectName("Dialog") self.resize(1024, 700) self.setWindowIcon(QIcon(I('convert.png'))) self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.input_label = QLabel(self) self.input_label.setObjectName("input_label") self.horizontalLayout.addWidget(self.input_label) self.input_formats = QComboBox(self) self.input_formats.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.input_formats.setMinimumContentsLength(5) self.input_formats.setObjectName("input_formats") self.horizontalLayout.addWidget(self.input_formats) self.opt_individual_saved_settings = QCheckBox(self) self.opt_individual_saved_settings.setObjectName( "opt_individual_saved_settings") self.horizontalLayout.addWidget(self.opt_individual_saved_settings) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.label_2 = QLabel(self) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) self.output_formats = QComboBox(self) self.output_formats.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.output_formats.setMinimumContentsLength(5) self.output_formats.setObjectName("output_formats") self.horizontalLayout.addWidget(self.output_formats) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2) self.groups = QListView(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.groups.sizePolicy().hasHeightForWidth()) self.groups.setSizePolicy(sizePolicy) self.groups.setTabKeyNavigation(True) self.groups.setIconSize(QSize(48, 48)) self.groups.setWordWrap(True) self.groups.setObjectName("groups") self.gridLayout.addWidget(self.groups, 1, 0, 3, 1) self.scrollArea = QScrollArea(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(4) sizePolicy.setVerticalStretch(10) sizePolicy.setHeightForWidth( self.scrollArea.sizePolicy().hasHeightForWidth()) self.scrollArea.setSizePolicy(sizePolicy) self.scrollArea.setFrameShape(QFrame.NoFrame) self.scrollArea.setLineWidth(0) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.page = QWidget() self.page.setObjectName("page") self.gridLayout.addWidget(self.scrollArea, 1, 1, 1, 1) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.RestoreDefaults) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) self.help = QTextEdit(self) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.help.sizePolicy().hasHeightForWidth()) self.help.setSizePolicy(sizePolicy) self.help.setMaximumHeight(80) self.help.setObjectName("help") self.gridLayout.addWidget(self.help, 2, 1, 1, 1) self.input_label.setBuddy(self.input_formats) self.label_2.setBuddy(self.output_formats) self.input_label.setText(_("&Input format:")) self.opt_individual_saved_settings.setText( _("Use &saved conversion settings for individual books")) self.label_2.setText(_("&Output format:")) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def sizeHint(self): desktop = QCoreApplication.instance().desktop() geom = desktop.availableGeometry(self) nh, nw = max(300, geom.height() - 100), max(400, geom.width() - 70) return QSize(nw, nh) def restore_defaults(self): delete_specifics(self.db, self.book_id) self.setup_pipeline() @property def input_format(self): return unicode_type(self.input_formats.currentText()).lower() @property def output_format(self): return unicode_type(self.output_formats.currentText()).lower() @property def manually_fine_tune_toc(self): for w in self.widgets: if hasattr(w, 'manually_fine_tune_toc'): return w.manually_fine_tune_toc.isChecked() def setup_pipeline(self, *args): oidx = self.groups.currentIndex().row() input_format = self.input_format output_format = self.output_format self.plumber = create_dummy_plumber(input_format, output_format) def widget_factory(cls): return cls(self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) self.mw = widget_factory(MetadataWidget) self.setWindowTitle( _('Convert') + ' ' + unicode_type(self.mw.title.text())) lf = widget_factory(LookAndFeelWidget) hw = widget_factory(HeuristicsWidget) sr = widget_factory(SearchAndReplaceWidget) ps = widget_factory(PageSetupWidget) sd = widget_factory(StructureDetectionWidget) toc = widget_factory(TOCWidget) from calibre.gui2.actions.toc_edit import SUPPORTED toc.manually_fine_tune_toc.setVisible( output_format.upper() in SUPPORTED) debug = widget_factory(DebugWidget) output_widget = self.plumber.output_plugin.gui_configuration_widget( self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) input_widget = self.plumber.input_plugin.gui_configuration_widget( self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) self.break_cycles() self.widgets = widgets = [self.mw, lf, hw, ps, sd, toc, sr] if input_widget is not None: widgets.append(input_widget) if output_widget is not None: widgets.append(output_widget) widgets.append(debug) for w in widgets: w.set_help_signal.connect(self.help.setPlainText) w.setVisible(False) self._groups_model = GroupModel(widgets) self.groups.setModel(self._groups_model) idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0 self.groups.setCurrentIndex(self._groups_model.index(idx)) self.show_pane(idx) try: shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True) except Exception: pass def setup_input_output_formats(self, db, book_id, preferred_input_format, preferred_output_format): if preferred_output_format: preferred_output_format = preferred_output_format.upper() output_formats = get_output_formats(preferred_output_format) input_format, input_formats = get_input_format_for_book( db, book_id, preferred_input_format) preferred_output_format = preferred_output_format if \ preferred_output_format in output_formats else \ sort_formats_by_preference(output_formats, [prefs['output_format']])[0] self.input_formats.addItems( (unicode_type(x.upper()) for x in input_formats)) self.output_formats.addItems( (unicode_type(x.upper()) for x in output_formats)) self.input_formats.setCurrentIndex(input_formats.index(input_format)) self.output_formats.setCurrentIndex( output_formats.index(preferred_output_format)) def show_pane(self, index): if hasattr(index, 'row'): index = index.row() ow = self.scrollArea.takeWidget() if ow: ow.setParent(self) for i, w in enumerate(self.widgets): if i == index: self.scrollArea.setWidget(w) w.show() else: w.setVisible(False) def accept(self): recs = GuiRecommendations() for w in self._groups_model.widgets: if not w.pre_commit_check(): return x = w.commit(save_defaults=False) recs.update(x) self.opf_file, self.cover_file = self.mw.opf_file, self.mw.cover_file self._recommendations = recs if self.db is not None: recs['gui_preferred_input_format'] = self.input_format save_specifics(self.db, self.book_id, recs) self.break_cycles() QDialog.accept(self) def reject(self): self.break_cycles() QDialog.reject(self) def done(self, r): if self.isVisible(): gprefs['convert_single_dialog_geom'] = \ bytearray(self.saveGeometry()) return QDialog.done(self, r) def break_cycles(self): for w in self.widgets: w.break_cycles() @property def recommendations(self): recs = [(k, v, OptionRecommendation.HIGH) for k, v in self._recommendations.items()] return recs def show_group_help(self, index): widget = self._groups_model.widgets[index.row()] self.help.setPlainText(widget.HELP)
def __init__(self, plugin): DefaultConfigWidget.__init__(self, plugin) c = plugin_prefs[STORE_NAME] all_tags = get_current_db().all_tags() self.gb.setMaximumHeight(80) genre_group_box = QGroupBox(_('Naverbook genre to calibre tag mappings'), self) self.l.addWidget(genre_group_box, self.l.rowCount(), 0, 1, 2) genre_group_box_layout = QVBoxLayout() genre_group_box.setLayout(genre_group_box_layout) tags_layout = QHBoxLayout() genre_group_box_layout.addLayout(tags_layout) self.edit_table = GenreTagMappingsTableWidget(self, all_tags) tags_layout.addWidget(self.edit_table) button_layout = QVBoxLayout() tags_layout.addLayout(button_layout) add_mapping_button = QtGui.QToolButton(self) add_mapping_button.setToolTip(_('Add genre mapping')) add_mapping_button.setIcon(QIcon(I('plus.png'))) add_mapping_button.clicked.connect(self.add_mapping) button_layout.addWidget(add_mapping_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem1) remove_mapping_button = QtGui.QToolButton(self) remove_mapping_button.setToolTip(_('Delete genre mapping')) remove_mapping_button.setIcon(QIcon(I('minus.png'))) remove_mapping_button.clicked.connect(self.delete_mapping) button_layout.addWidget(remove_mapping_button) spacerItem3 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem3) rename_genre_button = QtGui.QToolButton(self) rename_genre_button.setToolTip(_('Rename Goodreads genre')) rename_genre_button.setIcon(QIcon(I('edit-undo.png'))) rename_genre_button.clicked.connect(self.rename_genre) button_layout.addWidget(rename_genre_button) spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem2) reset_defaults_button = QtGui.QToolButton(self) reset_defaults_button.setToolTip(_('Reset to plugin default mappings')) reset_defaults_button.setIcon(QIcon(I('clear_left.png'))) reset_defaults_button.clicked.connect(self.reset_to_defaults) button_layout.addWidget(reset_defaults_button) self.l.setRowStretch(self.l.rowCount()-1, 2) other_group_box = QGroupBox(_('Other options'), self) self.l.addWidget(other_group_box, self.l.rowCount(), 0, 1, 2) other_group_box_layout = QVBoxLayout() other_group_box.setLayout(other_group_box_layout) self.get_editions_checkbox = QCheckBox('Scan multiple editions for title/author searches (slower)', self) self.get_editions_checkbox.setToolTip('When checked will perform an additional search to scan the top ranked\n' 'Goodreads editions (if available) to exclude audiobook editions.\n' 'Without this enabled you will get a faster search, using the "best".\n' 'edition ranked by Goodreads which can in some cases be an audiobook.') self.get_editions_checkbox.setChecked(c[KEY_GET_EDITIONS]) other_group_box_layout.addWidget(self.get_editions_checkbox) self.all_authors_checkbox = QCheckBox('Get all contributing authors (e.g. illustrators, series editors etc)', self) self.all_authors_checkbox.setToolTip('Goodreads for some books will list all of the contributing authors and\n' 'the type of contribution like (Editor), (Illustrator) etc.\n\n' 'When this option is checked, all contributing authors are retrieved.\n\n' 'When unchecked (default) only the primary author(s) are returned which\n' 'are those that either have no contribution type specified, or have the\n' 'value of (Goodreads Author).\n\n' 'If there is no primary author then only those with the same contribution\n' 'type as the first author are returned.\n' 'e.g. "A, B (Illustrator)" will return author A\n' 'e.g. "A (Goodreads Author)" will return author A\n' 'e.g. "A (Editor), B (Editor), C (Illustrator)" will return authors A & B\n' 'e.g. "A (Editor), B (Series Editor)" will return author A\n') self.all_authors_checkbox.setChecked(c[KEY_GET_ALL_AUTHORS]) other_group_box_layout.addWidget(self.all_authors_checkbox) self.edit_table.populate_table(c[KEY_GENRE_MAPPINGS])
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 __init__(self, parent=None, panel_name='search'): QWidget.__init__(self, parent) self.ignore_search_type_changes = False self.l = l = QVBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) l.addLayout(h) self.search_box = sb = SearchBox(self) self.panel_name = panel_name sb.initialize('viewer-{}-panel-expression'.format(panel_name)) sb.item_selected.connect(self.saved_search_selected) sb.history_saved.connect(self.history_saved) sb.cleared.connect(self.cleared) sb.lineEdit().returnPressed.connect(self.find_next) h.addWidget(sb) self.next_button = nb = QToolButton(self) h.addWidget(nb) nb.setFocusPolicy(Qt.NoFocus) nb.setIcon(QIcon(I('arrow-down.png'))) nb.clicked.connect(self.find_next) nb.setToolTip(_('Find next match')) self.prev_button = nb = QToolButton(self) h.addWidget(nb) nb.setFocusPolicy(Qt.NoFocus) nb.setIcon(QIcon(I('arrow-up.png'))) nb.clicked.connect(self.find_previous) nb.setToolTip(_('Find previous match')) h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) l.addLayout(h) self.query_type = qt = QComboBox(self) qt.setFocusPolicy(Qt.NoFocus) qt.addItem(_('Contains'), 'normal') qt.addItem(_('Whole words'), 'word') qt.addItem(_('Regex'), 'regex') qt.setToolTip(('<p>' + _( 'Choose the type of search: <ul>' '<li><b>Contains</b> will search for the entered text anywhere.' '<li><b>Whole words</b> will search for whole words that equal the entered text.' '<li><b>Regex</b> will interpret the text as a regular expression.' ))) qt.setCurrentIndex( qt.findData( vprefs.get('viewer-{}-mode'.format(self.panel_name), 'normal') or 'normal')) qt.currentIndexChanged.connect(self.save_search_type) h.addWidget(qt) self.case_sensitive = cs = QCheckBox(_('&Case sensitive'), self) cs.setFocusPolicy(Qt.NoFocus) cs.setChecked( bool( vprefs.get('viewer-{}-case-sensitive'.format(self.panel_name), False))) cs.stateChanged.connect(self.save_search_type) h.addWidget(cs) self.return_button = rb = QToolButton(self) rb.setIcon(QIcon(I('back.png'))) rb.setToolTip(_('Go back to where you were before searching')) rb.clicked.connect(self.go_back) h.addWidget(rb)
def __init__(self): super().__init__() self.setWindowTitle(WINDOW_TITLE) from pathlib import Path file_name = str(Path(__file__).resolve().parent / 'favicon.ico') icon = QIcon(file_name) self.setWindowIcon(icon) self.tray = QSystemTrayIcon(icon) self.tray.setToolTip(self.windowTitle()) self.tray.activated.connect(self._on_tray_activated) self.tray.show() self.logged_dict = dict() self.pb_refresh = QPushButton('REFRESH') self.pb_refresh.clicked.connect(self.refresh) self.cb_show_log = QCheckBox() self.cb_show_log.setChecked(True) self.log = QPlainTextEdit() self.log.setReadOnly(True) self.log.setWordWrapMode(QTextOption.NoWrap) log_font = self.log.font() log_font.setFamily('Courier New') self.log.setFont(log_font) self.cb_show_log.clicked.connect(self.log.setVisible) self.log.setVisible(self.cb_show_log.isChecked()) header_labels = ['DATE', 'TOTAL LOGGED TIME'] self.table_logged = QTableWidget() self.table_logged.setEditTriggers(QTableWidget.NoEditTriggers) self.table_logged.setSelectionBehavior(QTableWidget.SelectRows) self.table_logged.setSelectionMode(QTableWidget.SingleSelection) self.table_logged.setColumnCount(len(header_labels)) self.table_logged.setHorizontalHeaderLabels(header_labels) self.table_logged.horizontalHeader().setStretchLastSection(True) self.table_logged.itemClicked.connect( self._on_table_logged_item_clicked) header_labels = ['TIME', 'LOGGED', 'JIRA'] self.table_logged_info = QTableWidget() self.table_logged_info.setEditTriggers(QTableWidget.NoEditTriggers) self.table_logged_info.setSelectionBehavior(QTableWidget.SelectRows) self.table_logged_info.setSelectionMode(QTableWidget.SingleSelection) self.table_logged_info.setColumnCount(len(header_labels)) self.table_logged_info.setHorizontalHeaderLabels(header_labels) self.table_logged_info.horizontalHeader().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.table_logged_info.horizontalHeader().setStretchLastSection(True) self.table_logged_info.itemDoubleClicked.connect( self._on_table_logged_info_item_double_clicked) main_layout = QVBoxLayout() central_widget = QWidget() central_widget.setLayout(main_layout) self.setCentralWidget(central_widget) self.pb_refresh.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)) h_layout = QHBoxLayout() h_layout.addWidget(self.pb_refresh) h_layout.addWidget(self.cb_show_log) layout_table_widget = QVBoxLayout() layout_table_widget.setContentsMargins(0, 0, 0, 0) layout_table_widget.addWidget(self.table_logged) layout_table_widget.addWidget(self.table_logged_info) table_widget = QWidget() table_widget.setLayout(layout_table_widget) splitter = QSplitter(Qt.Horizontal) splitter.addWidget(table_widget) splitter.addWidget(self.log) main_layout.addLayout(h_layout) main_layout.addWidget(splitter)