class Comments(Base): def setup_ui(self, parent): self._box = QGroupBox(parent) self._box.setTitle('&'+self.col_metadata['name']) self._layout = QVBoxLayout() self._tb = CommentsEditor(self._box, toolbar_prefs_name=u'metadata-comments-editor-widget-hidden-toolbars') self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) # self._tb.setTabChangesFocus(True) self._layout.addWidget(self._tb) self._box.setLayout(self._layout) self.widgets = [self._box] def setter(self, val): if not val or not val.strip(): val = '' else: val = comments_to_html(val) self._tb.html = val self._tb.wyswyg_dirtied() def getter(self): val = unicode(self._tb.html).strip() if not val: val = None return val @dynamic_property def tab(self): def fget(self): return self._tb.tab def fset(self, val): self._tb.tab = val return property(fget=fget, fset=fset)
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__(self, parent): orientation = Qt.Vertical if config['gui_layout'] == 'narrow': orientation = Qt.Horizontal if is_widescreen() else Qt.Vertical idx = 0 if orientation == Qt.Vertical else 1 size = 300 if orientation == Qt.Vertical else 550 Splitter.__init__(self, 'cover_browser_splitter', _('Cover browser'), I('cover_flow.png'), orientation=orientation, parent=parent, connect_button=not config['separate_cover_flow'], side_index=idx, initial_side_size=size, initial_show=False, shortcut='Shift+Alt+B') quickview_widget = QWidget() parent.quickview_splitter = QuickviewSplitter( parent=self, orientation=Qt.Vertical, qv_widget=quickview_widget) parent.library_view = BooksView(parent) parent.library_view.setObjectName('library_view') stack = QStackedWidget(self) av = parent.library_view.alternate_views av.set_stack(stack) parent.grid_view = GridView(parent) parent.grid_view.setObjectName('grid_view') av.add_view('grid', parent.grid_view) parent.quickview_splitter.addWidget(stack) l = QVBoxLayout() l.setContentsMargins(4, 0, 0, 0) quickview_widget.setLayout(l) parent.quickview_splitter.addWidget(quickview_widget) parent.quickview_splitter.hide_quickview_widget() self.addWidget(parent.quickview_splitter)
def __init__(self, parent=None): self.loaded_ruleset = None QWidget.__init__(self, parent) self.PREFS_OBJECT = JSONConfig('style-transform-rules') l = QVBoxLayout(self) self.rules_widget = w = Rules(self) w.changed.connect(self.changed.emit) l.addWidget(w) self.h = h = QHBoxLayout() l.addLayout(h) self.export_button = b = QPushButton(_('E&xport'), self) b.setToolTip(_('Export these rules to a file')) b.clicked.connect(self.export_rules) h.addWidget(b) self.import_button = b = QPushButton(_('&Import'), self) b.setToolTip(_('Import previously exported rules')) b.clicked.connect(self.import_rules) h.addWidget(b) self.test_button = b = QPushButton(_('&Test rules'), self) b.clicked.connect(self.test_rules) h.addWidget(b) h.addStretch(10) self.save_button = b = QPushButton(_('&Save'), self) b.setToolTip(_('Save this ruleset for later re-use')) b.clicked.connect(self.save_ruleset) h.addWidget(b) self.export_button = b = QPushButton(_('&Load'), self) self.load_menu = QMenu(self) b.setMenu(self.load_menu) b.setToolTip(_('Load a previously saved ruleset')) b.clicked.connect(self.load_ruleset) h.addWidget(b) self.build_load_menu()
def initialize(self): """ Initialize History QWidget """ main_layout = QVBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) # Title Window main_layout.addWidget(get_logo_widget(self, _('History'))) # History QWidget history_widget = QWidget() history_layout = QVBoxLayout(history_widget) # History QTableWidget self.history_table.setObjectName('history') self.history_table.verticalHeader().hide() self.history_table.verticalHeader().setDefaultSectionSize(100) self.history_table.setColumnCount(len(self.table_headers)) self.history_table.setColumnWidth(0, 600) self.history_table.setSortingEnabled(True) self.history_table.setHorizontalScrollMode(QAbstractItemView.ScrollPerItem) self.history_table.setHorizontalHeaderLabels(self.table_headers) self.history_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.history_table.horizontalHeader().setStretchLastSection(True) self.history_table.horizontalHeader().setMinimumHeight(30) history_layout.addWidget(self.history_table) main_layout.addWidget(history_widget) center_widget(self)
def get_text_widget(self): """ Return text QWidget with QTextEdit :return: text QWidget :rtype: QWidget """ text_widget = QWidget() text_widget.setObjectName('dialog') text_layout = QVBoxLayout() text_widget.setLayout(text_layout) self.text_edit.setPlaceholderText(_('type your text...')) self.text_edit.setText(self.old_text) text_layout.addWidget(self.text_edit) # Accept button accept_btn = QPushButton(_('Confirm'), self) accept_btn.clicked.connect(self.accept_text) accept_btn.setObjectName('valid') accept_btn.setMinimumHeight(30) text_layout.addWidget(accept_btn) return text_widget
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) 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 show_config_widget(category, name, gui=None, show_restart_msg=False, parent=None, never_shutdown=False): ''' Show the preferences plugin identified by category and name :param gui: gui instance, if None a hidden gui is created :param show_restart_msg: If True and the preferences plugin indicates a restart is required, show a message box telling the user to restart :param parent: The parent of the displayed dialog :return: True iff a restart is required for the changes made by the user to take effect ''' from calibre.gui2 import gprefs pl = get_plugin(category, name) d = ConfigDialog(parent) d.resize(750, 550) conf_name = 'config_widget_dialog_geometry_%s_%s'%(category, name) geom = gprefs.get(conf_name, None) d.setWindowTitle(_('Configure ') + name) d.setWindowIcon(QIcon(I('config.png'))) bb = QDialogButtonBox(d) bb.setStandardButtons(bb.Apply|bb.Cancel|bb.RestoreDefaults) bb.accepted.connect(d.accept) bb.rejected.connect(d.reject) w = pl.create_widget(d) d.set_widget(w) bb.button(bb.RestoreDefaults).clicked.connect(w.restore_defaults) bb.button(bb.RestoreDefaults).setEnabled(w.supports_restoring_to_defaults) bb.button(bb.Apply).setEnabled(False) bb.button(bb.Apply).clicked.connect(d.accept) def onchange(): b = bb.button(bb.Apply) b.setEnabled(True) b.setDefault(True) b.setAutoDefault(True) w.changed_signal.connect(onchange) bb.button(bb.Cancel).setFocus(True) l = QVBoxLayout() d.setLayout(l) l.addWidget(w) l.addWidget(bb) mygui = gui is None if gui is None: gui = init_gui() mygui = True w.genesis(gui) w.initialize() if geom is not None: d.restoreGeometry(geom) d.exec_() geom = bytearray(d.saveGeometry()) gprefs[conf_name] = geom rr = getattr(d, 'restart_required', False) if show_restart_msg and rr: from calibre.gui2 import warning_dialog warning_dialog(gui, 'Restart required', 'Restart required', show=True) if mygui and not never_shutdown: gui.shutdown() return rr
def __init__(self, parent=None,): QDialog.__init__(self, parent) self.parent = parent self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION)) layout = QVBoxLayout(self) self.setLayout(layout) data_group_box = QGroupBox(u"", self) layout.addWidget(data_group_box) data_group_box_layout = QVBoxLayout() data_group_box.setLayout(data_group_box_layout) key_group = QHBoxLayout() data_group_box_layout.addLayout(key_group) key_group.addWidget(QLabel(u"PID:", self)) self.key_ledit = QLineEdit("", self) self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") key_group.addWidget(self.key_ledit) key_label = QLabel(_(''), self) key_label.setAlignment(Qt.AlignHCenter) data_group_box_layout.addWidget(key_label) self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) layout.addWidget(self.button_box) self.resize(self.sizeHint())
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())
class LogDialog(QDialog): # GUI definition def __init__(self, log, icon): ''' :param log: The text to show in the dialog :param icon: The window icon ''' QDialog.__init__(self) self.setWindowTitle(_('Prince log')) self.setWindowIcon(icon) self.l = QVBoxLayout() self.setLayout(self.l) monofont = QFont('') monofont.setStyleHint(QFont.TypeWriter) self.box = QPlainTextEdit() self.box.setPlainText(log) self.box.setStyleSheet('* { font-family: monospace }') self.box.setMinimumWidth(500) self.box.setLineWrapMode(QPlainTextEdit.NoWrap) self.box.setReadOnly(True) self.box.setToolTip(_('<qt>Console output from the last Prince run</qt>')) self.l.addWidget(self.box) self.buttons = QDialogButtonBox(QDialogButtonBox.Ok) self.l.addWidget(self.buttons) self.buttons.accepted.connect(self.accept) self.adjustSize()
class PlotDialog(QDialog): def __init__(self, parent=None): super(PlotDialog, self).__init__(parent) self.resize(550, 350) #self.verticalLayout.addWidget(self.buttonBox) def init_plot(self, component, field): self.plot = DataPlot() self.plot.initData(component, field) self.plot.resize(500, 300) self.plot.show() self.verticalLayout = QVBoxLayout(self) self.verticalLayout.addWidget(self.plot) def get_plot(self): return self.plot def closeEvent(self, event): self.reject() super(PlotDialog, self).closeEvent(event)
def __init__(self, parent, friendly_name, rac): #self.dialog = QDialog(parent.gui) QDialog.__init__(self, parent.gui) self.parent = parent self.opts = parent.opts self.rac = rac parent_loc = self.parent.gui.pos() self.move(parent_loc.x(), parent_loc.y()) self.setWindowTitle(rac.import_dialog_title) self.setWindowIcon(self.opts.icon) l = QVBoxLayout() self.setLayout(l) self.pte = PlainTextEdit(self.parent) self.pte.setPlainText(rac.initial_dialog_text) self.pte.setMinimumWidth(400) l.addWidget(self.pte) self.dialogButtonBox = QDialogButtonBox(QDialogButtonBox.Cancel|QDialogButtonBox.Help) self.import_button = self.dialogButtonBox.addButton(self.dialogButtonBox.Ok) self.import_button.setText('Import') self.dialogButtonBox.clicked.connect(self.import_annotations_dialog_clicked) l.addWidget(self.dialogButtonBox) self.rejected.connect(self.close) self.exec_() self.text = str(self.pte.toPlainText())
def message_dialog(self, msg): self.clear_dialog() self.dialog = dialog = WindowModalDialog(self.top_level_window(), _("Ledger Status")) l = QLabel(msg) vbox = QVBoxLayout(dialog) vbox.addWidget(l) dialog.show()
def __init__(self, parent, icon, text, over=True): QDialog.__init__(self, parent) self.state=None layout = QVBoxLayout(self) self.setLayout(layout) self.setWindowTitle('UnMerge Epub') label = QLabel(text) label.setOpenExternalLinks(True) label.setWordWrap(True) layout.addWidget(label) button_box = QDialogButtonBox(self) button = button_box.addButton(_("Add"), button_box.AcceptRole) button.clicked.connect(self.add) if over: button = button_box.addButton(_("Overwrite"), button_box.AcceptRole) button.clicked.connect(self.over) button = button_box.addButton(_("Discard"), button_box.AcceptRole) button.clicked.connect(self.discard) button_box.accepted.connect(self.accept) layout.addWidget(button_box)
class HelpView(SizePersistedDialog): ''' Modeless dialog for presenting HTML help content ''' def __init__(self, parent, icon, prefs, html=None, page=None, title=''): self.prefs = prefs #QDialog.__init__(self, parent=parent) super(HelpView, self).__init__(parent, 'help_dialog') self.setWindowTitle(title) self.setWindowIcon(icon) self.l = QVBoxLayout(self) self.setLayout(self.l) self.wv = QWebView() if html is not None: self.wv.setHtml(html) elif page is not None: self.wv.load(QUrl(page)) self.wv.setMinimumHeight(100) self.wv.setMaximumHeight(16777215) self.wv.setMinimumWidth(400) self.wv.setMaximumWidth(16777215) self.wv.setGeometry(0, 0, 400, 100) self.wv.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.l.addWidget(self.wv) # Sizing sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.resize_dialog()
def initialize(self): """ Intialize QWidget """ self.timer.setInterval(30000) self.timer.start() self.timer.timeout.connect(self.send_datamanager_events) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.events_list.setDragDropMode(QAbstractItemView.DragOnly) self.events_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.events_list.setDropIndicatorShown(True) self.events_list.doubleClicked.connect(self.remove_event) self.events_list.setWordWrap(True) self.events_list.setIconSize(QSize(16, 16)) self.add_event( 'OK', _('Welcome %s, you are connected to Alignak Backend') % data_manager.database['user'].name, timer=True ) layout.addWidget(self.events_list)
class Comments(Base): def setup_ui(self, parent): self._box = QGroupBox(parent) self._box.setTitle('&'+self.col_metadata['name']) self._layout = QVBoxLayout() self._tb = CommentsEditor(self._box) self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) # self._tb.setTabChangesFocus(True) self._layout.addWidget(self._tb) self._box.setLayout(self._layout) self.widgets = [self._box] def setter(self, val): if not val or not val.strip(): val = '' else: val = comments_to_html(val) self._tb.html = val self._tb.wyswyg_dirtied() def getter(self): val = unicode(self._tb.html).strip() if not val: val = None return val
class ConfigWidget(QWidget): def __init__(self, plugin_action): QWidget.__init__(self) self.plugin_action = plugin_action self.l = QVBoxLayout() self.setLayout(self.l) tab_widget = QTabWidget(self) self.l.addWidget(tab_widget) self.basic_tab = BasicTab(self, plugin_action) tab_widget.addTab(self.basic_tab, _('Basic')) self.searches_tab = SearchesTab(self, plugin_action) tab_widget.addTab(self.searches_tab, _('Searches')) def save_settings(self): prefs['checkreadinglistsync'] = self.basic_tab.checkreadinglistsync.isChecked() prefs['checkdups'] = self.basic_tab.checkdups.isChecked() prefs['checknotinlibrary'] = self.basic_tab.checknotinlibrary.isChecked() prefs['checknotondevice'] = self.basic_tab.checknotondevice.isChecked() prefs['checkdups_search'] = unicode(self.searches_tab.checkdups_search.text()) prefs['checknotinlibrary_search'] = unicode(self.searches_tab.checknotinlibrary_search.text()) prefs['checknotondevice_search'] = unicode(self.searches_tab.checknotondevice_search.text()) prefs.save_to_db() def edit_shortcuts(self): self.save_settings() d = KeyboardConfigDialog(self.plugin_action.gui, self.plugin_action.action_spec[0]) if d.exec_() == d.Accepted: self.plugin_action.gui.keyboard.finalize()
class ConfigWidget(QWidget): def __init__(self): QWidget.__init__(self) self.l = QVBoxLayout() self.setLayout(self.l) self.about_button = QPushButton('Help', self) self.about_button.clicked.connect(self.about) self.l.addWidget(self.about_button) self.notebookLabel = QLabel('evernote Notebook') self.l.addWidget(self.notebookLabel) self.notebookMsg = QLineEdit(self) self.notebookMsg.setText(prefs['notebook']) self.l.addWidget(self.notebookMsg) self.notebookLabel.setBuddy(self.notebookMsg) self.tagsCsvLabel = QLabel('evernote Tags CSV (ie calibre,mykindle)') self.l.addWidget(self.tagsCsvLabel) self.tagsCsvMsg = QLineEdit(self) self.tagsCsvMsg.setText(prefs['tagsCsv']) self.l.addWidget(self.tagsCsvMsg) self.tagsCsvLabel.setBuddy(self.tagsCsvMsg) def save_settings(self): prefs['notebook'] = unicode(self.notebookMsg.text()) prefs['tagsCsv'] = unicode(self.tagsCsvMsg.text()) def about(self): text = get_resources('about.txt') QMessageBox.about(self, 'About calibrebeam', text.decode('utf-8'))
class CustomColumnsTab(QWidget): 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(_("If you have custom columns defined, they will be listed below. Choose how you would like these columns handled.")) label.setWordWrap(True) self.l.addWidget(label) self.l.addSpacing(5) scrollable = QScrollArea() scrollcontent = QWidget() scrollable.setWidget(scrollcontent) scrollable.setWidgetResizable(True) self.l.addWidget(scrollable) self.sl = QVBoxLayout() scrollcontent.setLayout(self.sl) self.custcol_dropdowns = {} custom_columns = self.plugin_action.gui.library_view.model().custom_columns grid = QGridLayout() self.sl.addLayout(grid) row=0 for key, column in custom_columns.iteritems(): if column['datatype'] in permitted_values: # print("\n============== %s ===========\n"%key) # for (k,v) in column.iteritems(): # print("column['%s'] => %s"%(k,v)) label = QLabel('%s(%s)'%(column['name'],key)) label.setToolTip(_("Set this %s column on new merged books...")%column['datatype']) grid.addWidget(label,row,0) dropdown = QComboBox(self) dropdown.addItem('','none') for md in permitted_values[column['datatype']]: # tags-like column also 'text' if md == 'union' and not column['is_multiple']: continue if md == 'concat' and column['is_multiple']: continue dropdown.addItem(titleLabels[md],md) self.custcol_dropdowns[key] = dropdown if key in prefs['custom_cols']: dropdown.setCurrentIndex(dropdown.findData(prefs['custom_cols'][key])) dropdown.setToolTip(_("How this column will be populated by default.")) grid.addWidget(dropdown,row,1) row+=1 self.sl.insertStretch(-1)
class TabExtendedConfig(DeviceConfigTab): def __init__(self, parent, device): super(TabExtendedConfig, self).__init__(parent) self.l = QVBoxLayout(self) self.setLayout(self.l) self.extended_options = ExtendedGroupBox(self, device) self.l.addWidget(self.extended_options) self.addDeviceWidget(self.extended_options)
def __init__(self, info_str, parent=None): super(InfoDialog, self).__init__(parent) layout = QVBoxLayout(self) layout.addWidget(QLabel(info_str)) buttons = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, self) buttons.accepted.connect(self.accept) layout.addWidget(buttons)
def _init_controls(self): # Add the control set vbl = QVBoxLayout() self.move_element_up_tb = QToolButton() self.move_element_up_tb.setObjectName("move_element_up_tb") self.move_element_up_tb.setToolTip('Move element up') self.move_element_up_tb.setIcon(QIcon(I('arrow-up.png'))) self.move_element_up_tb.clicked.connect(self.move_row_up) vbl.addWidget(self.move_element_up_tb) self.undo_css_tb = QToolButton() self.undo_css_tb.setObjectName("undo_css_tb") self.undo_css_tb.setToolTip('Restore CSS to last saved') self.undo_css_tb.setIcon(QIcon(I('edit-undo.png'))) self.undo_css_tb.clicked.connect(partial(self.undo_reset_button_clicked, 'undo')) vbl.addWidget(self.undo_css_tb) self.reset_css_tb = QToolButton() self.reset_css_tb.setObjectName("reset_css_tb") self.reset_css_tb.setToolTip('Reset CSS to default') self.reset_css_tb.setIcon(QIcon(I('trash.png'))) self.reset_css_tb.clicked.connect(partial(self.undo_reset_button_clicked, 'reset')) vbl.addWidget(self.reset_css_tb) self.move_element_down_tb = QToolButton() self.move_element_down_tb.setObjectName("move_element_down_tb") self.move_element_down_tb.setToolTip('Move element down') self.move_element_down_tb.setIcon(QIcon(I('arrow-down.png'))) self.move_element_down_tb.clicked.connect(self.move_row_down) vbl.addWidget(self.move_element_down_tb) self.layout.addLayout(vbl)
def __init__(self, parent): super(MatrixDialog, self).__init__(parent) self.setWindowTitle(_("Trezor Matrix Recovery")) self.num = 9 self.loop = QEventLoop() vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(MATRIX_RECOVERY)) grid = QGridLayout() grid.setSpacing(0) self.char_buttons = [] for y in range(3): for x in range(3): button = QPushButton('?') button.clicked.connect(partial(self.process_key, ord('1') + y * 3 + x)) grid.addWidget(button, 3 - y, x) self.char_buttons.append(button) vbox.addLayout(grid) self.backspace_button = QPushButton("<=") self.backspace_button.clicked.connect(partial(self.process_key, Qt.Key_Backspace)) self.cancel_button = QPushButton(_("Cancel")) self.cancel_button.clicked.connect(partial(self.process_key, Qt.Key_Escape)) buttons = Buttons(self.backspace_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
def __init__(self, parent): super(CharacterDialog, self).__init__(parent) self.setWindowTitle(_("KeepKey Seed Recovery")) self.character_pos = 0 self.word_pos = 0 self.loop = QEventLoop() self.word_help = QLabel() self.char_buttons = [] vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(CHARACTER_RECOVERY)) hbox = QHBoxLayout() hbox.addWidget(self.word_help) for i in range(4): char_button = CharacterButton('*') char_button.setMaximumWidth(36) self.char_buttons.append(char_button) hbox.addWidget(char_button) self.accept_button = CharacterButton(_("Accept Word")) self.accept_button.clicked.connect(partial(self.process_key, 32)) self.rejected.connect(partial(self.loop.exit, 1)) hbox.addWidget(self.accept_button) hbox.addStretch(1) vbox.addLayout(hbox) self.finished_button = QPushButton(_("Seed Entered")) self.cancel_button = QPushButton(_("Cancel")) self.finished_button.clicked.connect(partial(self.process_key, Qt.Key_Return)) self.cancel_button.clicked.connect(self.rejected) buttons = Buttons(self.finished_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
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())
class ConfigWidget(QWidget): def __init__(self, plugin_action): QWidget.__init__(self) self.plugin_action = plugin_action self.l = QVBoxLayout() self.setLayout(self.l) tab_widget = QTabWidget(self) self.l.addWidget(tab_widget) self.basic_tab = BasicTab(self, plugin_action) tab_widget.addTab(self.basic_tab, _('Basic')) self.columns_tab = CustomColumnsTab(self, plugin_action) tab_widget.addTab(self.columns_tab, _('Custom Columns')) def save_settings(self): prefs['editmetadata'] = self.basic_tab.editmetadata.isChecked() prefs['show_checkedalways'] = self.basic_tab.show_checkedalways.isChecked() prefs['copytoctitle'] = self.basic_tab.copytoctitle.isChecked() prefs['copytitle'] = self.basic_tab.copytitle.isChecked() prefs['copyauthors'] = self.basic_tab.copyauthors.isChecked() prefs['copytags'] = self.basic_tab.copytags.isChecked() prefs['copylanguages'] = self.basic_tab.copylanguages.isChecked() prefs['copyseries'] = self.basic_tab.copyseries.isChecked() prefs['copycomments'] = self.basic_tab.copycomments.isChecked() prefs['copycover'] = self.basic_tab.copycover.isChecked() prefs['copydate'] = self.basic_tab.copydate.isChecked() prefs['copyrating'] = self.basic_tab.copyrating.isChecked() prefs['copypubdate'] = self.basic_tab.copypubdate.isChecked() prefs['copyidentifiers'] = self.basic_tab.copyidentifiers.isChecked() prefs['copypublisher'] = self.basic_tab.copypublisher.isChecked() # Custom Columns tab colsmap = {} for (col,chkbx) in self.columns_tab.custcol_checkboxes.iteritems(): if chkbx.isChecked(): colsmap[col] = chkbx.isChecked() #print("colsmap[%s]:%s"%(col,colsmap[col])) prefs['custom_cols'] = colsmap prefs['sourcecol'] = unicode(convert_qvariant(self.columns_tab.sourcecol.itemData(self.columns_tab.sourcecol.currentIndex()))) prefs['sourcetemplate'] = unicode(self.columns_tab.sourcetemplate.text()) prefs.save_to_db() def edit_shortcuts(self): self.save_settings() d = KeyboardConfigDialog(self.plugin_action.gui, self.plugin_action.action_spec[0]) if d.exec_() == d.Accepted: self.plugin_action.gui.keyboard.finalize()
def message_dialog(self, msg, on_cancel): # Called more than once during signing, to confirm output and fee self.clear_dialog() title = _('Please check your %s device') % self.device self.dialog = dialog = WindowModalDialog(self.top_level_window(), title) l = QLabel(msg) vbox = QVBoxLayout(dialog) vbox.addWidget(l) if on_cancel: dialog.rejected.connect(on_cancel) vbox.addLayout(Buttons(CancelButton(dialog))) dialog.show()
def create_main_frame(self): page = QWidget() self.button = QPushButton('OK', page) self.textWindow = QTextEdit() vbox1 = QVBoxLayout() vbox1.addWidget(self.textWindow) vbox1.addWidget(self.button) page.setLayout(vbox1) self.setCentralWidget(page) self.button.clicked.connect(self.clicked)
def genesis(self, gui): self.gui = gui if not isosx and not iswindows: self.label_widget_style.setVisible(False) self.opt_ui_style.setVisible(False) db = gui.library_view.model().db r = self.register try: self.icon_theme_title = json.loads(I('icon-theme.json', data=True))['name'] except Exception: self.icon_theme_title = _('Default icons') self.icon_theme.setText( _('Icon theme: <b>%s</b>') % self.icon_theme_title) self.commit_icon_theme = None self.icon_theme_button.clicked.connect(self.choose_icon_theme) self.default_author_link = DefaultAuthorLink( self.default_author_link_container) self.default_author_link.changed_signal.connect(self.changed_signal) r('gui_layout', config, restart_required=True, choices=[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')]) r('hidpi', gprefs, restart_required=True, choices=[(_('Automatic'), 'auto'), (_('On'), 'on'), (_('Off'), 'off')]) if isosx: self.opt_hidpi.setVisible(False), self.label_hidpi.setVisible( False) r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('calibre style'), 'calibre')]) r('book_list_tooltips', gprefs) r('show_layout_buttons', gprefs, restart_required=True) r('row_numbers_in_book_list', gprefs) r('tag_browser_old_look', gprefs) r('tag_browser_hide_empty_categories', gprefs) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) r('cover_grid_width', gprefs) r('cover_grid_height', gprefs) r('cover_grid_cache_size_multiple', gprefs) r('cover_grid_disk_cache_size', gprefs) r('cover_grid_spacing', gprefs) r('cover_grid_show_title', gprefs) r('tag_browser_show_counts', gprefs) r('tag_browser_item_padding', gprefs) r('qv_respects_vls', gprefs) r('qv_dclick_changes_column', gprefs) r('qv_retkey_changes_column', gprefs) r('qv_follows_column', gprefs) r('cover_flow_queue_length', config, restart_required=True) r('cover_browser_reflections', gprefs) r('cover_browser_title_template', db.prefs) fm = db.field_metadata r('cover_browser_subtitle_field', db.prefs, choices=[(_('No subtitle'), 'none')] + sorted( (fm[k].get('name'), k) for k in fm.all_field_keys() if fm[k].get('name'))) r('emblem_size', gprefs) r('emblem_position', gprefs, choices=[(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')]) r('book_list_extra_row_spacing', gprefs) r('book_details_narrow_comments_layout', gprefs, choices=[(_('Float'), 'float'), (_('Columns'), 'columns')]) self.opt_book_details_narrow_comments_layout.setToolTip( textwrap.fill( _('Choose how the text is laid out when using the "Narrow" user interface layout.' ' A value of "Float" means that the comments text will wrap around' ' the other metadata fields, while a value of "Columns" means that' ' the comments will be in a separate fixed width column.'))) self.cover_browser_title_template_button.clicked.connect( self.edit_cb_title_template) self.id_links_button.clicked.connect(self.edit_id_link_rules) def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) lang = get_lang() if lang is None or lang not in available_translations(): lang = 'en' items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(cmp=lambda x, y: cmp(x[1].lower(), y[1].lower())) choices = [(y, x) for x, y in items] # Default language is the autodetected one choices = [(get_language(lang), lang)] + choices r('language', prefs, choices=choices, restart_required=True) r('show_avg_rating', config) r('disable_animations', config) r('systray_icon', config, restart_required=True) r('show_splash_screen', gprefs) r('disable_tray_notification', config) r('use_roman_numerals_for_series_number', config) r('separate_cover_flow', config, restart_required=True) r('cb_fullscreen', gprefs) r('cb_preserve_aspect_ratio', gprefs) choices = [(_('Off'), 'off'), (_('Small'), 'small'), (_('Medium'), 'medium'), (_('Large'), 'large')] r('toolbar_icon_size', gprefs, choices=choices) choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'), (_('Never'), 'never')] r('toolbar_text', gprefs, choices=choices) choices = [(_('Disabled'), 'disable'), (_('By first letter'), 'first letter'), (_('Partitioned'), 'partition')] r('tags_browser_partition_method', gprefs, choices=choices) r('tags_browser_collapse_at', gprefs) r('tag_browser_dont_collapse', gprefs, setting=CommaSeparatedList) choices = set([ k for k in db.field_metadata.all_field_keys() if (db.field_metadata[k]['is_category'] and (db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']) and not db.field_metadata[k]['display'].get('is_names', False)) or (db.field_metadata[k]['datatype'] in ['composite'] and db.field_metadata[k]['display'].get('make_category', False)) ]) choices -= set( ['authors', 'publisher', 'formats', 'news', 'identifiers']) choices |= set(['search']) self.opt_categories_using_hierarchy.update_items_cache(choices) r('categories_using_hierarchy', db.prefs, setting=CommaSeparatedList, choices=sorted(list(choices), key=sort_key)) fm = db.field_metadata choices = sorted( ((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']), key=lambda x: sort_key(x[0])) r('field_under_covers_in_grid', db.prefs, choices=choices) self.current_font = self.initial_font = None self.change_font_button.clicked.connect(self.change_font) self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order) self.display_model.dataChanged.connect(self.changed_signal) self.field_display_order.setModel(self.display_model) self.df_up_button.clicked.connect( partial(move_field_up, self.field_display_order, self.display_model)) self.df_down_button.clicked.connect( partial(move_field_down, self.field_display_order, self.display_model)) self.qv_display_model = QVDisplayedFields(self.gui.current_db, self.qv_display_order) self.qv_display_model.dataChanged.connect(self.changed_signal) self.qv_display_order.setModel(self.qv_display_model) self.qv_up_button.clicked.connect( partial(move_field_up, self.qv_display_order, self.qv_display_model)) self.qv_down_button.clicked.connect( partial(move_field_down, self.qv_display_order, self.qv_display_model)) self.edit_rules = EditRules(self.tabWidget) self.edit_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.edit_rules, QIcon(I('format-fill-color.png')), _('Column &coloring')) self.icon_rules = EditRules(self.tabWidget) self.icon_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.icon_rules, QIcon(I('icon_choose.png')), _('Column &icons')) self.grid_rules = EditRules(self.emblems_tab) self.grid_rules.changed.connect(self.changed_signal) self.emblems_tab.setLayout(QVBoxLayout()) self.emblems_tab.layout().addWidget(self.grid_rules) self.tabWidget.setCurrentIndex(0) keys = [ QKeySequence('F11', QKeySequence.PortableText), QKeySequence('Ctrl+Shift+F', QKeySequence.PortableText) ] keys = [unicode(x.toString(QKeySequence.NativeText)) for x in keys] self.fs_help_msg.setText( unicode(self.fs_help_msg.text()) % (_(' or ').join(keys))) self.size_calculated.connect(self.update_cg_cache_size, type=Qt.QueuedConnection) self.tabWidget.currentChanged.connect(self.tab_changed) l = self.cg_background_box.layout() self.cg_bg_widget = w = Background(self) l.addWidget(w, 0, 0, 3, 1) self.cover_grid_color_button = b = QPushButton(_('Change &color'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 0, 1) b.clicked.connect(self.change_cover_grid_color) self.cover_grid_texture_button = b = QPushButton( _('Change &background image'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 1, 1) b.clicked.connect(self.change_cover_grid_texture) self.cover_grid_default_appearance_button = b = QPushButton( _('Restore &default appearance'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 2, 1) b.clicked.connect(self.restore_cover_grid_appearance) self.cover_grid_empty_cache.clicked.connect(self.empty_cache) self.cover_grid_open_cache.clicked.connect(self.open_cg_cache) self.cover_grid_smaller_cover.clicked.connect( partial(self.resize_cover, True)) self.cover_grid_larger_cover.clicked.connect( partial(self.resize_cover, False)) self.cover_grid_reset_size.clicked.connect(self.cg_reset_size) self.opt_cover_grid_disk_cache_size.setMinimum( self.gui.grid_view.thumbnail_cache.min_disk_cache) self.opt_cover_grid_disk_cache_size.setMaximum( self.gui.grid_view.thumbnail_cache.min_disk_cache * 100) self.opt_cover_grid_width.valueChanged.connect( self.update_aspect_ratio) self.opt_cover_grid_height.valueChanged.connect( self.update_aspect_ratio)
class TagBrowserWidget(QFrame): # {{{ def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.NoFrame if gprefs['tag_browser_old_look'] else QFrame.StyledPanel) self._parent = parent self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) # Set up the find box & button self.tb_bar = tbb = TagBrowserBar(self) tbb.clear_find.connect(self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) # The tags view parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self._layout.insertWidget(0, 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) # The Alter Tag Browser button l = self.alter_tb self.collapse_all_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll()) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Configure Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate( (_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip(_('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate( (_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip( _('All of these category_managers are available by right-clicking ' 'on items in the Tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item) # self.leak_test_timer = QTimer(self) # self.leak_test_timer.timeout.connect(self.test_for_leak) # self.leak_test_timer.start(5000) def save_state(self): gprefs.set('tag browser search box visible', self.toggle_search_button.isChecked()) def toggle_item(self): self.tags_view.toggle_current_index() def set_pane_is_visible(self, to_what): self.tags_view.set_pane_is_visible(to_what) def find_text_changed(self, str): self.current_find_position = None def set_focus_to_find_box(self): self.tb_bar.set_focus_to_find_box() def do_find(self, str=None): self.current_find_position = None self.find() @property def find_text(self): return unicode_type(self.item_search.currentText()).strip() def reset_find(self): model = self.tags_view.model() if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None def find(self): model = self.tags_view.model() model.clear_boxed() # When a key is specified don't use the auto-collapsing search. # A colon separates the lookup key from the search string. # A leading colon says not to use autocollapsing search but search all keys txt = self.find_text colon = txt.find(':') if colon >= 0: key = self._parent.library_view.model().db.\ field_metadata.search_term_to_field_key(txt[:colon]) if key in self._parent.library_view.model().db.field_metadata: txt = txt[colon + 1:] else: key = '' txt = txt[1:] if colon == 0 else txt else: key = None # key is None indicates that no colon was found. # key == '' means either a leading : was found or the key is invalid # At this point the txt might have a leading =, in which case do an # exact match search if (gprefs.get('tag_browser_always_autocollapse', False) and key is None and not txt.startswith('*')): txt = '*' + txt if txt.startswith('*'): self.tags_view.collapseAll() model.set_categories_filter(txt[1:]) self.tags_view.recount() self.current_find_position = None return if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None if not txt: return self.item_search.lineEdit().blockSignals(True) self.search_button.setFocus(True) self.item_search.lineEdit().blockSignals(False) if txt.startswith('='): equals_match = True txt = txt[1:] else: equals_match = False self.current_find_position = \ model.find_item_node(key, txt, self.current_find_position, equals_match=equals_match) if self.current_find_position: self.tags_view.show_item_at_path(self.current_find_position, box=True) elif self.item_search.text(): self.not_found_label.setVisible(True) if self.tags_view.verticalScrollBar().isVisible(): sbw = self.tags_view.verticalScrollBar().width() else: sbw = 0 width = self.width() - 8 - sbw height = self.not_found_label.heightForWidth(width) + 20 self.not_found_label.resize(width, height) self.not_found_label.move(4, 10) self.not_found_label_timer.start(2000) def not_found_label_timer_event(self): self.not_found_label.setVisible(False) def keyPressEvent(self, ev): if ev.key() in (Qt.Key_Enter, Qt.Key_Return) and self.find_text: self.find() ev.accept() return return QFrame.keyPressEvent(self, ev)
def __init__(self, ids, get_metadata, field_metadata, parent=None, window_title=None, reject_button_tooltip=None, accept_all_tooltip=None, reject_all_tooltip=None, revert_tooltip=None, intro_msg=None, action_button=None, **kwargs): QDialog.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) self.setWindowIcon(QIcon(I('auto_author_sort.png'))) self.get_metadata = get_metadata self.ids = list(ids) self.total = len(self.ids) self.accepted = OrderedDict() self.rejected_ids = set() self.window_title = window_title or _('Compare metadata') if intro_msg: self.la = la = QLabel(intro_msg) la.setWordWrap(True) l.addWidget(la) self.compare_widget = CompareSingle(field_metadata, parent=parent, revert_tooltip=revert_tooltip, **kwargs) self.sa = sa = QScrollArea() l.addWidget(sa) sa.setWidget(self.compare_widget) sa.setWidgetResizable(True) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Cancel) bb.button(bb.Cancel).setAutoDefault(False) bb.rejected.connect(self.reject) if self.total > 1: self.aarb = b = bb.addButton(_('&Accept all remaining'), bb.YesRole) b.setIcon(QIcon(I('ok.png'))), b.setAutoDefault(False) if accept_all_tooltip: b.setToolTip(accept_all_tooltip) b.clicked.connect(self.accept_all_remaining) self.rarb = b = bb.addButton(_('Re&ject all remaining'), bb.ActionRole) b.setIcon(QIcon(I('minus.png'))), b.setAutoDefault(False) if reject_all_tooltip: b.setToolTip(reject_all_tooltip) b.clicked.connect(self.reject_all_remaining) self.sb = b = bb.addButton(_('R&eject'), bb.ActionRole) b.clicked.connect(partial(self.next_item, False)) b.setIcon(QIcon(I('minus.png'))), b.setAutoDefault(False) if reject_button_tooltip: b.setToolTip(reject_button_tooltip) self.next_action = ac = QAction(self) ac.setShortcut(QKeySequence(Qt.ALT | Qt.Key_Right)) self.addAction(ac) if action_button is not None: self.acb = b = bb.addButton(action_button[0], bb.ActionRole) b.setIcon(QIcon(action_button[1])) self.action_button_action = action_button[2] b.clicked.connect(self.action_button_clicked) self.nb = b = bb.addButton( _('&Next') if self.total > 1 else _('&OK'), bb.ActionRole) if self.total > 1: b.setToolTip( _('Move to next [%s]') % self.next_action.shortcut().toString(QKeySequence.NativeText)) self.next_action.triggered.connect(b.click) b.setIcon(QIcon(I('forward.png' if self.total > 1 else 'ok.png'))) b.clicked.connect(partial(self.next_item, True)) b.setDefault(True), b.setAutoDefault(True) self.bbh = h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) l.addLayout(h) self.markq = m = QCheckBox(_('&Mark rejected books')) m.setChecked(gprefs['metadata_diff_mark_rejected']) m.stateChanged[int].connect( lambda: gprefs.set('metadata_diff_mark_rejected', m.isChecked())) m.setToolTip( _('Mark rejected books in the book list after this dialog is closed' )) h.addWidget(m), h.addWidget(bb) self.next_item(True) desktop = QApplication.instance().desktop() geom = desktop.availableGeometry(parent or self) width = max(700, min(950, geom.width() - 50)) height = max(650, min(1000, geom.height() - 100)) self.resize(QSize(width, height)) geom = gprefs.get('diff_dialog_geom', None) if geom is not None: self.restoreGeometry(geom) b.setFocus(Qt.OtherFocusReason)
def _setupUi(self): settings = Settings() settings.beginGroup('Browser-View-Settings') windowGeometry = settings.value('WindowGeometry', b'') keys = [ ('LocationBarWidth', int), ('WebSearchBarWidth', int), ('SideBarWidth', int), ('WebViewWidth', int), ('SideBar', str), ] uiState = {} for key, typ in keys: if settings.contains(key): uiState[key] = typ(settings.value(key)) settings.endGroup() widget = QWidget(self) widget.setCursor(Qt.ArrowCursor) self.setCentralWidget(widget) self._mainLayout = QVBoxLayout(widget) self._mainLayout.setContentsMargins(0, 0, 0, 0) self._mainLayout.setSpacing(0) self._mainSplitter = QSplitter(self) self._mainSplitter.setObjectName('sidebar-splitter') self._tabWidget = TabWidget(self) self._superMenu = QMenu(self) self._navigationToolbar = NavigationBar(self) self._bookmarksToolbar = BookmarksToolbar(self) self._tabModel = TabModel(self, self) self._tabMruModel = TabMruModel(self, self) self._tabMruModel.setSourceModel(self._tabModel) self._navigationContainer = NavigationContainer(self) self._navigationContainer.addWidget(self._navigationToolbar) self._navigationContainer.addWidget(self._bookmarksToolbar) self._navigationContainer.setTabBar(self._tabWidget.tabBar()) self._mainSplitter.addWidget(self._tabWidget) self._mainSplitter.setCollapsible(0, False) self._mainLayout.addWidget(self._navigationContainer) self._mainLayout.addWidget(self._mainSplitter) self._statusBar = StatusBar(self) self._statusBar.setObjectName('mainwindow-statusbar') self._statusBar.setCursor(Qt.ArrowCursor) self.setStatusBar(self._statusBar) self._progressBar = ProgressBar(self._statusBar) self._ipLabel = QLabel(self) self._ipLabel.setObjectName('statusbar-ip-label') self._ipLabel.setToolTip('IP Address of current page') self._statusBar.addPermanentWidget(self._progressBar) self._statusBar.addPermanentWidget(self.ipLabel()) downloadsButton = DownloadsButton(self) self._statusBar.addButton(downloadsButton) self._navigationToolbar.addToolButton(downloadsButton) desktop = gVar.app.desktop() windowWidth = desktop.availableGeometry().width() / 1.3 windowHeight = desktop.availableGeometry().height() / 1.3 # Let the WM decides where to put new browser window if self._windowType not in (const.BW_FirstAppWindow, const.BW_MacFirstWindow) and \ gVar.app.getWindow(): if const.OS_WIN: # Windows WM places every new window in the middle of screen .. for some reason p = gVar.app.getWindow().geometry().topLeft() p.setX(p.x() + 30) p.setY(p.y() + 30) if not desktop.availableGeometry( gVar.app.getWindow()).contains(p): p.setX( desktop.availableGeometry(gVar.app.getWindow()).x() + 30) p.setY( desktop.availableGeometry(gVar.app.getWindow()).y() + 30) self.setGeometry(QRect(p, gVar.app.getWindow().size())) else: self.resize(gVar.app.getWindow().size()) elif not self.restoreGeometry(windowGeometry): if const.OS_WIN: self.setGeometry( QRect( desktop.availableGeometry(gVar.app.getWindow()).x() + 30, desktop.availableGeometry(gVar.app.getWindow()).y() + 30, windowWidth, windowHeight)) else: self.resize(windowWidth, windowHeight) self._restoreUiState(uiState) # Set some sane minimum width self.setMinimumWidth(300)
def __init__(self, fm, pref_name, parent=None): QDialog.__init__(self, parent) self.fm = fm if pref_name == 'column_color_rules': self.rule_kind = 'color' rule_text = _('column coloring') elif pref_name == 'column_icon_rules': self.rule_kind = 'icon' rule_text = _('column icon') elif pref_name == 'cover_grid_icon_rules': self.rule_kind = 'emblem' rule_text = _('Cover grid emblem') self.setWindowIcon(QIcon(I('format-fill-color.png'))) self.setWindowTitle(_('Create/edit a {0} rule').format(rule_text)) self.l = l = QGridLayout(self) self.setLayout(l) self.l1 = l1 = QLabel( _('Create a {0} rule by' ' filling in the boxes below').format(rule_text)) l.addWidget(l1, 0, 0, 1, 8) self.f1 = QFrame(self) self.f1.setFrameShape(QFrame.HLine) l.addWidget(self.f1, 1, 0, 1, 8) self.l2 = l2 = QLabel( _('Add the emblem:') if self.rule_kind == 'emblem' else _('Set the')) l.addWidget(l2, 2, 0) if self.rule_kind == 'color': l.addWidget(QLabel(_('color'))) elif self.rule_kind == 'icon': self.kind_box = QComboBox(self) for tt, t in icon_rule_kinds: self.kind_box.addItem(tt, t) l.addWidget(self.kind_box, 2, 1) self.kind_box.setToolTip( textwrap.fill( _('If you choose composed icons and multiple rules match, then all the' ' matching icons will be combined, otherwise the icon from the' ' first rule to match will be used.'))) else: pass self.l3 = l3 = QLabel(_('of the column:')) l.addWidget(l3, 2, 2) self.column_box = QComboBox(self) l.addWidget(self.column_box, 2, 3) self.l4 = l4 = QLabel(_('to')) l.addWidget(l4, 2, 4) if self.rule_kind == 'emblem': l3.setVisible(False), self.column_box.setVisible( False), l4.setVisible(False) def create_filename_box(): self.filename_box = f = QComboBox() self.filenamebox_view = v = QListView() v.setIconSize(QSize(32, 32)) self.filename_box.setView(v) self.orig_filenamebox_view = f.view() f.setMinimumContentsLength(20), f.setSizeAdjustPolicy( f.AdjustToMinimumContentsLengthWithIcon) self.populate_icon_filenames() if self.rule_kind == 'color': self.color_box = ColorButton(parent=self) self.color_label = QLabel('Sample text Sample text') self.color_label.setTextFormat(Qt.RichText) l.addWidget(self.color_box, 2, 5) l.addWidget(self.color_label, 2, 6) l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7) elif self.rule_kind == 'emblem': create_filename_box() self.update_filename_box() self.filename_button = QPushButton(QIcon(I('document_open.png')), _('&Add new image')) l.addWidget(self.filename_box) l.addWidget(self.filename_button, 2, 6) l.addWidget(QLabel(_('(Images should be square-ish)')), 2, 7) l.setColumnStretch(7, 10) else: create_filename_box() vb = QVBoxLayout() self.multiple_icon_cb = QCheckBox(_('Choose &more than one icon')) vb.addWidget(self.multiple_icon_cb) self.update_filename_box() self.multiple_icon_cb.clicked.connect(self.multiple_box_clicked) vb.addWidget(self.filename_box) l.addLayout(vb, 2, 5) self.filename_button = QPushButton(QIcon(I('document_open.png')), _('&Add icon')) l.addWidget(self.filename_button, 2, 6) l.addWidget(QLabel(_('Icons should be square or landscape')), 2, 7) l.setColumnStretch(7, 10) self.l5 = l5 = QLabel( _('Only if the following conditions are all satisfied:')) l.addWidget(l5, 3, 0, 1, 7) self.scroll_area = sa = QScrollArea(self) sa.setMinimumHeight(300) sa.setMinimumWidth(950) sa.setWidgetResizable(True) l.addWidget(sa, 4, 0, 1, 8) self.add_button = b = QPushButton(QIcon(I('plus.png')), _('Add &another condition')) l.addWidget(b, 5, 0, 1, 8) b.clicked.connect(self.add_blank_condition) self.l6 = l6 = QLabel( _('You can disable a condition by' ' blanking all of its boxes')) l.addWidget(l6, 6, 0, 1, 8) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) l.addWidget(bb, 7, 0, 1, 8) if self.rule_kind != 'color': self.remove_button = b = bb.addButton(_('&Remove icon'), bb.ActionRole) b.setIcon(QIcon(I('minus.png'))) b.setMenu(QMenu()) b.setToolTip('<p>' + _( 'Remove a previously added icon. Note that doing so will cause rules that use it to stop working.' )) self.update_remove_button() self.conditions_widget = QWidget(self) sa.setWidget(self.conditions_widget) self.conditions_widget.setLayout(QVBoxLayout()) self.conditions_widget.layout().setAlignment(Qt.AlignTop) self.conditions = [] if self.rule_kind == 'color': for b in (self.column_box, ): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(15) for key in sorted(displayable_columns(fm), key=lambda k: sort_key(fm[k]['name']) if k != color_row_key else b''): if key == color_row_key and self.rule_kind != 'color': continue name = all_columns_string if key == color_row_key else fm[key][ 'name'] if name: self.column_box.addItem(name, key) self.column_box.setCurrentIndex(0) if self.rule_kind == 'color': self.color_box.color = '#000' self.update_color_label() self.color_box.color_changed.connect(self.update_color_label) else: self.rule_icon_files = [] self.filename_button.clicked.connect(self.filename_button_clicked) self.resize(self.sizeHint())
def ask_about_cc_mismatch(gui, db, newdb, missing_cols, incompatible_cols): # {{{ source_metadata = db.field_metadata.custom_field_metadata(include_composites=True) dest_library_path = newdb.library_path ndbname = os.path.basename(dest_library_path) d = QDialog(gui) d.setWindowTitle(_('Different custom columns')) l = QFormLayout() tl = QVBoxLayout() d.setLayout(tl) d.s = QScrollArea(d) tl.addWidget(d.s) d.w = QWidget(d) d.s.setWidget(d.w) d.s.setWidgetResizable(True) d.w.setLayout(l) d.setMinimumWidth(600) d.setMinimumHeight(500) d.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) msg = _('The custom columns in the <i>{0}</i> library are different from the ' 'custom columns in the <i>{1}</i> library. As a result, some metadata might not be copied.').format( os.path.basename(db.library_path), ndbname) d.la = la = QLabel(msg) la.setWordWrap(True) la.setStyleSheet('QLabel { margin-bottom: 1.5ex }') l.addRow(la) if incompatible_cols: la = d.la2 = QLabel(_('The following columns are incompatible - they have the same name' ' but different data types. They will be ignored: ') + ', '.join(sorted(incompatible_cols, key=sort_key))) la.setWordWrap(True) la.setStyleSheet('QLabel { margin-bottom: 1.5ex }') l.addRow(la) missing_widgets = [] if missing_cols: la = d.la3 = QLabel(_('The following columns are missing in the <i>{0}</i> library.' ' You can choose to add them automatically below.').format( ndbname)) la.setWordWrap(True) l.addRow(la) for k in missing_cols: widgets = (k, QCheckBox(_('Add to the %s library') % ndbname)) l.addRow(QLabel(k), widgets[1]) missing_widgets.append(widgets) d.la4 = la = QLabel(_('This warning is only shown once per library, per session')) la.setWordWrap(True) tl.addWidget(la) tl.addWidget(d.bb) d.bb.accepted.connect(d.accept) d.bb.rejected.connect(d.reject) d.resize(d.sizeHint()) if d.exec_() == d.Accepted: changes_made = False for k, cb in missing_widgets: if cb.isChecked(): col_meta = source_metadata[k] newdb.create_custom_column( col_meta['label'], col_meta['name'], col_meta['datatype'], len(col_meta['is_multiple']) > 0, col_meta['is_editable'], col_meta['display']) changes_made = True if changes_made: # Unload the db so that the changes are available # when it is next accessed from calibre.gui2.ui import get_gui library_broker = get_gui().library_broker library_broker.unload_library(dest_library_path) return True return False
def __init__(self, window, plugin, keystore, device_id): title = _("{} Settings").format(plugin.device) super(SettingsDialog, self).__init__(window, title) self.setMaximumWidth(540) devmgr = plugin.device_manager() config = devmgr.config handler = keystore.handler thread = keystore.thread hs_rows, hs_cols = (64, 128) def invoke_client(method, *args, **kw_args): unpair_after = kw_args.pop('unpair_after', False) def task(): client = devmgr.client_by_id(device_id) if not client: raise RuntimeError("Device not connected") if method: getattr(client, method)(*args, **kw_args) if unpair_after: devmgr.unpair_id(device_id) return client.features thread.add(task, on_success=update) def update(features): self.features = features set_label_enabled() if features.bootloader_hash: bl_hash = bh2u(features.bootloader_hash) bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]]) else: bl_hash = "N/A" noyes = [_("No"), _("Yes")] endis = [_("Enable Passphrases"), _("Disable Passphrases")] disen = [_("Disabled"), _("Enabled")] setchange = [_("Set a PIN"), _("Change PIN")] version = "%d.%d.%d" % (features.major_version, features.minor_version, features.patch_version) coins = ", ".join(coin.coin_name for coin in features.coins) device_label.setText(features.label) pin_set_label.setText(noyes[features.pin_protection]) passphrases_label.setText(disen[features.passphrase_protection]) bl_hash_label.setText(bl_hash) label_edit.setText(features.label) device_id_label.setText(features.device_id) initialized_label.setText(noyes[features.initialized]) version_label.setText(version) coins_label.setText(coins) clear_pin_button.setVisible(features.pin_protection) clear_pin_warning.setVisible(features.pin_protection) pin_button.setText(setchange[features.pin_protection]) pin_msg.setVisible(not features.pin_protection) passphrase_button.setText(endis[features.passphrase_protection]) language_label.setText(features.language) def set_label_enabled(): label_apply.setEnabled(label_edit.text() != self.features.label) def rename(): invoke_client('change_label', label_edit.text()) def toggle_passphrase(): title = _("Confirm Toggle Passphrase Protection") currently_enabled = self.features.passphrase_protection if currently_enabled: msg = _("After disabling passphrases, you can only pair this " "Electrum wallet if it had an empty passphrase. " "If its passphrase was not empty, you will need to " "create a new wallet with the install wizard. You " "can use this wallet again at any time by re-enabling " "passphrases and entering its passphrase.") else: msg = _("Your current Electrum wallet can only be used with " "an empty passphrase. You must create a separate " "wallet with the install wizard for other passphrases " "as each one generates a new set of addresses.") msg += "\n\n" + _("Are you sure you want to proceed?") if not self.question(msg, title=title): return invoke_client('toggle_passphrase', unpair_after=currently_enabled) def change_homescreen(): dialog = QFileDialog(self, _("Choose Homescreen")) filename, __ = dialog.getOpenFileName() if filename.endswith('.toif'): img = open(filename, 'rb').read() if img[:8] != b'TOIf\x90\x00\x90\x00': raise Exception( 'File is not a TOIF file with size of 144x144') else: from PIL import Image # FIXME im = Image.open(filename) if im.size != (128, 64): raise Exception('Image must be 128 x 64 pixels') im = im.convert('1') pix = im.load() img = bytearray(1024) for j in range(64): for i in range(128): if pix[i, j]: o = (i + j * 128) img[o // 8] |= (1 << (7 - o % 8)) img = bytes(img) invoke_client('change_homescreen', img) def clear_homescreen(): invoke_client('change_homescreen', b'\x00') def set_pin(): invoke_client('set_pin', remove=False) def clear_pin(): invoke_client('set_pin', remove=True) def wipe_device(): wallet = window.wallet if wallet and sum(wallet.get_balance()): title = _("Confirm Device Wipe") msg = _("Are you SURE you want to wipe the device?\n" "Your wallet still has bitcoins in it!") if not self.question( msg, title=title, icon=QMessageBox.Critical): return invoke_client('wipe_device', unpair_after=True) def slider_moved(): mins = timeout_slider.sliderPosition() timeout_minutes.setText(_("%2d minutes") % mins) def slider_released(): config.set_session_timeout(timeout_slider.sliderPosition() * 60) # Information tab info_tab = QWidget() info_layout = QVBoxLayout(info_tab) info_glayout = QGridLayout() info_glayout.setColumnStretch(2, 1) device_label = QLabel() pin_set_label = QLabel() passphrases_label = QLabel() version_label = QLabel() device_id_label = QLabel() bl_hash_label = QLabel() bl_hash_label.setWordWrap(True) coins_label = QLabel() coins_label.setWordWrap(True) language_label = QLabel() initialized_label = QLabel() rows = [ (_("Device Label"), device_label), (_("PIN set"), pin_set_label), (_("Passphrases"), passphrases_label), (_("Firmware Version"), version_label), (_("Device ID"), device_id_label), (_("Bootloader Hash"), bl_hash_label), (_("Supported Coins"), coins_label), (_("Language"), language_label), (_("Initialized"), initialized_label), ] for row_num, (label, widget) in enumerate(rows): info_glayout.addWidget(QLabel(label), row_num, 0) info_glayout.addWidget(widget, row_num, 1) info_layout.addLayout(info_glayout) # Settings tab settings_tab = QWidget() settings_layout = QVBoxLayout(settings_tab) settings_glayout = QGridLayout() # Settings tab - Label label_msg = QLabel( _("Name this {}. If you have multiple devices " "their labels help distinguish them.").format(plugin.device)) label_msg.setWordWrap(True) label_label = QLabel(_("Device Label")) label_edit = QLineEdit() label_edit.setMinimumWidth(150) label_edit.setMaxLength(plugin.MAX_LABEL_LEN) label_apply = QPushButton(_("Apply")) label_apply.clicked.connect(rename) label_edit.textChanged.connect(set_label_enabled) settings_glayout.addWidget(label_label, 0, 0) settings_glayout.addWidget(label_edit, 0, 1, 1, 2) settings_glayout.addWidget(label_apply, 0, 3) settings_glayout.addWidget(label_msg, 1, 1, 1, -1) # Settings tab - PIN pin_label = QLabel(_("PIN Protection")) pin_button = QPushButton() pin_button.clicked.connect(set_pin) settings_glayout.addWidget(pin_label, 2, 0) settings_glayout.addWidget(pin_button, 2, 1) pin_msg = QLabel( _("PIN protection is strongly recommended. " "A PIN is your only protection against someone " "stealing your bitcoins if they obtain physical " "access to your {}.").format(plugin.device)) pin_msg.setWordWrap(True) pin_msg.setStyleSheet("color: red") settings_glayout.addWidget(pin_msg, 3, 1, 1, -1) # Settings tab - Homescreen if plugin.device != 'KeepKey': # Not yet supported by KK firmware homescreen_layout = QHBoxLayout() homescreen_label = QLabel(_("Homescreen")) homescreen_change_button = QPushButton(_("Change...")) homescreen_clear_button = QPushButton(_("Reset")) homescreen_change_button.clicked.connect(change_homescreen) homescreen_clear_button.clicked.connect(clear_homescreen) homescreen_msg = QLabel( _("You can set the homescreen on your " "device to personalize it. You must " "choose a {} x {} monochrome black and " "white image.").format(hs_rows, hs_cols)) homescreen_msg.setWordWrap(True) settings_glayout.addWidget(homescreen_label, 4, 0) settings_glayout.addWidget(homescreen_change_button, 4, 1) settings_glayout.addWidget(homescreen_clear_button, 4, 2) settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1) # Settings tab - Session Timeout timeout_label = QLabel(_("Session Timeout")) timeout_minutes = QLabel() timeout_slider = QSlider(Qt.Horizontal) timeout_slider.setRange(1, 60) timeout_slider.setSingleStep(1) timeout_slider.setTickInterval(5) timeout_slider.setTickPosition(QSlider.TicksBelow) timeout_slider.setTracking(True) timeout_msg = QLabel( _("Clear the session after the specified period " "of inactivity. Once a session has timed out, " "your PIN and passphrase (if enabled) must be " "re-entered to use the device.")) timeout_msg.setWordWrap(True) timeout_slider.setSliderPosition(config.get_session_timeout() // 60) slider_moved() timeout_slider.valueChanged.connect(slider_moved) timeout_slider.sliderReleased.connect(slider_released) settings_glayout.addWidget(timeout_label, 6, 0) settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3) settings_glayout.addWidget(timeout_minutes, 6, 4) settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1) settings_layout.addLayout(settings_glayout) settings_layout.addStretch(1) # Advanced tab advanced_tab = QWidget() advanced_layout = QVBoxLayout(advanced_tab) advanced_glayout = QGridLayout() # Advanced tab - clear PIN clear_pin_button = QPushButton(_("Disable PIN")) clear_pin_button.clicked.connect(clear_pin) clear_pin_warning = QLabel( _("If you disable your PIN, anyone with physical access to your " "{} device can spend your bitcoins.").format(plugin.device)) clear_pin_warning.setWordWrap(True) clear_pin_warning.setStyleSheet("color: red") advanced_glayout.addWidget(clear_pin_button, 0, 2) advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5) # Advanced tab - toggle passphrase protection passphrase_button = QPushButton() passphrase_button.clicked.connect(toggle_passphrase) passphrase_msg = WWLabel(PASSPHRASE_HELP) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") advanced_glayout.addWidget(passphrase_button, 3, 2) advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5) advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5) # Advanced tab - wipe device wipe_device_button = QPushButton(_("Wipe Device")) wipe_device_button.clicked.connect(wipe_device) wipe_device_msg = QLabel( _("Wipe the device, removing all data from it. The firmware " "is left unchanged.")) wipe_device_msg.setWordWrap(True) wipe_device_warning = QLabel( _("Only wipe a device if you have the recovery seed written down " "and the device wallet(s) are empty, otherwise the bitcoins " "will be lost forever.")) wipe_device_warning.setWordWrap(True) wipe_device_warning.setStyleSheet("color: red") advanced_glayout.addWidget(wipe_device_button, 6, 2) advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5) advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5) advanced_layout.addLayout(advanced_glayout) advanced_layout.addStretch(1) tabs = QTabWidget(self) tabs.addTab(info_tab, _("Information")) tabs.addTab(settings_tab, _("Settings")) tabs.addTab(advanced_tab, _("Advanced")) dialog_vbox = QVBoxLayout(self) dialog_vbox.addWidget(tabs) dialog_vbox.addLayout(Buttons(CloseButton(self))) # Update information invoke_client(None)
def __init__(self, parent, view, row, link_delegate): QDialog.__init__(self, parent) self.normal_brush = QBrush(Qt.white) self.marked_brush = QBrush(Qt.lightGray) self.marked = None self.gui = parent self.splitter = QSplitter(self) self._l = l = QVBoxLayout(self) self.setLayout(l) l.addWidget(self.splitter) self.cover = CoverView(self) self.cover.resizeEvent = self.cover_view_resized self.cover.cover_changed.connect(self.cover_changed) self.cover_pixmap = None self.cover.sizeHint = self.details_size_hint self.splitter.addWidget(self.cover) self.details = Details(parent.book_details.book_info, self) self.details.page().setLinkDelegationPolicy( self.details.page().DelegateAllLinks) self.details.linkClicked.connect(self.link_clicked) s = self.details.page().settings() s.setAttribute(s.JavascriptEnabled, False) self.css = css() self.link_delegate = link_delegate self.details.setAttribute(Qt.WA_OpaquePaintEvent, False) palette = self.details.palette() self.details.setAcceptDrops(False) palette.setBrush(QPalette.Base, Qt.transparent) self.details.page().setPalette(palette) self.c = QWidget(self) self.c.l = l2 = QGridLayout(self.c) self.c.setLayout(l2) l2.addWidget(self.details, 0, 0, 1, -1) self.splitter.addWidget(self.c) self.fit_cover = QCheckBox(_('Fit &cover within view'), self) self.fit_cover.setChecked( gprefs.get('book_info_dialog_fit_cover', True)) l2.addWidget(self.fit_cover, l2.rowCount(), 0, 1, -1) self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self) self.previous_button.clicked.connect(self.previous) l2.addWidget(self.previous_button, l2.rowCount(), 0) self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self) self.next_button.clicked.connect(self.next) l2.addWidget(self.next_button, l2.rowCount() - 1, 1) self.view = view self.current_row = None self.refresh(row) self.view.model().new_bookdisplay_data.connect(self.slave) self.fit_cover.stateChanged.connect(self.toggle_cover_fit) self.ns = QShortcut(QKeySequence('Alt+Right'), self) self.ns.activated.connect(self.next) self.ps = QShortcut(QKeySequence('Alt+Left'), self) self.ps.activated.connect(self.previous) self.next_button.setToolTip( _('Next [%s]') % unicode(self.ns.key().toString(QKeySequence.NativeText))) self.previous_button.setToolTip( _('Previous [%s]') % unicode(self.ps.key().toString(QKeySequence.NativeText))) geom = QCoreApplication.instance().desktop().availableGeometry(self) screen_height = geom.height() - 100 screen_width = geom.width() - 100 self.resize(max(int(screen_width / 2), 700), screen_height) saved_layout = gprefs.get('book_info_dialog_layout', None) if saved_layout is not None: try: self.restoreGeometry(saved_layout[0]) self.splitter.restoreState(saved_layout[1]) except Exception: pass
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.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(self.tabs.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('N&ormal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_' + x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list' % x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(w.InstantPopup) self.toolbar2.addAction(self.editor.action_insert_link) self.toolbar2.addAction(self.editor.action_insert_hr) # }}} # toolbar3 {{{ for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.page().contentsChanged.connect(self.wyswyg_dirtied)
class Editor(QWidget): # {{{ toolbar_prefs_name = None 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.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(self.tabs.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('N&ormal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_' + x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list' % x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(w.InstantPopup) self.toolbar2.addAction(self.editor.action_insert_link) self.toolbar2.addAction(self.editor.action_insert_hr) # }}} # toolbar3 {{{ for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_' + x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.page().contentsChanged.connect(self.wyswyg_dirtied) def set_minimum_height_for_editor(self, val): self.editor.setMinimumHeight(val) @dynamic_property def html(self): def fset(self, v): self.editor.html = v def fget(self): self.tabs.setCurrentIndex(0) return self.editor.html return property(fget=fget, fset=fset) def change_tab(self, index): # print 'reloading:', (index and self.wyswyg_dirty) or (not index and # self.source_dirty) if index == 1: # changing to code view if self.wyswyg_dirty: self.code_edit.setPlainText(self.editor.html) self.wyswyg_dirty = False elif index == 0: # changing to wyswyg if self.source_dirty: self.editor.html = unicode(self.code_edit.toPlainText()) self.source_dirty = False @dynamic_property def tab(self): def fget(self): return 'code' if self.tabs.currentWidget( ) is self.code_edit else 'wyswyg' def fset(self, val): self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg) return property(fget=fget, fset=fset) def wyswyg_dirtied(self, *args): self.wyswyg_dirty = True def code_dirtied(self, *args): self.source_dirty = True def hide_toolbars(self): self.toolbar1.setVisible(False) self.toolbar2.setVisible(False) self.toolbar3.setVisible(False) def show_toolbars(self): self.toolbar1.setVisible(True) self.toolbar2.setVisible(True) self.toolbar3.setVisible(True) def toggle_toolbars(self): visible = self.toolbars_visible getattr(self, ('hide' if visible else 'show') + '_toolbars')() if self.toolbar_prefs_name is not None: gprefs.set(self.toolbar_prefs_name, visible) @dynamic_property def toolbars_visible(self): def fget(self): return self.toolbar1.isVisible() or self.toolbar2.isVisible( ) or self.toolbar3.isVisible() def fset(self, val): getattr(self, ('show' if val else 'hide') + '_toolbars')() return property(fget=fget, fset=fset) def set_readonly(self, what): self.editor.set_readonly(what) def hide_tabs(self): self.tabs.tabBar().setVisible(False)
return False # }}} if __name__ == '__main__': from calibre.gui2 import Application from calibre.devices.kobo.driver import KOBOTOUCH from calibre.devices.scanner import DeviceScanner s = DeviceScanner() s.scan() app = Application([]) debug_print("KOBOTOUCH:", KOBOTOUCH) dev = KOBOTOUCH(None) # dev.startup() # cd = dev.detect_managed_devices(s.devices) # dev.open(cd, 'test') cw = dev.config_widget() d = QDialog() d.l = QVBoxLayout() d.setLayout(d.l) d.l.addWidget(cw) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) d.l.addWidget(bb) bb.accepted.connect(d.accept) bb.rejected.connect(d.reject) if d.exec_() == d.Accepted: cw.commit() dev.shutdown()
def request_trezor_init_settings(self, wizard, method, device): vbox = QVBoxLayout() next_enabled = True label = QLabel(_("Enter a label to name your device:")) name = QLineEdit() hl = QHBoxLayout() hl.addWidget(label) hl.addWidget(name) hl.addStretch(1) vbox.addLayout(hl) def clean_text(widget): text = widget.toPlainText().strip() return ' '.join(text.split()) if method in [TIM_NEW, TIM_RECOVER]: gb = QGroupBox() hbox1 = QHBoxLayout() gb.setLayout(hbox1) vbox.addWidget(gb) gb.setTitle(_("Select your seed length:")) bg = QButtonGroup() for i, count in enumerate([12, 18, 24]): rb = QRadioButton(gb) rb.setText(_("%d words") % count) bg.addButton(rb) bg.setId(rb, i) hbox1.addWidget(rb) rb.setChecked(True) cb_pin = QCheckBox(_('Enable PIN protection')) cb_pin.setChecked(True) else: text = QTextEdit() text.setMaximumHeight(60) if method == TIM_MNEMONIC: msg = _("Enter your BIP39 mnemonic:") else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): from btn_electrum.keystore import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False vbox.addWidget(QLabel(msg)) vbox.addWidget(text) pin = QLineEdit() pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,9}'))) pin.setMaximumWidth(100) hbox_pin = QHBoxLayout() hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) hbox_pin.addWidget(pin) hbox_pin.addStretch(1) if method in [TIM_NEW, TIM_RECOVER]: vbox.addWidget(WWLabel(RECOMMEND_PIN)) vbox.addWidget(cb_pin) else: vbox.addLayout(hbox_pin) passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") cb_phrase = QCheckBox(_('Enable passphrases')) cb_phrase.setChecked(False) vbox.addWidget(passphrase_msg) vbox.addWidget(passphrase_warning) vbox.addWidget(cb_phrase) wizard.exec_layout(vbox, next_enabled=next_enabled) if method in [TIM_NEW, TIM_RECOVER]: item = bg.checkedId() pin = cb_pin.isChecked() else: item = ' '.join(str(clean_text(text)).split()) pin = str(pin.text()) return (item, name.text(), pin, cb_phrase.isChecked())
def __init__(self, main): super(GameCreateWidget, self).__init__() self.main_win = main self.setObjectName("GameCreateWidget") h_layout = QHBoxLayout() form_layout = QFormLayout() form_layout.setContentsMargins(20, 50, 20, 50) self.game_name_value = QLineEdit() form_layout.addRow("游戏名称:", self.game_name_value) self.game_desc_value = QTextEdit() form_layout.addRow("游戏简介:", self.game_desc_value) self.game_appid_value = QLineEdit() form_layout.addRow("游戏ID:", self.game_appid_value) self.game_appkey_value = QLineEdit() form_layout.addRow("客户端Key:", self.game_appkey_value) h_layout2 = QHBoxLayout() self.keystore_path = QLineEdit() select_key_btn = QPushButton("浏览") select_key_btn.setStyleSheet('QPushButton{border-radius: 0px;}') select_key_btn.clicked.connect(self.select_keystore) h_layout2.addWidget(self.keystore_path) h_layout2.addWidget(select_key_btn) form_layout.addRow("KeyStore:", h_layout2) self.keystore_pwd_value = QLineEdit() form_layout.addRow("KeyPass:"******"Alias:", self.keystore_alias_value) self.keystore_aliaspwd_value = QLineEdit() form_layout.addRow("AliasPass:"******"添加Icon") icon_add_btn.setFixedWidth(100) icon_add_btn.clicked.connect(self.add_icon) v_layout2.addWidget(icon_add_btn, alignment=Qt.AlignHCenter) v_layout2.addStretch(6) create_btn = QPushButton("创 建") create_btn.setFixedWidth(100) create_btn.clicked.connect(self.create) v_layout2.addWidget(create_btn, alignment=Qt.AlignRight | Qt.AlignBottom) v_layout2.addStretch(1) back_btn = QPushButton("返 回") back_btn.setFixedWidth(100) back_btn.clicked.connect(self.back) v_layout2.addWidget(back_btn, alignment=Qt.AlignRight | Qt.AlignBottom) h_layout.addLayout(v_layout2, 1) self.setLayout(h_layout) self.game = {} self.icon_path = None
def do_user_config(self, parent=None): ''' This method shows a configuration dialog for this plugin. It returns True if the user clicks OK, False otherwise. The changes are automatically applied. ''' from PyQt5.Qt import QDialog, QDialogButtonBox, QVBoxLayout, \ QLabel, Qt, QLineEdit from calibre.gui2 import gprefs prefname = 'plugin config dialog:' + self.type + ':' + self.name geom = gprefs.get(prefname, None) config_dialog = QDialog(parent) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) v = QVBoxLayout(config_dialog) def size_dialog(): if geom is None: config_dialog.resize(config_dialog.sizeHint()) else: config_dialog.restoreGeometry(geom) button_box.accepted.connect(config_dialog.accept) button_box.rejected.connect(config_dialog.reject) config_dialog.setWindowTitle(_('Customize') + ' ' + self.name) try: config_widget = self.config_widget() except NotImplementedError: config_widget = None if isinstance(config_widget, tuple): from calibre.gui2 import warning_dialog warning_dialog(parent, _('Cannot configure'), config_widget[0], det_msg=config_widget[1], show=True) return False if config_widget is not None: v.addWidget(config_widget) v.addWidget(button_box) size_dialog() config_dialog.exec_() if config_dialog.result() == QDialog.Accepted: if hasattr(config_widget, 'validate'): if config_widget.validate(): self.save_settings(config_widget) else: self.save_settings(config_widget) else: from calibre.customize.ui import plugin_customization, \ customize_plugin help_text = self.customization_help(gui=True) help_text = QLabel(help_text, config_dialog) help_text.setWordWrap(True) help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_text.setOpenExternalLinks(True) v.addWidget(help_text) sc = plugin_customization(self) if not sc: sc = '' sc = sc.strip() sc = QLineEdit(sc, config_dialog) v.addWidget(sc) v.addWidget(button_box) size_dialog() config_dialog.exec_() if config_dialog.result() == QDialog.Accepted: sc = unicode(sc.text()).strip() customize_plugin(self, sc) geom = bytearray(config_dialog.saveGeometry()) gprefs[prefname] = geom return config_dialog.result()
def clear(self): self.lineEdit().clear() EnComboBox.clear(self) def eventFilter(self, obj, e): try: c = self.lineEdit().mcompleter except AttributeError: return False etype = e.type() if self.eat_focus_out and self is obj and etype == e.FocusOut: if c.isVisible(): return True return EnComboBox.eventFilter(self, obj, e) if __name__ == '__main__': from PyQt5.Qt import QDialog, QVBoxLayout app = QApplication([]) d = QDialog() d.setLayout(QVBoxLayout()) le = EditWithComplete(d) d.layout().addWidget(le) items = [ 'one', 'otwo', 'othree', 'ooone', 'ootwo', 'oothree', 'a1', 'a2', u'Edgas', u'Èdgar', u'Édgaq', u'Edgar', u'Édgar' ] le.update_items_cache(items) le.show_initial_value('') d.exec_()
def setup_ui(self): self.l = l = QVBoxLayout(self) self._text = QPlainTextEdit(self) l.addWidget(self._text) l.addWidget(self.bb)
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)
class CheckLibraryDialog(QDialog): is_deletable = 1 is_fixable = 2 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_type(self.ext_ignores.text())) self.db.new_api.set_pref('check_library_ignore_names', unicode_type(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_type(self.name_ignores.text())), self.box_to_list(unicode_type(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.setData(1, Qt.UserRole, self.is_fixable) tl.setText(1, _('(fixable)')) tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(1, False) else: tl.setData(1, Qt.UserRole, self.is_deletable) tl.setData(2, Qt.UserRole, self.is_deletable) tl.setText(1, _('(deletable)')) tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(1, False) if attr == 'extra_covers': tl.setData(2, Qt.UserRole, self.is_deletable) tl.setText(2, _('(deletable)')) tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(2, False) self.top_level_items[attr] = tl for problem in list_: it = Item() if checkable: it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) it.setCheckState(2, False) it.setData(2, Qt.UserRole, self.is_deletable) else: it.setFlags(Qt.ItemIsEnabled) it.setText(0, problem[0]) it.setData(0, Qt.UserRole, problem[2]) it.setText(2, 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(3) 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): def set_delete_boxes(node, col, to_what): self.log.blockSignals(True) if col: node.setCheckState(col, to_what) for i in range(0, node.childCount()): node.child(i).setCheckState(2, to_what) self.log.blockSignals(False) def is_child_delete_checked(node): checked = False all_checked = True for i in range(0, node.childCount()): c = node.child(i).checkState(2) checked = checked or c == Qt.Checked all_checked = all_checked and c == Qt.Checked return (checked, all_checked) def any_child_delete_checked(): for parent in self.top_level_items.values(): (c, _) = is_child_delete_checked(parent) if c: return True return False def any_fix_checked(): for parent in self.top_level_items.values(): if (parent.data(1, Qt.UserRole) == self.is_fixable and parent.checkState(1) == Qt.Checked): return True return False if item in self.top_level_items.values(): if item.childCount() > 0: if item.data(1, Qt.UserRole) == self.is_fixable and column == 1: if item.data(2, Qt.UserRole) == self.is_deletable: set_delete_boxes(item, 2, False) else: set_delete_boxes(item, column, item.checkState(column)) if column == 2: self.log.blockSignals(True) item.setCheckState(1, False) self.log.blockSignals(False) else: item.setCheckState(column, Qt.Unchecked) else: for parent in self.top_level_items.values(): if parent.data(2, Qt.UserRole) == self.is_deletable: (child_chkd, all_chkd) = is_child_delete_checked(parent) if all_chkd and child_chkd: check_state = Qt.Checked elif child_chkd: check_state = Qt.PartiallyChecked else: check_state = Qt.Unchecked self.log.blockSignals(True) if parent.data(1, Qt.UserRole) == self.is_fixable: parent.setCheckState(2, check_state) else: parent.setCheckState(1, check_state) if child_chkd and parent.data( 1, Qt.UserRole) == self.is_fixable: parent.setCheckState(1, Qt.Unchecked) self.log.blockSignals(False) self.delete_button.setEnabled(any_child_delete_checked()) self.fix_button.setEnabled(any_fix_checked()) def mark_for_fix(self): for it in self.top_level_items.values(): if (it.flags() & Qt.ItemIsUserCheckable and it.data(1, Qt.UserRole) == self.is_fixable and it.childCount() > 0): it.setCheckState(1, Qt.Checked) def mark_for_delete(self): for it in self.all_items: if (it.flags() & Qt.ItemIsUserCheckable and it.data(2, Qt.UserRole) == self.is_deletable): it.setCheckState(2, 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(2) == Qt.Checked: try: p = os.path.join(self.db.library_path, unicode_type(it.text(2))) 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_type(it.text(2)))) 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 = {f.strip() for f in all.split(',')} if all else set() valid = self.db.formats(id, index_is_id=True, verify_formats=True) valid = {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 BrowserWindow(QMainWindow): class SavedWindow(object): def __init__(self, window=None): ''' @param: window BrowserWindow ''' self.windowState = QByteArray() self.windowGeometry = QByteArray() self.windowUiState = {} # QString -> QVariant self.virtualDesktop = -1 self.currentTab = -1 self.tabs = [] # WebTab.SavedTab if window: self.init(window) def init(self, window): if window.isFullScreen(): self.windowState = QByteArray() else: self.windowState = window.saveState() self.windowGeometry = window.saveGeometry() self.windowUiState = window._saveUiState() tabsCount = window.tabCount() for idx in range(tabsCount): # TabbedWebView webView = window.weView(idx) if not webView: continue webTab = webView.webTab() if not webTab: continue tab = WebTab.SavedTab(webTab) if not tab.isValid(): continue if webTab.isCurrentTab(): self.currentTab = len(self.tabs) self.tabs.append(tab) def isValid(self): for tab in self.tabs: if not tab.isValid(): return False return self.currentTab > -1 def clear(self): self.windowState.clear() self.windowGeometry.clear() self.virtualDesktop = -1 self.currentTab = -1 self.tabs.clear() def __init__(self, type_, startUrl=QUrl()): super().__init__(None) self._startUrl = startUrl self._homepage = QUrl() self._windowType = type_ self._startTab = None # WebTab self._startPage = None # WebPage self._mainLayout = None # QVBoxLayout self._mainSplitter = None # QSplitter self._tabWidget = None # TabWidget self._sideBar = None # QPointer<SideBar> self._sideBarManager = SideBarManager(self) self._statusBar = None self._navigationContainer = None # NavigationContainer self._navigationToolbar = None # NavigationBar self._bookmarksToolbar = None # BookmarksToolbar self._progressBar = None # ProgressBar self._ipLabel = None # QLabel self._superMenu = None # QMenu self._mainMenu = None # MainMenu self._tabModel = None # TabModel self._tabMruModel = None # TabMruModel self._sideBarWidth = 0 self._webViewWidth = 0 # Shortcuts self._useTabNumberShortcuts = False self._useSpeedDialNumberShortcuts = False self._useSingleKeyShortcuts = False # Remember visibility of menubar and statusbar after entering Fullscreen self._menuBarVisible = False self._statusBarVisible = False self._htmlFullScreenView = None # TabbedWebView self._hideNavigationTimer = None # QTimer self._deleteOnCloseWidgets = [] # QList<QPointer<QWidget>> self.setAttribute(Qt.WA_DeleteOnClose) self.setAttribute(Qt.WA_DontCreateNativeAncestors) self.setObjectName('mainwindow') self.setWindowTitle(const.APPNAME) self.setProperty('private', gVar.app.isPrivate()) self._setupUi() self._setupMenu() self._hideNavigationTimer = QTimer(self) self._hideNavigationTimer.setInterval(1000) self._hideNavigationTimer.setSingleShot(True) self._hideNavigationTimer.timeout.connect(self._hideNavigationSlot) gVar.app.settingsReloaded.connect(self._loadSettings) QTimer.singleShot(0, self._postLaunch) if gVar.app.isPrivate(): gVar.appTools.setWmClass( '%s Browser (Private Window)' % const.APPNAME, self) else: gVar.appTools.setWmClass('%s Browser' % const.APPNAME, self) def __del__(self): gVar.app.plugins().emitMainWindowDeleted(self) for widget in self._deleteOnCloseWidgets: widget.deleteLater() def setStartTab(self, tab): ''' @param: tab WebTab ''' self._startTab = tab def setStartPage(self, page): ''' @param: page WebPage ''' self._startPage = page def restoreWindow(self, window): ''' @param: window SavedWindow ''' self.restoreState(window.windowState) self.restoreGeometry(window.windowGeometry) self._restoreUiState(window.windowUiState) if not gVar.app.isTestModeEnabled(): self.show( ) # Window has to be visible before adding QWebEngineView's self._tabWidget.restoreState(window.tabs, window.currentTab) self._updateStartupFocus() def fullScreenNavigationVisible(self): return self._navigationContainer.isVisible() def showNavigationWithFullScreen(self): if self._htmlFullScreenView: return if self._hideNavigationTimer.isActive(): self._hideNavigationTimer.stop() self._navigationContainer.show() def hideNavigationWithFullScreen(self): if self._tabWidget.isCurrentTabFresh(): return if not self._hideNavigationTimer.isActive(): self._hideNavigationTimer.start() def currentTabChanged(self): view = self.weView() self._navigationToolbar.setCurrentView(view) if not view: return title = view.webTab().title(True) # allowEmpty if not title: self.setWindowTitle(const.APPNAME) else: self.setWindowTitle('%s - %s' % (title, const.APPNAME)) self._ipLabel.setText(view.getIp()) view.setFocus() self.updateLoadingActions() # Settings correct tab order (LocationBar -> WebSearchBar -> WebView) self.setTabOrder(self.locationBar(), self._navigationToolbar.webSearchBar()) self.setTabOrder(self._navigationToolbar.webSearchBar(), view) def updateLoadingActions(self): view = self.weView() if not view: return isLoading = view.isLoading() self._ipLabel.setVisible(not isLoading) self._progressBar.setVisible(isLoading) self.action('View/Stop').setEnabled(isLoading) self.action('View/Reload').setEnabled(not isLoading) if isLoading: self._progressBar.setValue(view.loadingProgress()) self._navigationToolbar.showStopButton() else: self._navigationToolbar.showReloadButton() def addBookmark(self, url, title): BookmarksTools.addBookmarkDilaog(self, url, title) def addDeleteOnCloseWidget(self, widget): ''' @param: widget QWidget ''' if widget not in self._deleteOnCloseWidgets: self._deleteOnCloseWidgets.append(widget) def createToolbarsMenu(self, menu): self.removeActions(menu.actions()) menu.clear() action = menu.addAction('&Menu Bar', self.toggleShowMenubar) action.setCheckable(True) action.setChecked(self.menuBar().isVisible()) action = menu.addAction('&Navigation Toolbar', self.toggleShowNavigationToolbar) action.setCheckable(True) action.setChecked(self._navigationToolbar.isVisible()) action = menu.addAction('&Bookmarks Toolbar', self.toggleShowBookmarksToolbar) action.setCheckable(True) action.setChecked(Settings().value( 'Browser-View-Settings/showBookmarksToolbar', True)) menu.addSeparator() action = menu.addAction('&Tabs on Top', self.toggleTabsOnTop) action.setCheckable(True) action.setChecked(gVar.appSettings.tabsOnTop) self.addActions(menu.actions()) def createSidebarsMenu(self, menu): self._sideBarManager.createMenu(menu) def createEncodingMenu(self, menu): isoCodecs = [] utfCodecs = [] windowsCodecs = [] isciiCodecs = [] ibmCodecs = [] otherCodecs = [] allCodecs = [] for mib in QTextCodec.availableMibs(): codecName = QTextCodec.codecForMib(mib).name() codecName = codecName.data().decode('utf8') if codecName in allCodecs: continue allCodecs.append(codecName) if codecName.startswith('ISO'): isoCodecs.append(codecName) elif codecName.startswith('UTF'): utfCodecs.append(codecName) elif codecName.startswith('windows'): windowsCodecs.append(codecName) elif codecName.startswith('Iscii'): isciiCodecs.append(codecName) elif codecName.startswith('IBM'): ibmCodecs.append(codecName) else: otherCodecs.append(codecName) if not menu.isEmpty(): menu.addSeperator() self._createEncodingSubMenu('ISO', isoCodecs, menu) self._createEncodingSubMenu('UTF', utfCodecs, menu) self._createEncodingSubMenu('Windows', windowsCodecs, menu) self._createEncodingSubMenu('Iscii', isciiCodecs, menu) self._createEncodingSubMenu('IBM', ibmCodecs, menu) self._createEncodingSubMenu('Other', otherCodecs, menu) def removeActions(self, actions): ''' @param: actions QList<QAction*> ''' for action in actions: self.removeAction(action) def addSideBar(self): ''' @return SideBar* ''' if self._sideBar: return self._sideBar self._sideBar = SideBar(self._sideBarManager, self) self._mainSplitter.insertWidget(0, self._sideBar) self._mainSplitter.setCollapsible(0, False) self._mainSplitter.setSizes([self._sideBarWidth, self._webViewWidth]) return self._sideBar def setSideBarNone(self): ''' @note: when sideBar is notified destroyed, we should clean python ref in window ''' self._sideBar = None def saveSideBarSettings(self): if self._sideBar: # That +1 is important here, without it, the sidebar width would # decrease by 1 pixel every close self._sideBarWidth = self._mainSplitter.sizes()[0] + 1 self._webViewWidth = self.width() - self._sideBarWidth Settings().setValue('Browser-View-Settings/SideBar', self._sideBarManager.activeSideBar()) def tabCount(self): return self._tabWidget.count() def weView(self, index=None): ''' @return TabbedWebView ''' if index is None: index = self._tabWidget.currentIndex() webTab = self._tabWidget.widget(index) if not webTab: return None return webTab.webView() def windowType(self): ''' @return const.BrowserWindowType ''' return self._windowType def locationBar(self): ''' @return LocationBar ''' return self._tabWidget.locationBars().currentWidget() def tabWidget(self): return self._tabWidget def bookmarksToolbar(self): ''' @return BookmarksToolbar ''' return self._bookmarksToolbar def statusBar(self): ''' @return StatusBar ''' return self._statusBar def navigationBar(self): ''' @return NavigationBar ''' return self._navigationToolbar def sideBarManager(self): ''' @return SideBarManager ''' return self._sideBarManager def ipLabel(self): ''' @return QLabel ''' return self._ipLabel def superMenu(self): ''' @return QMenu ''' return self._superMenu def homepageUrl(self): return self._homepage def action(self, name): ''' @return QAction ''' return self._mainMenu.action(name) def tabModel(self): ''' @return TabModel ''' return self._tabModel def tabMruModel(self): ''' @return TabMruModel ''' return self._tabMruModel # public Q_SIGNALS: startingCompleted = pyqtSignal() aboutToClose = pyqtSignal() # public Q_SLOTS: def addTab(self): self._tabWidget.addViewByUrl(QUrl(), const.NT_SelectedNewEmptyTab, True) self._tabWidget.setCurrentTabFresh(True) if self.isFullScreen(): self.showNavigationWithFullScreen() def goHome(self): self.loadAddress(self._homepage) def goHomeInNewTab(self): self._tabWidget.addViewByUrl(self._homepage, const.NT_SelectedTab) def goBack(self): self.weView().back() def goForward(self): self.weView().forward() def reload(self): self.weView().reload() def reloadBypassCache(self): self.weView().reloadBypassCache() def setWindowTitle(self, title): if gVar.app.isPrivate(): title = '%s (Private Browsing)' % title super().setWindowTitle(title) def showWebInspector(self): webView = self.weView() if webView and webView.webTab(): webView.webTab().showWebInspector() def toggleWebInspector(self): webView = self.weView() if webView and webView.webTab(): webView.webTab().toggleWebInspector() def showHistoryManager(self): gVar.app.browsingLibrary().showHistory(self) def toggleShowMenubar(self): self.setUpdatesEnabled(False) menuBar = self.menuBar() menuBar.setVisible(not menuBar.isVisible()) self._navigationToolbar.setSuperMenuVisible(not menuBar.isVisible()) self.setUpdatesEnabled(True) Settings().setValue('Browser-View-Settings/showMenuBar', menuBar.isVisible()) # Make sure we show Navigation Toolbar when Menu Bar is hidden if not self._navigationToolbar.isVisible() and not menuBar.isVisible(): self.toggleShowNavigationToolbar() def toggleShowStatusBar(self): self.setUpdatesEnabled(False) self._statusBar.setVisible(not self._statusBar.isVisible()) self.setUpdatesEnabled(True) Settings().setValue('Browser-View-Settings/showStatusBar', self._statusBar.isVisible()) def toggleShowBookmarksToolbar(self): self.setUpdatesEnabled(False) self._bookmarksToolbar.setVisible( not self._bookmarksToolbar.isVisible()) self.setUpdatesEnabled(True) Settings().setValue('Browser-View-Settings/showBookmarksToolbar', self._bookmarksToolbar.isVisible()) Settings().setValue('Browser-View-Settings/instantBookmarksToolbar', False) def toggleShowNavigationToolbar(self): self.setUpdatesEnabled(False) self._navigationToolbar.setVisible( not self._navigationToolbar.isVisible()) self.setUpdatesEnabled(True) Settings().setValue('Browser-View-Settings/showNavigationToolbar', self._navigationToolbar.isVisible()) # Make sure we show Navigation Toolbar when Menu Bar is hidden if not self._navigationToolbar.isVisible() and not self.menuBar( ).isVisible(): self.toggleShowMenubar() def toggleTabsOnTop(self, enable): gVar.appSettings.tabsOnTop = enable self._navigationContainer.toggleTabsOnTop(enable) def toggleFullScreen(self): if self._htmlFullScreenView: self.weView().triggerPageAction(QWebEnginePage.ExitFullScreen) return if self.isFullScreen(): self.setWindowState(self.windowState() & ~Qt.WindowFullScreen) else: self.setWindowState(self.windowState() | Qt.WindowFullScreen) def requestHtmlFullScreen(self, view, enable): ''' @param: view TabbedWebView @param: enable bool ''' if enable: self.setWindowState(self.windowState() | Qt.WindowFullScreen) else: self.setWindowState(self.windowState() & ~Qt.WindowFullScreen) if self._sideBar: self._sideBar.setHidden(enable) self._htmlFullScreenView = enable and view or None def loadActionUrl(self, obj=None): if not obj: obj = self.sender() action = obj if isinstance(action, QAction): self.loadAddress(action.data().toUrl()) def loadActionUrlInNewTab(self, obj=None): if not obj: obj = self.sender() action = obj if isinstance(action, QAction): self.loadAddress(action.data().toUrl(), const.NT_SelectedTabAtTheEnd) def bookmarkPage(self): view = self.weView() BookmarksTools.addBookmarkDialog(self, view.url(), view.title()) def bookmarkAllTabs(self): BookmarksTools.bookmarkAllTabsDialog(self, self._tabWidget) def loadAddress(self, url): webView = self.weView() if webView.webTab().isPinned(): index = self._tabWidget.addViewByUrl( url, gVar.appSettings.newTabPosition) self.weView(index).setFocus() else: webView.setFocus() webView.loadByReq(LoadRequest(url)) def showSource(self, view=None): if not view: view = self.weView() if not view: return view.showSource() # private Q_SLOTS: def _openLocation(self): if self.isFullScreen(): self.showNavigationWithFullScreen() self.locationBar().setFocus() self.locationBar().selectAll() def _openFile(self): fileTypes = ("%s(*.html *.htm *.shtml *.shtm *.xhtml);;" "%s(*.png *.jpg *.jpeg *.bmp *.gif *.svg *.tiff);;" "%s(*.txt);;" "%s(*.*)") fileTypes %= ("HTML files", "Image files", "Text files", "All files") filePath = gVar.appTools.getOpenFileName("MainWindow-openFile", self, "Open file...", QDir.homePath(), fileTypes) if filePath: self.loadAddress(QUrl.fromLocalFile(filePath)) def _closeWindow(self): if const.OS_MAC: self.close() return if gVar.app.windowCount() > 1: self.close() def _closeTab(self): # Don't close pinned tabs with keyboard shortcuts (Ctrl+w, Ctrl+F4) webView = self.weView() if webView and not webView.webTab().isPinned(): self._tabWidget.requestCloseTab() def _loadSettings(self): settings = Settings() # Url settings settings.beginGroup('Web-URL-Settings') self._homepage = settings.value('homepage', 'app:start', type=QUrl) settings.endGroup() # Browser Window settings settings.beginGroup('Browser-View-Settings') showStatusBar = settings.value('showStatusBar', False) showBookmarksToolbar = settings.value('showBookmarksToolbar', False) showNavigationToolbar = settings.value('showNavigationToolbar', True) showMenuBar = settings.value('showMenuBar', False) # Make sure both menubar and navigationbar are not hidden if not showNavigationToolbar: showMenuBar = True settings.setValue('showMenubar', True) settings.endGroup() settings.beginGroup('Shortcuts') self._useTabNumberShortcuts = settings.value('useTabNumberShortcuts', True) self._useSpeedDialNumberShortcuts = settings.value( 'useSpeedDialNumberShortcuts', True) self._useSingleKeyShortcuts = settings.value('useSingleKeyShortcuts', False) settings.endGroup() settings.beginGroup('Web-Browser-Settings') quitAction = self._mainMenu.action('Standard/Quit') if settings.value('closeAppWithCtrlQ', True): quitAction.setShortcut( gVar.appTools.actionShortcut(QKeySequence.Quit, QKeySequence('Ctrl+Q'))) else: quitAction.setShortcut(QKeySequence()) settings.endGroup() self._statusBarVisible = showStatusBar self.statusBar().setVisible(not self.isFullScreen() and showStatusBar) self._bookmarksToolbar.setVisible(showBookmarksToolbar) self._navigationToolbar.setVisible(showNavigationToolbar) if not const.OS_MACOS: self._menuBarVisible = showMenuBar self.menuBar().setVisible(not self.isFullScreen() and showMenuBar) showSuperMenu = self.isFullScreen() or not showMenuBar # TODO: debug code showSuperMenu = True self._navigationToolbar.setSuperMenuVisible(showSuperMenu) def _postLaunch(self): # noqa C901 self._loadSettings() addTab = True startUrl = QUrl() from .MainApplication import MainApplication afterLaunch = gVar.app.afterLaunch() if afterLaunch == MainApplication.OpenBlankPage: startUrl = QUrl() elif afterLaunch == MainApplication.OpenSpeedDial: startUrl = QUrl('app:speeddial') elif afterLaunch in (MainApplication.OpenHomePage, MainApplication.RestoreSession, MainApplication.SelectSession): startUrl = QUrl(self._homepage) if not gVar.app.isTestModeEnabled(): self.show() if self._windowType == const.BW_FirstAppWindow: if gVar.app.isStartingAfterCrash(): addTab = False startUrl.clear() self._tabWidget.addViewByUrl(QUrl('app:restore'), const.NT_CleanSelectedTabAtTheEnd) elif afterLaunch in (MainApplication.SelectSession, MainApplication.RestoreSession): addTab = self._tabWidget.count() <= 0 elif self._windowType in (const.BW_NewWindow, const.BW_MacFirstWindow): addTab = True elif self._windowType == const.BW_OtherRestoredWindow: addTab = False if not self._startUrl.isEmpty(): startUrl = QUrl(self._startUrl) addTab = True if self._startTab: addTab = False self._tabWidget.addViewByTab(self._startTab, const.NT_SelectedTab) if self._startPage: addTab = False self._tabWidget.addViewByUrl(QUrl()) self.weView().setPage(self._startPage) if addTab: self._tabWidget.addViewByUrl(startUrl, const.NT_CleanSelectedTabAtTheEnd) if not startUrl or startUrl == 'app:speeddial': self.locationBar().setFocus() # Someting went really wrong .. add one tab if self._tabWidget.count() <= 0: self._tabWidget.addViewByUrl(self._homepage, const.NT_SelectedTabAtTheEnd) gVar.app.plugins().emitMainWindowCreated(self) self.startingCompleted.emit() self.raise_() self.activateWindow() self._updateStartupFocus() def _webSearch(self): self._navigationToolbar.webSearchBar().setFocus() self._navigationToolbar.webSearchBar().selectAll() def _searchOnPage(self): webView = self.weView() if webView and webView.webTab(): searchText = webView.page().selectedText() if '\n' not in searchText: webView.webTab().showSearchToolBar(searchText) else: webView.webTab().showSearchToolBar() def _changeEncoding(self): action = self.sender() if action: encoding = action.data() gVar.app.webSettings().setDefaultTextEncoding(encoding) Settings().setValue('Web-Browser-Settings/DefaultEncoding', encoding) self.weView().reload() def _printPage(self): self.weView().printPage() def _saveSettings(self): if gVar.app.isPrivate(): return settings = Settings() settings.beginGroup('Browser-View-Settings') settings.setValue('WindowGeometry', self.saveGeometry()) state = self._saveUiState() for key, val in state.items(): settings.setValue(key, val) settings.endGroup() def _hideNavigationSlot(self): view = self.weView() mouseInView = view and view.underMouse() if self.isFullScreen() and mouseInView: self._navigationContainer.hide() # private # override def event(self, event): ''' @param: event QEvent ''' if event.type() == QEvent.WindowStateChange: e = event assert (isinstance(e, QWindowStateChangeEvent)) if not (e.oldState() & Qt.WindowFullScreen) and ( self.windowState() & Qt.WindowFullScreen): # Enter fullscreen self._statusBarVisible = self._statusBar.isVisible() if not const.OS_MACOS: self._menuBarVisible = self.menuBar().isVisible() self.menuBar().hide() self._statusBar.hide() self._navigationContainer.hide() self._navigationToolbar.enterFullScreen() # Show main menu button since menubar is hidden self._navigationToolbar.setSuperMenuVisible(True) elif (e.oldState() & Qt.WindowFullScreen ) and not (self.windowState() & Qt.WindowFullScreen): # Leave fullscreen self._statusBar.setVisible(self._statusBarVisible) if not const.OS_MACOS: self.menuBar().setVisible(self._menuBarVisible) self._navigationContainer.show() self._navigationToolbar.setSuperMenuVisible( not self._menuBarVisible) self._navigationToolbar.leaveFullScreen() self._htmlFullScreenView = None if self._hideNavigationTimer: self._hideNavigationTimer.stop() return super().event(event) # override def resizeEvent(self, event): ''' @param: event QResizeEvent ''' self._bookmarksToolbar.setMaximumWidth(self.width()) super().resizeEvent(event) # override def keyPressEvent(self, event): # noqa C901 ''' @param: event QKeyEvent ''' if gVar.app.plugins().processKeyPress(const.ON_BrowserWindow, self, event): return number = -1 # TabbedWebView view = self.weView() evtKey = event.key() if evtKey == Qt.Key_Back: if view: view.back() event.accept() elif evtKey == Qt.Key_Forward: if view: view.forward() event.accept() elif evtKey == Qt.Key_Stop: if view: view.stop() event.accept() elif evtKey in (Qt.Key_Reload, Qt.Key_Refresh): if view: view.reload() event.accept() elif evtKey == Qt.Key_HomePage: self.goHome() event.accept() elif evtKey == Qt.Key_Favorites: gVar.app.browsingLibrary().showBookmarks(self) event.accept() elif evtKey == Qt.Key_Search: self.searchOnPage() event.accept() elif evtKey in (Qt.Key_F6, Qt.Key_OpenUrl): self.openLocation() event.accept() elif evtKey == Qt.Key_History: self.showHistoryManager() event.accept() elif evtKey == Qt.Key_AddFavorite: self.bookmarkPage() event.accept() elif evtKey == Qt.Key_News: self.action("Tools/RssReader").trigger() event.accept() elif evtKey == Qt.Key_Tools: self.action("Standard/Preferences").trigger() event.accept() elif evtKey == Qt.Key_Tab: if event.modifiers() == Qt.ControlModifier: self._tabWidget.event(event) elif evtKey == Qt.Key_Backtab: if event.modifiers() == Qt.ControlModifier + Qt.ShiftModifier: self._tabWidget.event(event) elif evtKey == Qt.Key_PageDown: if event.modifiers() == Qt.ControlModifier: self._tabWidget.nextTab() event.accept() elif evtKey == Qt.Key_PageUp: if event.modifiers() == Qt.ControlModifier: self._tabWidget.previousTab() event.accept() elif evtKey == Qt.Key_Equal: if view and event.modifiers() == Qt.ControlModifier: view.zoomIn() event.accept() elif evtKey == Qt.Key_I: if event.modifiers() == Qt.ControlModifier: self.action("Tools/SiteInfo").trigger() event.accept() elif evtKey == Qt.Key_U: if event.modifiers() == Qt.ControlModifier: self.action("View/PageSource").trigger() event.accept() elif evtKey == Qt.Key_F: if event.modifiers() == Qt.ControlModifier: self.action("Edit/Find").trigger() event.accept() elif evtKey == Qt.Key_Slash: if self._useSingleKeyShortcuts: self.action("Edit/Find").trigger() event.accept() elif evtKey == Qt.Key_1: number = 1 elif evtKey == Qt.Key_2: number = 2 elif evtKey == Qt.Key_3: number = 3 elif evtKey == Qt.Key_4: number = 4 elif evtKey == Qt.Key_5: number = 5 elif evtKey == Qt.Key_6: number = 6 elif evtKey == Qt.Key_7: number = 7 elif evtKey == Qt.Key_8: number = 8 elif evtKey == Qt.Key_9: number = 9 if number != -1: modifiers = event.modifiers() if modifiers & Qt.AltModifier and self._useTabNumberShortcuts: if number == 9: number = self._tabWidget.count() self._tabWidget.setCurrentIndex(number - 1) event.accept() return if modifiers & Qt.ControlModifier and self._useSpeedDialNumberShortcuts: # QUrl url = gVar.app.plugins().speedDial().urlForShortcut(number - 1) if url.isValid(): self.loadAddress(url) event.accept() return if modifiers == Qt.NoModifier and self._useSingleKeyShortcuts: if number == 1: self._tabWidget.previousTab() if number == 2: self._tabWidget.nextTab() super().keyPressEvent(event) # override def keyReleaseEvent(self, event): ''' @param: event QKeyEvent ''' if gVar.app.plugins().processKeyRelease(const.ON_BrowserWindow, self, event): return evtKey = event.key() if evtKey == Qt.Key_F: if event.modifiers() == Qt.ControlModifier: self.action('Edit/Find').trigger() event.accept() super().keyReleaseEvent(event) # override def closeEvent(self, event): ''' @param: event QCloseEvent ''' if gVar.app.isClosing(): self._saveSettings() return settings = Settings() askOnClose = settings.value('Browser-Tabs-Settings/AskOnClosing', True) from .MainApplication import MainApplication if gVar.app.afterLaunch() in (MainApplication.SelectSession, MainApplication.RestoreSession ) and gVar.app.windowCount() == 1: askOnClose = False if askOnClose and self._tabWidget.normalTabsCount() > 1: dialog = CheckBoxDialog(QMessageBox.Yes | QMessageBox.No, self) dialog.setDefaultButton(QMessageBox.No) dialog.setText( "There are still %s open tabs and your session won't be stored.\n" % self._tabWidget.count() + "Are you sure you want to close this window?") dialog.setCheckBoxText("Don't ask again") dialog.setWindowTitle('There are still open tabs') dialog.setIcon(QMessageBox.Warning) if dialog.exec_() != QMessageBox.Yes: event.ignore() return if dialog.isChecked(): settings.setValue('Browser-Tabs-Settings/AskOnClosing', False) self.aboutToClose.emit() self._saveSettings() gVar.app.closedWindowsManager().saveWindow(self) if gVar.app.windowCount() == 1: gVar.app.quitApplication() event.accept() # == private == def _setupUi(self): settings = Settings() settings.beginGroup('Browser-View-Settings') windowGeometry = settings.value('WindowGeometry', b'') keys = [ ('LocationBarWidth', int), ('WebSearchBarWidth', int), ('SideBarWidth', int), ('WebViewWidth', int), ('SideBar', str), ] uiState = {} for key, typ in keys: if settings.contains(key): uiState[key] = typ(settings.value(key)) settings.endGroup() widget = QWidget(self) widget.setCursor(Qt.ArrowCursor) self.setCentralWidget(widget) self._mainLayout = QVBoxLayout(widget) self._mainLayout.setContentsMargins(0, 0, 0, 0) self._mainLayout.setSpacing(0) self._mainSplitter = QSplitter(self) self._mainSplitter.setObjectName('sidebar-splitter') self._tabWidget = TabWidget(self) self._superMenu = QMenu(self) self._navigationToolbar = NavigationBar(self) self._bookmarksToolbar = BookmarksToolbar(self) self._tabModel = TabModel(self, self) self._tabMruModel = TabMruModel(self, self) self._tabMruModel.setSourceModel(self._tabModel) self._navigationContainer = NavigationContainer(self) self._navigationContainer.addWidget(self._navigationToolbar) self._navigationContainer.addWidget(self._bookmarksToolbar) self._navigationContainer.setTabBar(self._tabWidget.tabBar()) self._mainSplitter.addWidget(self._tabWidget) self._mainSplitter.setCollapsible(0, False) self._mainLayout.addWidget(self._navigationContainer) self._mainLayout.addWidget(self._mainSplitter) self._statusBar = StatusBar(self) self._statusBar.setObjectName('mainwindow-statusbar') self._statusBar.setCursor(Qt.ArrowCursor) self.setStatusBar(self._statusBar) self._progressBar = ProgressBar(self._statusBar) self._ipLabel = QLabel(self) self._ipLabel.setObjectName('statusbar-ip-label') self._ipLabel.setToolTip('IP Address of current page') self._statusBar.addPermanentWidget(self._progressBar) self._statusBar.addPermanentWidget(self.ipLabel()) downloadsButton = DownloadsButton(self) self._statusBar.addButton(downloadsButton) self._navigationToolbar.addToolButton(downloadsButton) desktop = gVar.app.desktop() windowWidth = desktop.availableGeometry().width() / 1.3 windowHeight = desktop.availableGeometry().height() / 1.3 # Let the WM decides where to put new browser window if self._windowType not in (const.BW_FirstAppWindow, const.BW_MacFirstWindow) and \ gVar.app.getWindow(): if const.OS_WIN: # Windows WM places every new window in the middle of screen .. for some reason p = gVar.app.getWindow().geometry().topLeft() p.setX(p.x() + 30) p.setY(p.y() + 30) if not desktop.availableGeometry( gVar.app.getWindow()).contains(p): p.setX( desktop.availableGeometry(gVar.app.getWindow()).x() + 30) p.setY( desktop.availableGeometry(gVar.app.getWindow()).y() + 30) self.setGeometry(QRect(p, gVar.app.getWindow().size())) else: self.resize(gVar.app.getWindow().size()) elif not self.restoreGeometry(windowGeometry): if const.OS_WIN: self.setGeometry( QRect( desktop.availableGeometry(gVar.app.getWindow()).x() + 30, desktop.availableGeometry(gVar.app.getWindow()).y() + 30, windowWidth, windowHeight)) else: self.resize(windowWidth, windowHeight) self._restoreUiState(uiState) # Set some sane minimum width self.setMinimumWidth(300) def _setupMenu(self): if const.OS_MACOS: macMainMenu = None if not macMainMenu: macMainMenu = MainMenu(self, 0) macMainMenu.initMenuBar(QMenuBar(0)) gVar.app.activeWindowChanged.connect(macMainMenu.setWindow) else: macMainMenu.setWindow(self) else: self.setMenuBar(MenuBar(self)) self._mainMenu = MainMenu(self, self) self._mainMenu.initMenuBar(self.menuBar()) self._mainMenu.initSuperMenu(self._superMenu) # Setup other shortcuts reloadBypassCacheAction = QShortcut(QKeySequence('Ctrl+F5'), self) reloadBypassCacheAction2 = QShortcut(QKeySequence('Ctrl+Shift+R'), self) reloadBypassCacheAction.activated.connect(self.reloadBypassCache) reloadBypassCacheAction2.activated.connect(self.reloadBypassCache) closeTabAction = QShortcut(QKeySequence('Ctrl+W'), self) closeTabAction2 = QShortcut(QKeySequence('Ctrl+F4'), self) closeTabAction.activated.connect(self._closeTab) closeTabAction2.activated.connect(self._closeTab) reloadAction = QShortcut(QKeySequence('Ctrl+R'), self) reloadAction.activated.connect(self.reload) openLocationAction = QShortcut(QKeySequence('Alt+D'), self) openLocationAction.activated.connect(self._openLocation) inspectorAction = QShortcut(QKeySequence('F12'), self) inspectorAction.activated.connect(self.toggleWebInspector) restoreClosedWindow = QShortcut(QKeySequence('Ctrl+Shift+N'), self) restoreClosedWindow.activated.connect( gVar.app.closedWindowsManager().restoreClosedWindow) def _updateStartupFocus(self): def _updateStartupFocusCb(): # Scroll to current tab self.tabWidget().tabBar().ensureVisible() # Update focus page = self.weView().page() url = page.requestedUrl() if not self._startPage and not LocationBar.convertUrlToText(url): self.locationBar().setFocus() else: self.weView().setFocus() QTimer.singleShot(500, _updateStartupFocusCb) def _createEncodingAction(self, codecName, activeCodecName, menu): ''' @param: codecName QString @param: activeCodecName QString @param: menu QMenu ''' action = QAction(codecName, menu) action.setData(codecName) action.setCheckable(True) action.triggered.connect(self._changeEncoding) if activeCodecName.lower() == codecName.lower(): action.setChecked(True) return action def _createEncodingSubMenu(self, name, codecNames, menu): ''' @param: name QString @param: codecName QStringList @param: menu QMenu ''' if not codecNames: return codecNames.sort() subMenu = QMenu(name, menu) activeCodecName = gVar.app.webSettings().defaultTextEncoding() group = QActionGroup(subMenu) for codecName in codecNames: act = self._createEncodingAction(codecName, activeCodecName, subMenu) group.addAction(act) subMenu.addAction(act) menu.addMenu(subMenu) def _saveUiState(self): ''' @return: QHash<QStirng, QVariant> ''' self.saveSideBarSettings() state = {} state['LocationBarWidth'] = self._navigationToolbar.splitter().sizes( )[0] state['WebSearchBarWidth'] = self._navigationToolbar.splitter().sizes( )[1] state['SideBarWidth'] = self._sideBarWidth state['WebViewWidth'] = self._webViewWidth state['SideBar'] = self._sideBarManager.activeSideBar() return state def _restoreUiState(self, state): ''' @param: state QHash<QString, QVariant> ''' locationBarWidth = state.get('LocationBarWidth', 480) webSearchBarWidth = state.get('WebSearchBarWidth', 140) self._navigationToolbar.setSplitterSizes(locationBarWidth, webSearchBarWidth) self._sideBarWidth = state.get('SideBarWidth', 250) self._webViewWidth = state.get('WebViewWidth', 2000) if self._sideBar: self._mainSplitter.setSizes( [self._sideBarWidth, self._webViewWidth]) activeSideBar = state.get('SideBar') if not activeSideBar and self._sideBar: self._sideBar.close() else: self._sideBarManager.showSideBar(activeSideBar, False)
def setupUi(self, x): self.l = l = QVBoxLayout(self) self.la1 = la = QLabel( _("Values for the tweaks are shown below. Edit them to change the behavior of calibre." " Your changes will only take effect <b>after a restart</b> of calibre." )) l.addWidget(la), la.setWordWrap(True) self.splitter = s = QSplitter(self) s.setChildrenCollapsible(False) l.addWidget(s, 10) self.lv = lv = QWidget(self) lv.l = l2 = QVBoxLayout(lv) l2.setContentsMargins(0, 0, 0, 0) self.tweaks_view = tv = TweaksView(self) l2.addWidget(tv) self.plugin_tweaks_button = b = QPushButton(self) b.setToolTip( _("Edit tweaks for any custom plugins you have installed")) b.setText(_("&Plugin tweaks")) l2.addWidget(b) s.addWidget(lv) self.lv1 = lv = QWidget(self) s.addWidget(lv) lv.g = g = QGridLayout(lv) g.setContentsMargins(0, 0, 0, 0) self.search = sb = SearchBox2(self) sb.sizePolicy().setHorizontalStretch(10) sb.setSizeAdjustPolicy(sb.AdjustToMinimumContentsLength) sb.setMinimumContentsLength(10) g.addWidget(self.search, 0, 0, 1, 1) self.next_button = b = QPushButton(self) b.setIcon(QIcon(I("arrow-down.png"))) b.setText(_("&Next")) g.addWidget(self.next_button, 0, 1, 1, 1) self.previous_button = b = QPushButton(self) b.setIcon(QIcon(I("arrow-up.png"))) b.setText(_("&Previous")) g.addWidget(self.previous_button, 0, 2, 1, 1) self.hb = hb = QGroupBox(self) hb.setTitle(_("Help")) hb.l = l2 = QVBoxLayout(hb) self.help = h = QPlainTextEdit(self) l2.addWidget(h) h.setLineWrapMode(QPlainTextEdit.NoWrap) h.setReadOnly(True) g.addWidget(hb, 1, 0, 1, 3) self.eb = eb = QGroupBox(self) g.addWidget(eb, 2, 0, 1, 3) eb.setTitle(_("Edit tweak")) eb.g = ebg = QGridLayout(eb) self.edit_tweak = et = QPlainTextEdit(self) et.setMinimumWidth(400) et.setLineWrapMode(QPlainTextEdit.NoWrap) ebg.addWidget(et, 0, 0, 1, 2) self.restore_default_button = b = QPushButton(self) b.setToolTip(_("Restore this tweak to its default value")) b.setText(_("&Reset this tweak")) ebg.addWidget(b, 1, 0, 1, 1) self.apply_button = ab = QPushButton(self) ab.setToolTip(_("Apply any changes you made to this tweak")) ab.setText(_("&Apply changes to this tweak")) ebg.addWidget(ab, 1, 1, 1, 1)
class UserDefinedDevice(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self._layout = QVBoxLayout(self) self.setLayout(self._layout) self.log = QPlainTextEdit(self) self._layout.addWidget(self.log) self.log.setPlainText(_('Getting device information') + '...') self.copy = QPushButton(_('Copy to &clipboard')) self.copy.setDefault(True) self.setWindowTitle(_('User-defined device information')) self.setWindowIcon(QIcon(I('debug.png'))) self.copy.clicked.connect(self.copy_to_clipboard) self.ok = QPushButton('&OK') self.ok.setAutoDefault(False) self.ok.clicked.connect(self.accept) self.bbox = QDialogButtonBox(self) self.bbox.addButton(self.copy, QDialogButtonBox.ActionRole) self.bbox.addButton(self.ok, QDialogButtonBox.AcceptRole) self._layout.addWidget(self.bbox) self.resize(750, 500) self.bbox.setEnabled(False) QTimer.singleShot(1000, self.device_info) def device_info(self): try: from calibre.devices import device_info r = step_dialog( self.parent(), _('Device Detection'), _('Ensure your device is disconnected, then press OK')) if r: self.close() return before = device_info() r = step_dialog( self.parent(), _('Device Detection'), _('Ensure your device is connected, then press OK')) if r: self.close() return after = device_info() new_devices = after['device_set'] - before['device_set'] res = '' if len(new_devices) == 1: def fmtid(x): if isinstance(x, (int, long)): x = hex(x) if not x.startswith('0x'): x = '0x' + x return x for d in new_devices: res = _('USB Vendor ID (in hex)') + ': ' + \ fmtid(after['device_details'][d][0]) + '\n' res += _('USB Product ID (in hex)') + ': ' + \ fmtid(after['device_details'][d][1]) + '\n' res += _('USB Revision ID (in hex)') + ': ' + \ fmtid(after['device_details'][d][2]) + '\n' trailer = _( 'Copy these values to the clipboard, paste them into an ' 'editor, then enter them into the USER_DEVICE by ' 'customizing the device plugin in Preferences->Advanced->Plugins. ' 'Remember to also enter the folders where you want the books to ' 'be put. You must restart calibre for your changes ' 'to take effect.\n') self.log.setPlainText(res + '\n\n' + trailer) finally: self.bbox.setEnabled(True) def copy_to_clipboard(self): QApplication.clipboard().setText(self.log.toPlainText())
def __init__(self, parent): QWidget.__init__(self, parent) self.parent = parent self._layout = QVBoxLayout() self.setLayout(self._layout) self._layout.setContentsMargins(0, 0, 0, 0) # Set up the find box & button search_layout = QHBoxLayout() self._layout.addLayout(search_layout) self.item_search = HistoryLineEdit(parent) self.item_search.setMinimumContentsLength(5) self.item_search.setSizeAdjustPolicy( self.item_search.AdjustToMinimumContentsLengthWithIcon) try: self.item_search.lineEdit().setPlaceholderText( _('Find item in Tag browser')) except: pass # Using Qt < 4.7 self.item_search.setToolTip( _('Search for items. This is a "contains" search; items containing the\n' 'text anywhere in the name will be found. You can limit the search\n' 'to particular categories using syntax similar to search. For example,\n' 'tags:foo will find foo in any tag, but not in authors etc. Entering\n' '*foo will filter all categories at once, showing only those items\n' 'containing the text "foo"')) search_layout.addWidget(self.item_search) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser find box', _('Find item'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.set_focus_to_find_box) self.search_button = QToolButton() self.search_button.setText(_('Find')) self.search_button.setToolTip(_('Find the first/next matching item')) search_layout.addWidget(self.search_button) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser find button', _('Find button'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.search_button.click) self.expand_button = QToolButton() self.expand_button.setText('-') self.expand_button.setToolTip(_('Collapse all categories')) search_layout.addWidget(self.expand_button) search_layout.setStretch(0, 10) search_layout.setStretch(1, 1) search_layout.setStretch(2, 1) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.expand_button.clicked) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.initialize('tag_browser_search') self.item_search.lineEdit().returnPressed.connect(self.do_find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive) parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self.expand_button.clicked.connect(self.tags_view.collapseAll) self._layout.addWidget(parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.StyledPanel) l.setAutoFillBackground(True) l.setText( '<p><b>' + _('No More Matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10, 20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect( self.not_found_label_timer_event, type=Qt.QueuedConnection) parent.alter_tb = l = QPushButton(parent) l.setText(_('Alter Tag browser')) l.setIcon(QIcon(I('tags.png'))) l.m = QMenu() l.setMenu(l.m) self._layout.addWidget(l) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Alter Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate( (_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip(_('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate( (_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip( _('All of these category_managers are available by right-clicking ' 'on items in the tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item)
def __init__(self, parent, prefs): QFrame.__init__(self, parent) self.prefs = prefs self.setFrameShape(QFrame.StyledPanel) self.setMinimumWidth(250) self.stack = s = QStackedWidget(self) self.l = l = QVBoxLayout() self.setLayout(l) l.addWidget(s) self.root_pane = rp = QWidget(self) self.item_pane = ip = QWidget(self) self.current_item = None s.addWidget(rp) s.addWidget(ip) self.l1 = la = QLabel('<p>'+_( 'You can edit existing entries in the Table of Contents by clicking them' ' in the panel to the left.')+'<p>'+_( 'Entries with a green tick next to them point to a location that has ' 'been verified to exist. Entries with a red dot are broken and may need' ' to be fixed.')) la.setStyleSheet('QLabel { margin-bottom: 20px }') la.setWordWrap(True) l = rp.l = QVBoxLayout() rp.setLayout(l) l.addWidget(la) self.add_new_to_root_button = b = QPushButton(_('Create a &new entry')) b.clicked.connect(self.add_new_to_root) l.addWidget(b) l.addStretch() self.cfmhb = b = QPushButton(_('Generate ToC from &major headings')) b.clicked.connect(self.create_from_major_headings) b.setToolTip(textwrap.fill(_( 'Generate a Table of Contents from the major headings in the book.' ' This will work if the book identifies its headings using HTML' ' heading tags. Uses the <h1>, <h2> and <h3> tags.'))) l.addWidget(b) self.cfmab = b = QPushButton(_('Generate ToC from &all headings')) b.clicked.connect(self.create_from_all_headings) b.setToolTip(textwrap.fill(_( 'Generate a Table of Contents from all the headings in the book.' ' This will work if the book identifies its headings using HTML' ' heading tags. Uses the <h1-6> tags.'))) l.addWidget(b) self.lb = b = QPushButton(_('Generate ToC from &links')) b.clicked.connect(self.create_from_links) b.setToolTip(textwrap.fill(_( 'Generate a Table of Contents from all the links in the book.' ' Links that point to destinations that do not exist in the book are' ' ignored. Also multiple links with the same destination or the same' ' text are ignored.' ))) l.addWidget(b) self.cfb = b = QPushButton(_('Generate ToC from &files')) b.clicked.connect(self.create_from_files) b.setToolTip(textwrap.fill(_( 'Generate a Table of Contents from individual files in the book.' ' Each entry in the ToC will point to the start of the file, the' ' text of the entry will be the "first line" of text from the file.' ))) l.addWidget(b) self.xpb = b = QPushButton(_('Generate ToC from &XPath')) b.clicked.connect(self.create_from_user_xpath) b.setToolTip(textwrap.fill(_( 'Generate a Table of Contents from arbitrary XPath expressions.' ))) l.addWidget(b) self.fal = b = QPushButton(_('&Flatten the ToC')) b.clicked.connect(self.flatten_toc) b.setToolTip(textwrap.fill(_( 'Flatten the Table of Contents, putting all entries at the top level' ))) l.addWidget(b) l.addStretch() self.w1 = la = QLabel(_('<b>WARNING:</b> calibre only supports the ' 'creation of linear ToCs in AZW3 files. In a ' 'linear ToC every entry must point to a ' 'location after the previous entry. If you ' 'create a non-linear ToC it will be ' 'automatically re-arranged inside the AZW3 file.' )) la.setWordWrap(True) l.addWidget(la) l = ip.l = QGridLayout() ip.setLayout(l) la = ip.heading = QLabel('') l.addWidget(la, 0, 0, 1, 2) la.setWordWrap(True) la = ip.la = QLabel(_( 'You can move this entry around the Table of Contents by drag ' 'and drop or using the up and down buttons to the left')) la.setWordWrap(True) l.addWidget(la, 1, 0, 1, 2) # Item status ip.hl1 = hl = QFrame() hl.setFrameShape(hl.HLine) l.addWidget(hl, l.rowCount(), 0, 1, 2) self.icon_label = QLabel() self.status_label = QLabel() self.status_label.setWordWrap(True) l.addWidget(self.icon_label, l.rowCount(), 0) l.addWidget(self.status_label, l.rowCount()-1, 1) ip.hl2 = hl = QFrame() hl.setFrameShape(hl.HLine) l.addWidget(hl, l.rowCount(), 0, 1, 2) # Edit/remove item rs = l.rowCount() ip.b1 = b = QPushButton(QIcon(I('edit_input.png')), _('Change the &location this entry points to'), self) b.clicked.connect(self.edit_item) l.addWidget(b, l.rowCount()+1, 0, 1, 2) ip.b2 = b = QPushButton(QIcon(I('trash.png')), _('&Remove this entry'), self) l.addWidget(b, l.rowCount(), 0, 1, 2) b.clicked.connect(self.delete_item) ip.hl3 = hl = QFrame() hl.setFrameShape(hl.HLine) l.addWidget(hl, l.rowCount(), 0, 1, 2) l.setRowMinimumHeight(rs, 20) # Add new item rs = l.rowCount() ip.b3 = b = QPushButton(QIcon(I('plus.png')), _('New entry &inside this entry')) connect_lambda(b.clicked, self, lambda self: self.add_new('inside')) l.addWidget(b, l.rowCount()+1, 0, 1, 2) ip.b4 = b = QPushButton(QIcon(I('plus.png')), _('New entry &above this entry')) connect_lambda(b.clicked, self, lambda self: self.add_new('before')) l.addWidget(b, l.rowCount(), 0, 1, 2) ip.b5 = b = QPushButton(QIcon(I('plus.png')), _('New entry &below this entry')) connect_lambda(b.clicked, self, lambda self: self.add_new('after')) l.addWidget(b, l.rowCount(), 0, 1, 2) # Flatten entry ip.b3 = b = QPushButton(QIcon(I('heuristics.png')), _('&Flatten this entry')) b.clicked.connect(self.flatten_item) b.setToolTip(_('All children of this entry are brought to the same ' 'level as this entry.')) l.addWidget(b, l.rowCount()+1, 0, 1, 2) ip.hl4 = hl = QFrame() hl.setFrameShape(hl.HLine) l.addWidget(hl, l.rowCount(), 0, 1, 2) l.setRowMinimumHeight(rs, 20) # Return to welcome rs = l.rowCount() ip.b4 = b = QPushButton(QIcon(I('back.png')), _('&Return to welcome screen')) b.clicked.connect(self.go_to_root) b.setToolTip(_('Go back to the top level view')) l.addWidget(b, l.rowCount()+1, 0, 1, 2) l.setRowMinimumHeight(rs, 20) l.addWidget(QLabel(), l.rowCount(), 0, 1, 2) l.setColumnStretch(1, 10) l.setRowStretch(l.rowCount()-1, 10) self.w2 = la = QLabel(self.w1.text()) self.w2.setWordWrap(True) l.addWidget(la, l.rowCount(), 0, 1, 2)
def __init__(self, parent): QWidget.__init__(self, parent) l = QVBoxLayout(parent) l.addWidget(self) l.setContentsMargins(0, 0, 0, 0) l = QFormLayout(self) l.setContentsMargins(0, 0, 0, 0) l.setFieldGrowthPolicy(l.AllNonFixedFieldsGrow) self.choices = c = QComboBox() c.setMinimumContentsLength(30) for text, data in [ (_('Search for the author on Goodreads'), 'search-goodreads'), (_('Search for the author on Amazon'), 'search-amzn'), (_('Search for the author in your calibre library'), 'search-calibre'), (_('Search for the author on Wikipedia'), 'search-wikipedia'), (_('Search for the author on Google Books'), 'search-google'), (_('Search for the book on Goodreads'), 'search-goodreads-book'), (_('Search for the book on Amazon'), 'search-amzn-book'), (_('Search for the book on Google Books'), 'search-google-book'), (_('Use a custom search URL'), 'url'), ]: c.addItem(text, data) l.addRow(_('Clicking on &author names should:'), c) self.custom_url = u = QLineEdit(self) u.textChanged.connect(self.changed_signal) u.setPlaceholderText(_('Enter the URL')) c.currentIndexChanged.connect(self.current_changed) l.addRow(u) self.current_changed() c.currentIndexChanged.connect(self.changed_signal)
def setup_ui(self): self.vl = vl = QVBoxLayout(self) self.stack = l = QStackedLayout() self.pi = pi = ProgressIndicator(self, 256) vl.addLayout(l), vl.addWidget(self.bb) self.restore_defs_button = b = self.bb.addButton( _('Restore &default icons'), self.bb.ActionRole) b.clicked.connect(self.restore_defaults) b.setIcon(QIcon(I('view-refresh.png'))) self.c = c = QWidget(self) self.c.v = v = QVBoxLayout(self.c) v.addStretch(), v.addWidget(pi, 0, Qt.AlignCenter) self.wait_msg = m = QLabel(self) v.addWidget(m, 0, Qt.AlignCenter), v.addStretch() f = m.font() f.setBold(True), f.setPointSize(28), m.setFont(f) self.start_spinner() l.addWidget(c) self.w = w = QWidget(self) l.addWidget(w) w.l = l = QGridLayout(w) def add_row(x, y=None): if isinstance(x, type('')): x = QLabel(x) row = l.rowCount() if y is None: if isinstance(x, QLabel): x.setWordWrap(True) l.addWidget(x, row, 0, 1, 2) else: if isinstance(x, QLabel): x.setBuddy(y) l.addWidget(x, row, 0), l.addWidget(y, row, 1) add_row( _('Choose an icon theme below. You will need to restart' ' calibre to see the new icons.')) add_row( _('Current icon theme:') + '\xa0<b>' + (self.current_theme or 'None')) self.sort_by = sb = QComboBox(self) add_row(_('&Sort by:'), sb) sb.addItems([ _('Number of icons'), _('Popularity'), _('Name'), ]) sb.setEditable(False), sb.setCurrentIndex( gprefs.get('choose_icon_theme_sort_by', 1)) sb.currentIndexChanged[int].connect(self.re_sort) sb.currentIndexChanged[int].connect( lambda: gprefs.set('choose_icon_theme_sort_by', sb.currentIndex())) self.theme_list = tl = QListWidget(self) tl.setVerticalScrollMode(tl.ScrollPerPixel) self.delegate = Delegate(tl) tl.setItemDelegate(self.delegate) tl.itemDoubleClicked.connect(self.accept) add_row(tl) t = Thread(name='GetIconThemes', target=self.get_themes) t.daemon = True t.start()
def __initUI(self): # Onglet "Visualisation images" vbox = QVBoxLayout() # Ligne 1 : extraction trajec self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain); line1 = QHBoxLayout() line1.addStretch(1) line1.addWidget(self.btn_algo) line1.addWidget(self.btn_traj) line1.addWidget(self.target_color_label) line1.addWidget(self.picked_color) line1.addWidget(self.btn_clear) line1.addWidget(self.btn_exportCSV) line1.addStretch(1) # Ligne 2 : infos video + visu image line2 = QHBoxLayout() # boîte d'infos sur la vidéo infoVBox = QVBoxLayout() for _ in ImageDisplay.video_infos: label = QLabel(self) label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain); infoVBox.addWidget(label) self.videoLabels.append(label) infoVBox.addStretch() widget = QLabel("Conversion pixels -> mm", self) self.dicoScale['Pixels-mm'] = widget infoVBox.addWidget(widget) grid = QGridLayout() infoVBox.addLayout(grid) widget = QLabel("pixels ",self) self.dicoScale['pixels'] = widget grid.addWidget(widget,1,1) self.scale_pixel = QLineEdit(self) self.dicoScale['pixelsForMM'] = self.scale_pixel grid.addWidget(self.scale_pixel,1,2) widget = QLabel("millimètres ",self) self.dicoScale['millimeters'] = widget grid.addWidget(widget,2,1) self.scale_mm = QLineEdit(self) self.dicoScale['mmForPixels'] = self.scale_mm grid.addWidget(self.scale_mm,2,2) self.lbl_epsilon = QLabel("Epsilon ",self) grid.addWidget(self.lbl_epsilon,5,1) self.epsi_spin = QSpinBox(self) self.epsi_spin.setRange(1,50) self.epsi_spin.setSingleStep(1) self.epsi_spin.setValue(10) grid.addWidget(self.epsi_spin,5,2) infoVBox.addStretch() line2.addLayout(infoVBox) line2.addStretch(1) line2.addWidget(self.img_lbl) # le QLabel por afficher l'image line2.addStretch(1) # line 3 : navigation boutons self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.image_index.setText(" ") line3 = QHBoxLayout() line3.addStretch(1) line3.addWidget(self.btn_first) line3.addWidget(self.btn_prev) line3.addWidget(self.image_index) line3.addWidget(self.btn_next) line3.addWidget(self.btn_last) line3.addStretch(1) # line 4 : first , step, last image selection line4 = QHBoxLayout() line4.addStretch(1) line4.addWidget(self.images_firstRank) line4.addWidget(self.images_step) line4.addWidget(self.images_lastRank) line4.addStretch(1) vbox.addLayout(line1) vbox.addStretch(1) vbox.addLayout(line2) vbox.addStretch(1) vbox.addLayout(line3) vbox.addLayout(line4) self.setLayout(vbox) self.buttonsState() self.__buttonsConnect() self.__setVideoLabelVisible(False)
class DownloadDialog(QDialog): # {{{ def __init__(self, url, fname, parent): QDialog.__init__(self, parent) self.setWindowTitle(_('Download %s')%fname) self.l = QVBoxLayout(self) self.purl = urlparse(url) self.msg = QLabel(_('Downloading <b>%(fname)s</b> from %(url)s')%dict( fname=fname, url=self.purl.netloc)) self.msg.setWordWrap(True) self.l.addWidget(self.msg) self.pb = QProgressBar(self) self.pb.setMinimum(0) self.pb.setMaximum(0) self.l.addWidget(self.pb) self.bb = QDialogButtonBox(QDialogButtonBox.Cancel, Qt.Horizontal, self) self.l.addWidget(self.bb) self.bb.rejected.connect(self.reject) sz = self.sizeHint() self.resize(max(sz.width(), 400), sz.height()) fpath = PersistentTemporaryFile(os.path.splitext(fname)[1]) fpath.close() self.fpath = fpath.name self.worker = Worker(url, self.fpath, Queue()) self.rejected = False def reject(self): self.rejected = True QDialog.reject(self) def start_download(self): self.worker.start() QTimer.singleShot(50, self.update) self.exec_() if self.worker.err is not None: error_dialog(self.parent(), _('Download failed'), _('Failed to download from %(url)r with error: %(err)s')%dict( url=self.worker.url, err=self.worker.err), det_msg=self.worker.tb, show=True) def update(self): if self.rejected: return try: progress = self.worker.rq.get_nowait() except Empty: pass else: self.update_pb(progress) if not self.worker.is_alive(): return self.accept() QTimer.singleShot(50, self.update) def update_pb(self, progress): transferred, block_size, total = progress if total == -1: self.pb.setMaximum(0) self.pb.setMinimum(0) self.pb.setValue(0) else: so_far = transferred * block_size self.pb.setMaximum(max(total, so_far)) self.pb.setValue(so_far) @property def err(self): return self.worker.err
class TagBrowserWidget(QWidget): # {{{ def __init__(self, parent): QWidget.__init__(self, parent) self.parent = parent self._layout = QVBoxLayout() self.setLayout(self._layout) self._layout.setContentsMargins(0, 0, 0, 0) # Set up the find box & button search_layout = QHBoxLayout() self._layout.addLayout(search_layout) self.item_search = HistoryLineEdit(parent) self.item_search.setMinimumContentsLength(5) self.item_search.setSizeAdjustPolicy( self.item_search.AdjustToMinimumContentsLengthWithIcon) try: self.item_search.lineEdit().setPlaceholderText( _('Find item in Tag browser')) except: pass # Using Qt < 4.7 self.item_search.setToolTip( _('Search for items. This is a "contains" search; items containing the\n' 'text anywhere in the name will be found. You can limit the search\n' 'to particular categories using syntax similar to search. For example,\n' 'tags:foo will find foo in any tag, but not in authors etc. Entering\n' '*foo will filter all categories at once, showing only those items\n' 'containing the text "foo"')) search_layout.addWidget(self.item_search) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser find box', _('Find item'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.set_focus_to_find_box) self.search_button = QToolButton() self.search_button.setText(_('Find')) self.search_button.setToolTip(_('Find the first/next matching item')) search_layout.addWidget(self.search_button) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser find button', _('Find button'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.search_button.click) self.expand_button = QToolButton() self.expand_button.setText('-') self.expand_button.setToolTip(_('Collapse all categories')) search_layout.addWidget(self.expand_button) search_layout.setStretch(0, 10) search_layout.setStretch(1, 1) search_layout.setStretch(2, 1) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.expand_button.clicked) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.initialize('tag_browser_search') self.item_search.lineEdit().returnPressed.connect(self.do_find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) self.item_search.completer().setCaseSensitivity(Qt.CaseSensitive) parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self.expand_button.clicked.connect(self.tags_view.collapseAll) self._layout.addWidget(parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.StyledPanel) l.setAutoFillBackground(True) l.setText( '<p><b>' + _('No More Matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10, 20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect( self.not_found_label_timer_event, type=Qt.QueuedConnection) parent.alter_tb = l = QPushButton(parent) l.setText(_('Alter Tag browser')) l.setIcon(QIcon(I('tags.png'))) l.m = QMenu() l.setMenu(l.m) self._layout.addWidget(l) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Alter Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate( (_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip(_('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate( (_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip( _('All of these category_managers are available by right-clicking ' 'on items in the tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item) # self.leak_test_timer = QTimer(self) # self.leak_test_timer.timeout.connect(self.test_for_leak) # self.leak_test_timer.start(5000) def toggle_item(self): self.tags_view.toggle_current_index() def set_pane_is_visible(self, to_what): self.tags_view.set_pane_is_visible(to_what) def find_text_changed(self, str): self.current_find_position = None def set_focus_to_find_box(self): self.item_search.setFocus() self.item_search.lineEdit().selectAll() def do_find(self, str=None): self.current_find_position = None self.find() def find(self): model = self.tags_view.model() model.clear_boxed() txt = unicode(self.item_search.currentText()).strip() if txt.startswith('*'): model.set_categories_filter(txt[1:]) self.tags_view.recount() self.current_find_position = None return if model.get_categories_filter(): model.set_categories_filter(None) self.tags_view.recount() self.current_find_position = None if not txt: return self.item_search.lineEdit().blockSignals(True) self.search_button.setFocus(True) self.item_search.lineEdit().blockSignals(False) key = None colon = txt.rfind(':') if len(txt) > 2 else 0 if colon > 0: key = self.parent.library_view.model().db.\ field_metadata.search_term_to_field_key(txt[:colon]) txt = txt[colon + 1:] self.current_find_position = \ model.find_item_node(key, txt, self.current_find_position) if self.current_find_position: self.tags_view.show_item_at_path(self.current_find_position, box=True) elif self.item_search.text(): self.not_found_label.setVisible(True) if self.tags_view.verticalScrollBar().isVisible(): sbw = self.tags_view.verticalScrollBar().width() else: sbw = 0 width = self.width() - 8 - sbw height = self.not_found_label.heightForWidth(width) + 20 self.not_found_label.resize(width, height) self.not_found_label.move(4, 10) self.not_found_label_timer.start(2000) def not_found_label_timer_event(self): self.not_found_label.setVisible(False)
def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.NoFrame if gprefs['tag_browser_old_look'] else QFrame.StyledPanel) self._parent = parent self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) # Set up the find box & button self.tb_bar = tbb = TagBrowserBar(self) tbb.clear_find.connect(self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) # The tags view parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self._layout.insertWidget(0, 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) # The Alter Tag Browser button l = self.alter_tb self.collapse_all_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll()) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Configure Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate( (_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip(_('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate( (_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip( _('All of these category_managers are available by right-clicking ' 'on items in the Tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item)
def __init__(self, parent): QWidget.__init__(self, parent) l = QVBoxLayout() self.setLayout(l) l.addStretch(10) self.pi = ProgressIndicator(self, 128) l.addWidget(self.pi, alignment=Qt.AlignHCenter) self.dummy = QLabel('<h2>\xa0') l.addSpacing(10) l.addWidget(self.dummy, alignment=Qt.AlignHCenter) l.addStretch(10) self.text = _('Calculating differences, please wait...')