def __init__(self, filesystem_cache, show_files=True): QTabWidget.__init__(self) self.fs = filesystem_cache for storage in self.fs.entries: w = Storage(storage, show_files) self.addTab(w, w.name) w.doubleClicked.connect(self.selected) self.setCurrentIndex(0)
def __init__(self, parent=None): QStackedWidget.__init__(self, parent) self.welcome = w = QLabel('<p>'+_( 'Double click a file in the left panel to start editing' ' it.')) self.addWidget(w) w.setWordWrap(True) w.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter) self.container = c = QWidget(self) self.addWidget(c) l = c.l = QVBoxLayout(c) c.setLayout(l) l.setContentsMargins(0, 0, 0, 0) self.editor_tabs = t = QTabWidget(c) l.addWidget(t) t.setDocumentMode(True) t.setTabsClosable(True) t.setMovable(True) pal = self.palette() if pal.color(QPalette.ColorRole.WindowText).lightness() > 128: i = QImage(I('modified.png')) i.invertPixels() self.modified_icon = QIcon(QPixmap.fromImage(i)) else: self.modified_icon = QIcon(I('modified.png')) self.editor_tabs.currentChanged.connect(self.current_editor_changed) self.editor_tabs.tabCloseRequested.connect(self._close_requested) self.search_panel = SearchPanel(self) l.addWidget(self.search_panel) self.restore_state() self.editor_tabs.tabBar().installEventFilter(self)
def __init__(self, *args, **kw): ConfigWidgetBase.__init__(self, *args, **kw) self.l = l = QVBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) self.tabs_widget = t = QTabWidget(self) l.addWidget(t) self.main_tab = m = MainTab(self) t.addTab(m, _('&Main')) m.start_server.connect(self.start_server) m.stop_server.connect(self.stop_server) m.test_server.connect(self.test_server) m.show_logs.connect(self.view_server_logs) self.opt_autolaunch_server = m.opt_autolaunch_server self.users_tab = ua = Users(self) t.addTab(ua, _('&User accounts')) self.advanced_tab = a = AdvancedTab(self) sa = QScrollArea(self) sa.setWidget(a), sa.setWidgetResizable(True) t.addTab(sa, _('&Advanced')) self.custom_list_tab = clt = CustomList(self) sa = QScrollArea(self) sa.setWidget(clt), sa.setWidgetResizable(True) t.addTab(sa, _('Book &list template')) self.search_net_tab = SearchTheInternet(self) t.addTab(self.search_net_tab, _('&Search the internet')) for tab in self.tabs: if hasattr(tab, 'changed_signal'): tab.changed_signal.connect(self.changed_signal.emit)
def do_config(self): # Save values that need to be synced between the dialog and the # search widget. self.config['open_external'] = self.open_external.isChecked() # Create the config dialog. It's going to put two config widgets # into a QTabWidget for displaying all of the settings. d = QDialog(self) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) v = QVBoxLayout(d) button_box.accepted.connect(d.accept) button_box.rejected.connect(d.reject) d.setWindowTitle(_('Customize Get books search')) tab_widget = QTabWidget(d) v.addWidget(tab_widget) v.addWidget(button_box) chooser_config_widget = StoreChooserWidget() search_config_widget = StoreConfigWidget(self.config) tab_widget.addTab(chooser_config_widget, _('Choose s&tores')) tab_widget.addTab(search_config_widget, _('Configure s&earch')) # Restore dialog state. geometry = self.config.get('config_dialog_geometry', None) if geometry: QApplication.instance().safe_restore_geometry(d, geometry) else: d.resize(800, 600) tab_index = self.config.get('config_dialog_tab_index', 0) tab_index = min(tab_index, tab_widget.count() - 1) tab_widget.setCurrentIndex(tab_index) d.exec() # Save dialog state. self.config['config_dialog_geometry'] = bytearray(d.saveGeometry()) self.config['config_dialog_tab_index'] = tab_widget.currentIndex() search_config_widget.save_settings() self.config_changed() self.gui.load_store_plugins() self.setup_store_checks()
def __init__(self, dev, ignored_folders=None, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) self.la = la = QLabel('<p>' + _('<b>Scanned folders:</b>') + ' ' + _('You can select which folders calibre will ' 'scan when searching this device for books.')) la.setWordWrap(True) l.addWidget(la) self.tabs = QTabWidget(self) l.addWidget(self.tabs) self.widgets = [] for storage in dev.filesystem_cache.entries: self.dev = dev w = Storage(storage, item_func=self.create_item) del self.dev self.tabs.addTab(w, storage.name) self.widgets.append(w) w.itemChanged.connect(self.item_changed) self.la2 = la = QLabel( _('If you a select a previously unselected folder, any sub-folders' ' will not be visible until you restart calibre.')) l.addWidget(la) la.setWordWrap(True) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.sab = self.bb.addButton(_('Select &all'), QDialogButtonBox.ButtonRole.ActionRole) self.sab.clicked.connect(self.select_all) self.snb = self.bb.addButton(_('Select &none'), QDialogButtonBox.ButtonRole.ActionRole) self.snb.clicked.connect(self.select_none) l.addWidget(self.bb) self.setWindowTitle(_('Choose folders to scan')) self.setWindowIcon(QIcon(I('devices/tablet.png'))) self.resize(600, 500)
def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None): QWidget.__init__(self, parent) self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name self.toolbar1 = QToolBar(self) self.toolbar2 = QToolBar(self) self.toolbar3 = QToolBar(self) for i in range(1, 4): t = getattr(self, 'toolbar%d'%i) t.setIconSize(QSize(18, 18)) self.editor = EditorWidget(self) self.editor.data_changed.connect(self.data_changed) self.set_base_url = self.editor.set_base_url self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(QTabWidget.TabPosition.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('&Normal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_'+x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list'%x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(QToolButton.ToolButtonPopupMode.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.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.data_changed.connect(self.wyswyg_dirtied)
class Editor(QWidget): # {{{ toolbar_prefs_name = None data_changed = pyqtSignal() def __init__(self, parent=None, one_line_toolbar=False, toolbar_prefs_name=None): QWidget.__init__(self, parent) self.toolbar_prefs_name = toolbar_prefs_name or self.toolbar_prefs_name self.toolbar1 = QToolBar(self) self.toolbar2 = QToolBar(self) self.toolbar3 = QToolBar(self) for i in range(1, 4): t = getattr(self, 'toolbar%d'%i) t.setIconSize(QSize(18, 18)) self.editor = EditorWidget(self) self.editor.data_changed.connect(self.data_changed) self.set_base_url = self.editor.set_base_url self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(QTabWidget.TabPosition.South) self.wyswyg = QWidget(self.tabs) self.code_edit = QPlainTextEdit(self.tabs) self.source_dirty = False self.wyswyg_dirty = True self._layout = QVBoxLayout(self) self.wyswyg.layout = l = QVBoxLayout(self.wyswyg) self.setLayout(self._layout) l.setContentsMargins(0, 0, 0, 0) if one_line_toolbar: tb = QHBoxLayout() l.addLayout(tb) else: tb = l tb.addWidget(self.toolbar1) tb.addWidget(self.toolbar2) tb.addWidget(self.toolbar3) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('&Normal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() # toolbar1 {{{ self.toolbar1.addAction(self.editor.action_undo) self.toolbar1.addAction(self.editor.action_redo) self.toolbar1.addAction(self.editor.action_select_all) self.toolbar1.addAction(self.editor.action_remove_format) self.toolbar1.addAction(self.editor.action_clear) self.toolbar1.addSeparator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_'+x) self.toolbar1.addAction(ac) self.toolbar1.addSeparator() self.toolbar1.addAction(self.editor.action_background) # }}} # toolbar2 {{{ for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list'%x) self.toolbar2.addAction(ac) self.toolbar2.addSeparator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar2.addAction(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar2.addSeparator() self.toolbar2.addAction(self.editor.action_block_style) w = self.toolbar2.widgetForAction(self.editor.action_block_style) if hasattr(w, 'setPopupMode'): w.setPopupMode(QToolButton.ToolButtonPopupMode.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.addAction(ac) self.toolbar3.addSeparator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_'+x) self.toolbar3.addAction(ac) self.toolbar3.addSeparator() self.toolbar3.addAction(self.editor.action_color) # }}} self.code_edit.textChanged.connect(self.code_dirtied) self.editor.data_changed.connect(self.wyswyg_dirtied) def set_minimum_height_for_editor(self, val): self.editor.setMinimumHeight(val) @property def html(self): self.tabs.setCurrentIndex(0) return self.editor.html @html.setter def html(self, v): self.editor.html = v 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 = to_plain_text(self.code_edit) self.source_dirty = False @property def tab(self): return 'code' if self.tabs.currentWidget() is self.code_edit else 'wyswyg' @tab.setter def tab(self, val): self.tabs.setCurrentWidget(self.code_edit if val == 'code' else self.wyswyg) 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) @property def toolbars_visible(self): return self.toolbar1.isVisible() or self.toolbar2.isVisible() or self.toolbar3.isVisible() @toolbars_visible.setter def toolbars_visible(self, val): getattr(self, ('show' if val else 'hide') + '_toolbars')() def set_readonly(self, what): self.editor.set_readonly(what) def hide_tabs(self): self.tabs.tabBar().setVisible(False) def smarten_punctuation(self): from calibre.ebooks.conversion.preprocess import smarten_punctuation html = self.html newhtml = smarten_punctuation(html) if html != newhtml: self.html = newhtml
def addTab(self, page, *args): return QTabWidget.addTab(self, self.wrap_widget(page), *args)
def currentWidget(self): return QTabWidget.currentWidget(self).widget()
def __init__(self, parent=None): QTabWidget.__init__(self, parent)
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.toolbar = create_flow_toolbar( self, restrict_to_single_line=one_line_toolbar, icon_size=18) self.editor = EditorWidget(self) self.editor.data_changed.connect(self.data_changed) self.set_base_url = self.editor.set_base_url self.set_html = self.editor.set_html self.tabs = QTabWidget(self) self.tabs.setTabPosition(QTabWidget.TabPosition.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) l.addWidget(self.toolbar) l.addWidget(self.editor) self._layout.addWidget(self.tabs) self.tabs.addTab(self.wyswyg, _('&Normal view')) self.tabs.addTab(self.code_edit, _('&HTML source')) self.tabs.currentChanged[int].connect(self.change_tab) self.highlighter = Highlighter(self.code_edit.document()) self.layout().setContentsMargins(0, 0, 0, 0) if self.toolbar_prefs_name is not None: hidden = gprefs.get(self.toolbar_prefs_name) if hidden: self.hide_toolbars() self.toolbar.add_action(self.editor.action_undo) self.toolbar.add_action(self.editor.action_redo) self.toolbar.add_action(self.editor.action_select_all) self.toolbar.add_action(self.editor.action_remove_format) self.toolbar.add_action(self.editor.action_clear) self.toolbar.add_separator() for x in ('copy', 'cut', 'paste'): ac = getattr(self.editor, 'action_' + x) self.toolbar.add_action(ac) self.toolbar.add_separator() self.toolbar.add_action(self.editor.action_background) self.toolbar.add_action(self.editor.action_color) self.toolbar.add_separator() for x in ('', 'un'): ac = getattr(self.editor, 'action_%sordered_list' % x) self.toolbar.add_action(ac) self.toolbar.add_separator() for x in ('superscript', 'subscript', 'indent', 'outdent'): self.toolbar.add_action(getattr(self.editor, 'action_' + x)) if x in ('subscript', 'outdent'): self.toolbar.add_separator() self.toolbar.add_action( self.editor.action_block_style, popup_mode=QToolButton.ToolButtonPopupMode.InstantPopup) self.toolbar.add_action(self.editor.action_insert_link) self.toolbar.add_action(self.editor.action_insert_hr) self.toolbar.add_separator() for x in ('bold', 'italic', 'underline', 'strikethrough'): ac = getattr(self.editor, 'action_' + x) self.toolbar.add_action(ac) self.addAction(ac) self.toolbar.add_separator() for x in ('left', 'center', 'right', 'justified'): ac = getattr(self.editor, 'action_align_' + x) self.toolbar.add_action(ac) self.toolbar.add_separator() QTimer.singleShot(0, self.toolbar.updateGeometry) self.code_edit.textChanged.connect(self.code_dirtied) self.editor.data_changed.connect(self.wyswyg_dirtied)
def __init__(self, recipe_model, parent=None): QDialog.__init__(self, parent) self.commit_on_change = True self.previous_urn = None self.setWindowIcon(QIcon(I('scheduler.png'))) self.l = l = QGridLayout(self) # Left panel self.h = h = QHBoxLayout() l.addLayout(h, 0, 0, 1, 1) self.search = s = SearchBox2(self) self.search.initialize('scheduler_search_history') self.search.setMinimumContentsLength(15) self.go_button = b = QToolButton(self) b.setText(_("Go")) b.clicked.connect(self.search.do_search) h.addWidget(s), h.addWidget(b) self.recipes = RecipesView(self) l.addWidget(self.recipes, 1, 0, 2, 1) self.recipe_model = recipe_model self.recipe_model.do_refresh() self.recipes.setModel(self.recipe_model) self.recipes.setFocus(Qt.FocusReason.OtherFocusReason) self.recipes.item_activated.connect(self.download_clicked) self.setWindowTitle( _("Schedule news download [{} sources]").format( self.recipe_model.showing_count)) self.search.search.connect(self.recipe_model.search) self.recipe_model.searched.connect( self.search.search_done, type=Qt.ConnectionType.QueuedConnection) self.recipe_model.searched.connect(self.search_done) # Right Panel self.scroll_area_contents = sac = QWidget(self) self.l.addWidget(sac, 0, 1, 2, 1) sac.v = v = QVBoxLayout(sac) v.setContentsMargins(0, 0, 0, 0) self.detail_box = QTabWidget(self) self.detail_box.setVisible(False) self.detail_box.setCurrentIndex(0) v.addWidget(self.detail_box) v.addItem( QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)) # First Tab (scheduling) self.tab = QWidget() self.detail_box.addTab(self.tab, _("&Schedule")) self.tab.v = vt = QVBoxLayout(self.tab) vt.setContentsMargins(0, 0, 0, 0) self.blurb = la = QLabel('blurb') la.setWordWrap(True), la.setOpenExternalLinks(True) vt.addWidget(la) self.frame = f = QFrame(self.tab) vt.addWidget(f) f.setFrameShape(QFrame.Shape.StyledPanel) f.setFrameShadow(QFrame.Shadow.Raised) f.v = vf = QVBoxLayout(f) self.schedule = s = QCheckBox(_("&Schedule for download:"), f) self.schedule.stateChanged[int].connect(self.toggle_schedule_info) vf.addWidget(s) f.h = h = QHBoxLayout() vf.addLayout(h) self.days_of_week = QRadioButton(_("&Days of week"), f) self.days_of_month = QRadioButton(_("Da&ys of month"), f) self.every_x_days = QRadioButton(_("Every &x days"), f) self.days_of_week.setChecked(True) h.addWidget(self.days_of_week), h.addWidget( self.days_of_month), h.addWidget(self.every_x_days) self.schedule_stack = ss = QStackedWidget(f) self.schedule_widgets = [] for key in reversed(self.SCHEDULE_TYPES): self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self)) self.schedule_stack.insertWidget(0, self.schedule_widgets[0]) vf.addWidget(ss) self.last_downloaded = la = QLabel(f) la.setWordWrap(True) vf.addWidget(la) self.account = acc = QGroupBox(self.tab) acc.setTitle(_("&Account")) vt.addWidget(acc) acc.g = g = QGridLayout(acc) acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account) spw.stateChanged[int].connect(self.set_pw_echo_mode) g.addWidget(spw, 2, 0, 1, 2) self.rla = la = QLabel( _("For the scheduling to work, you must leave calibre running.")) vt.addWidget(la) for b, c in iteritems(self.SCHEDULE_TYPES): b = getattr(self, b) b.toggled.connect(self.schedule_type_selected) b.setToolTip(textwrap.dedent(c.HELP)) # Second tab (advanced settings) self.tab2 = t2 = QWidget() self.detail_box.addTab(self.tab2, _("&Advanced")) self.tab2.g = g = QGridLayout(t2) g.setContentsMargins(0, 0, 0, 0) self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2) g.addWidget(tt, 0, 0, 1, 2) t2.la = la = QLabel(_("&Extra tags:")) self.custom_tags = ct = QLineEdit(self) la.setBuddy(ct) g.addWidget(la), g.addWidget(ct, 1, 1) t2.la2 = la = QLabel(_("&Keep at most:")) la.setToolTip( _("Maximum number of copies (issues) of this recipe to keep. Set to 0 to keep all (disable)." )) self.keep_issues = ki = QSpinBox(t2) tt.toggled['bool'].connect(self.keep_issues.setEnabled) ki.setMaximum(100000), la.setBuddy(ki) ki.setToolTip( _("<p>When set, this option will cause calibre to keep, at most, the specified number of issues" " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the" " total is larger than this number.\n<p>Note that this feature only works if you have the" " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals" " older than a number of days, below, takes priority over this setting." )) ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues")) g.addWidget(la), g.addWidget(ki, 2, 1) si = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) g.addItem(si, 3, 1, 1, 1) # Bottom area self.hb = h = QHBoxLayout() self.l.addLayout(h, 2, 1, 1, 1) self.labt = la = QLabel(_("Delete downloaded &news older than:")) self.old_news = on = QSpinBox(self) on.setToolTip( _("<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n" "<p>You can also control the maximum number of issues of a specific periodical that are kept" " by clicking the Advanced tab for that periodical above.")) on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days")) on.setMaximum(1000), la.setBuddy(on) on.setValue(gconf['oldest_news']) h.addWidget(la), h.addWidget(on) self.download_all_button = b = QPushButton( QIcon(I('news.png')), _("Download &all scheduled"), self) b.setToolTip(_("Download all scheduled news sources at once")) b.clicked.connect(self.download_all_clicked) self.l.addWidget(b, 3, 0, 1, 1) self.bb = bb = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, self) bb.accepted.connect(self.accept), bb.rejected.connect(self.reject) self.download_button = b = bb.addButton( _('&Download now'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False) b.clicked.connect(self.download_clicked) self.l.addWidget(bb, 3, 1, 1, 1) geom = gprefs.get('scheduler_dialog_geometry') if geom is not None: QApplication.instance().safe_restore_geometry(self, geom)
class SchedulerDialog(QDialog): SCHEDULE_TYPES = OrderedDict([ ('days_of_week', DaysOfWeek), ('days_of_month', DaysOfMonth), ('every_x_days', EveryXDays), ]) download = pyqtSignal(object) def __init__(self, recipe_model, parent=None): QDialog.__init__(self, parent) self.commit_on_change = True self.previous_urn = None self.setWindowIcon(QIcon(I('scheduler.png'))) self.l = l = QGridLayout(self) # Left panel self.h = h = QHBoxLayout() l.addLayout(h, 0, 0, 1, 1) self.search = s = SearchBox2(self) self.search.initialize('scheduler_search_history') self.search.setMinimumContentsLength(15) self.go_button = b = QToolButton(self) b.setText(_("Go")) b.clicked.connect(self.search.do_search) h.addWidget(s), h.addWidget(b) self.recipes = RecipesView(self) l.addWidget(self.recipes, 1, 0, 2, 1) self.recipe_model = recipe_model self.recipe_model.do_refresh() self.recipes.setModel(self.recipe_model) self.recipes.setFocus(Qt.FocusReason.OtherFocusReason) self.recipes.item_activated.connect(self.download_clicked) self.setWindowTitle( _("Schedule news download [{} sources]").format( self.recipe_model.showing_count)) self.search.search.connect(self.recipe_model.search) self.recipe_model.searched.connect( self.search.search_done, type=Qt.ConnectionType.QueuedConnection) self.recipe_model.searched.connect(self.search_done) # Right Panel self.scroll_area_contents = sac = QWidget(self) self.l.addWidget(sac, 0, 1, 2, 1) sac.v = v = QVBoxLayout(sac) v.setContentsMargins(0, 0, 0, 0) self.detail_box = QTabWidget(self) self.detail_box.setVisible(False) self.detail_box.setCurrentIndex(0) v.addWidget(self.detail_box) v.addItem( QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)) # First Tab (scheduling) self.tab = QWidget() self.detail_box.addTab(self.tab, _("&Schedule")) self.tab.v = vt = QVBoxLayout(self.tab) vt.setContentsMargins(0, 0, 0, 0) self.blurb = la = QLabel('blurb') la.setWordWrap(True), la.setOpenExternalLinks(True) vt.addWidget(la) self.frame = f = QFrame(self.tab) vt.addWidget(f) f.setFrameShape(QFrame.Shape.StyledPanel) f.setFrameShadow(QFrame.Shadow.Raised) f.v = vf = QVBoxLayout(f) self.schedule = s = QCheckBox(_("&Schedule for download:"), f) self.schedule.stateChanged[int].connect(self.toggle_schedule_info) vf.addWidget(s) f.h = h = QHBoxLayout() vf.addLayout(h) self.days_of_week = QRadioButton(_("&Days of week"), f) self.days_of_month = QRadioButton(_("Da&ys of month"), f) self.every_x_days = QRadioButton(_("Every &x days"), f) self.days_of_week.setChecked(True) h.addWidget(self.days_of_week), h.addWidget( self.days_of_month), h.addWidget(self.every_x_days) self.schedule_stack = ss = QStackedWidget(f) self.schedule_widgets = [] for key in reversed(self.SCHEDULE_TYPES): self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self)) self.schedule_stack.insertWidget(0, self.schedule_widgets[0]) vf.addWidget(ss) self.last_downloaded = la = QLabel(f) la.setWordWrap(True) vf.addWidget(la) self.account = acc = QGroupBox(self.tab) acc.setTitle(_("&Account")) vt.addWidget(acc) acc.g = g = QGridLayout(acc) acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account) spw.stateChanged[int].connect(self.set_pw_echo_mode) g.addWidget(spw, 2, 0, 1, 2) self.rla = la = QLabel( _("For the scheduling to work, you must leave calibre running.")) vt.addWidget(la) for b, c in iteritems(self.SCHEDULE_TYPES): b = getattr(self, b) b.toggled.connect(self.schedule_type_selected) b.setToolTip(textwrap.dedent(c.HELP)) # Second tab (advanced settings) self.tab2 = t2 = QWidget() self.detail_box.addTab(self.tab2, _("&Advanced")) self.tab2.g = g = QGridLayout(t2) g.setContentsMargins(0, 0, 0, 0) self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2) g.addWidget(tt, 0, 0, 1, 2) t2.la = la = QLabel(_("&Extra tags:")) self.custom_tags = ct = QLineEdit(self) la.setBuddy(ct) g.addWidget(la), g.addWidget(ct, 1, 1) t2.la2 = la = QLabel(_("&Keep at most:")) la.setToolTip( _("Maximum number of copies (issues) of this recipe to keep. Set to 0 to keep all (disable)." )) self.keep_issues = ki = QSpinBox(t2) tt.toggled['bool'].connect(self.keep_issues.setEnabled) ki.setMaximum(100000), la.setBuddy(ki) ki.setToolTip( _("<p>When set, this option will cause calibre to keep, at most, the specified number of issues" " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the" " total is larger than this number.\n<p>Note that this feature only works if you have the" " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals" " older than a number of days, below, takes priority over this setting." )) ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues")) g.addWidget(la), g.addWidget(ki, 2, 1) si = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) g.addItem(si, 3, 1, 1, 1) # Bottom area self.hb = h = QHBoxLayout() self.l.addLayout(h, 2, 1, 1, 1) self.labt = la = QLabel(_("Delete downloaded &news older than:")) self.old_news = on = QSpinBox(self) on.setToolTip( _("<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n" "<p>You can also control the maximum number of issues of a specific periodical that are kept" " by clicking the Advanced tab for that periodical above.")) on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days")) on.setMaximum(1000), la.setBuddy(on) on.setValue(gconf['oldest_news']) h.addWidget(la), h.addWidget(on) self.download_all_button = b = QPushButton( QIcon(I('news.png')), _("Download &all scheduled"), self) b.setToolTip(_("Download all scheduled news sources at once")) b.clicked.connect(self.download_all_clicked) self.l.addWidget(b, 3, 0, 1, 1) self.bb = bb = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, self) bb.accepted.connect(self.accept), bb.rejected.connect(self.reject) self.download_button = b = bb.addButton( _('&Download now'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False) b.clicked.connect(self.download_clicked) self.l.addWidget(bb, 3, 1, 1, 1) geom = gprefs.get('scheduler_dialog_geometry') if geom is not None: QApplication.instance().safe_restore_geometry(self, geom) def sizeHint(self): return QSize(800, 600) def set_pw_echo_mode(self, state): self.password.setEchoMode( QLineEdit.EchoMode.Normal if state == Qt.CheckState.Checked else QLineEdit.EchoMode.Password) def schedule_type_selected(self, *args): for i, st in enumerate(self.SCHEDULE_TYPES): if getattr(self, st).isChecked(): self.schedule_stack.setCurrentIndex(i) break def keyPressEvent(self, ev): if ev.key() not in (Qt.Key.Key_Enter, Qt.Key.Key_Return): return QDialog.keyPressEvent(self, ev) def break_cycles(self): try: self.recipe_model.searched.disconnect(self.search_done) self.recipe_model.searched.disconnect(self.search.search_done) self.search.search.disconnect() self.download.disconnect() except: pass self.recipe_model = None def search_done(self, *args): if self.recipe_model.showing_count < 20: self.recipes.expandAll() def toggle_schedule_info(self, *args): enabled = self.schedule.isChecked() for x in self.SCHEDULE_TYPES: getattr(self, x).setEnabled(enabled) self.schedule_stack.setEnabled(enabled) self.last_downloaded.setVisible(enabled) def current_changed(self, current, previous): if self.previous_urn is not None: self.commit(urn=self.previous_urn) self.previous_urn = None urn = self.current_urn if urn is not None: self.initialize_detail_box(urn) self.recipes.scrollTo(current) def accept(self): if not self.commit(): return False self.save_geometry() return QDialog.accept(self) def reject(self): self.save_geometry() return QDialog.reject(self) def save_geometry(self): gprefs.set('scheduler_dialog_geometry', bytearray(self.saveGeometry())) def download_clicked(self, *args): self.commit() if self.commit() and self.current_urn: self.download.emit(self.current_urn) def download_all_clicked(self, *args): if self.commit() and self.commit(): self.download.emit(None) @property def current_urn(self): current = self.recipes.currentIndex() if current.isValid(): return getattr(current.internalPointer(), 'urn', None) def commit(self, urn=None): urn = self.current_urn if urn is None else urn if not self.detail_box.isVisible() or urn is None: return True if self.account.isVisible(): un, pw = map(unicode_type, (self.username.text(), self.password.text())) un, pw = un.strip(), pw.strip() if not un and not pw and self.schedule.isChecked(): if not getattr(self, 'subscription_optional', False): error_dialog( self, _('Need username and password'), _('You must provide a username and/or password to ' 'use this news source.'), show=True) return False if un or pw: self.recipe_model.set_account_info(urn, un, pw) else: self.recipe_model.clear_account_info(urn) if self.schedule.isChecked(): schedule_type, schedule = \ self.schedule_stack.currentWidget().schedule self.recipe_model.schedule_recipe(urn, schedule_type, schedule) else: self.recipe_model.un_schedule_recipe(urn) add_title_tag = self.add_title_tag.isChecked() keep_issues = '0' if self.keep_issues.isEnabled(): keep_issues = unicode_type(self.keep_issues.value()) custom_tags = unicode_type(self.custom_tags.text()).strip() custom_tags = [x.strip() for x in custom_tags.split(',')] self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags, keep_issues) return True def initialize_detail_box(self, urn): self.previous_urn = urn self.detail_box.setVisible(True) self.download_button.setVisible(True) self.detail_box.setCurrentIndex(0) recipe = self.recipe_model.recipe_from_urn(urn) try: schedule_info = self.recipe_model.schedule_info_from_urn(urn) except: # Happens if user does something stupid like unchecking all the # days of the week schedule_info = None account_info = self.recipe_model.account_info_from_urn(urn) customize_info = self.recipe_model.get_customize_info(urn) ns = recipe.get('needs_subscription', '') self.account.setVisible(ns in ('yes', 'optional')) self.subscription_optional = ns == 'optional' act = _('Account') act2 = _('(optional)') if self.subscription_optional else \ _('(required)') self.account.setTitle(act + ' ' + act2) un = pw = '' if account_info is not None: un, pw = account_info[:2] if not un: un = '' if not pw: pw = '' self.username.setText(un) self.password.setText(pw) self.show_password.setChecked(False) self.blurb.setText(''' <p> <b>%(title)s</b><br> %(cb)s %(author)s<br/> %(description)s </p> ''' % dict(title=recipe.get('title'), cb=_('Created by: '), author=recipe.get('author', _('Unknown')), description=recipe.get('description', ''))) self.download_button.setToolTip( _('Download %s now') % recipe.get('title')) scheduled = schedule_info is not None self.schedule.setChecked(scheduled) self.toggle_schedule_info() self.last_downloaded.setText(_('Last downloaded: never')) ld_text = _('never') if scheduled: typ, sch, last_downloaded = schedule_info d = utcnow() - last_downloaded def hm(x): return (x - x % 3600) // 3600, (x % 3600 - (x % 3600) % 60) // 60 hours, minutes = hm(d.seconds) tm = _('%(days)d days, %(hours)d hours' ' and %(mins)d minutes ago') % dict( days=d.days, hours=hours, mins=minutes) if d < timedelta(days=366): ld_text = tm else: typ, sch = 'day/time', (-1, 6, 0) sch_widget = { 'day/time': 0, 'days_of_week': 0, 'days_of_month': 1, 'interval': 2 }[typ] rb = getattr(self, list(self.SCHEDULE_TYPES)[sch_widget]) rb.setChecked(True) self.schedule_stack.setCurrentIndex(sch_widget) self.schedule_stack.currentWidget().initialize(typ, sch) add_title_tag, custom_tags, keep_issues = customize_info self.add_title_tag.setChecked(add_title_tag) self.custom_tags.setText(', '.join(custom_tags)) self.last_downloaded.setText(_('Last downloaded:') + ' ' + ld_text) try: keep_issues = int(keep_issues) except: keep_issues = 0 self.keep_issues.setValue(keep_issues) self.keep_issues.setEnabled(self.add_title_tag.isChecked())
class IgnoredFolders(QDialog): def __init__(self, dev, ignored_folders=None, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout() self.setLayout(l) self.la = la = QLabel('<p>' + _('<b>Scanned folders:</b>') + ' ' + _('You can select which folders calibre will ' 'scan when searching this device for books.')) la.setWordWrap(True) l.addWidget(la) self.tabs = QTabWidget(self) l.addWidget(self.tabs) self.widgets = [] for storage in dev.filesystem_cache.entries: self.dev = dev w = Storage(storage, item_func=self.create_item) del self.dev self.tabs.addTab(w, storage.name) self.widgets.append(w) w.itemChanged.connect(self.item_changed) self.la2 = la = QLabel( _('If you a select a previously unselected folder, any sub-folders' ' will not be visible until you restart calibre.')) l.addWidget(la) la.setWordWrap(True) self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.sab = self.bb.addButton(_('Select &all'), QDialogButtonBox.ButtonRole.ActionRole) self.sab.clicked.connect(self.select_all) self.snb = self.bb.addButton(_('Select &none'), QDialogButtonBox.ButtonRole.ActionRole) self.snb.clicked.connect(self.select_none) l.addWidget(self.bb) self.setWindowTitle(_('Choose folders to scan')) self.setWindowIcon(QIcon(I('devices/tablet.png'))) self.resize(600, 500) def item_changed(self, item, column): w = item.treeWidget() root = w.invisibleRootItem() w.itemChanged.disconnect(self.item_changed) try: if item.checkState(0) == Qt.CheckState.Checked: # Ensure that the parents of this item are checked p = item.parent() while p is not None and p is not root: p.setCheckState(0, Qt.CheckState.Checked) p = p.parent() # Set the state of all descendants to the same state as this item for child in self.iterchildren(item): child.setCheckState(0, item.checkState(0)) finally: w.itemChanged.connect(self.item_changed) def iterchildren(self, node): ' Iterate over all descendants of node ' for i in range(node.childCount()): child = node.child(i) yield child for gc in self.iterchildren(child): yield gc def create_item(self, f, parent): name = f.name ans = QTreeWidgetItem(parent, [name]) ans.setData(0, Qt.ItemDataRole.UserRole, '/'.join(f.full_path[1:])) ans.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled) ans.setCheckState( 0, Qt.CheckState.Unchecked if self.dev.is_folder_ignored( f.storage_id, f.full_path[1:]) else Qt.CheckState.Checked) ans.setData(0, Qt.ItemDataRole.DecorationRole, file_icon_provider().icon_from_ext('dir')) return ans def select_all(self): w = self.tabs.currentWidget() for i in range(w.invisibleRootItem().childCount()): c = w.invisibleRootItem().child(i) c.setCheckState(0, Qt.CheckState.Checked) def select_none(self): w = self.tabs.currentWidget() for i in range(w.invisibleRootItem().childCount()): c = w.invisibleRootItem().child(i) c.setCheckState(0, Qt.CheckState.Unchecked) @property def ignored_folders(self): ans = {} for w in self.widgets: folders = set() for node in self.iterchildren(w.invisibleRootItem()): if node.checkState(0) == Qt.CheckState.Checked: continue path = unicode_type( node.data(0, Qt.ItemDataRole.UserRole) or '') parent = path.rpartition('/')[0] if '/' not in path or icu_lower(parent) not in folders: folders.add(icu_lower(path)) ans[unicode_type(w.storage.storage_id)] = list(folders) return ans
def __init__(self, mi=None, prefs=None, parent=None, for_global_prefs=False): QWidget.__init__(self, parent) self.ignore_changed = False self.for_global_prefs = for_global_prefs self.l = l = QHBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) self.setLayout(l) self.settings_tabs = st = QTabWidget(self) l.addWidget(st) self.preview_label = la = Preview(self) l.addWidget(la) if prefs is None: prefs = cprefs self.original_prefs = prefs self.mi = mi or self.default_mi() self.colors_page = cp = QWidget(st) st.addTab(cp, _('&Colors')) cp.l = l = QGridLayout() cp.setLayout(l) if for_global_prefs: msg = _( 'When generating covers, a color scheme for the cover is chosen at random from the' ' color schemes below. You can prevent an individual scheme from being selected by' ' unchecking it. The preview on the right shows the currently selected color scheme.' ) else: msg = _( 'Choose a color scheme to be used for this generated cover.' ) + '<p>' + _( 'In normal cover generation, the color scheme is chosen at random from the list of color schemes below. You' ' can prevent an individual color scheme from being chosen by unchecking it here.' ) cp.la = la = QLabel('<p>' + msg) la.setWordWrap(True) l.addWidget(la, 0, 0, 1, -1) self.colors_list = cl = QListWidget(cp) l.addWidget(cl, 1, 0, 1, -1) self.colors_map = OrderedDict() self.ncs = ncs = QPushButton(QIcon(I('plus.png')), _('&New color scheme'), cp) ncs.clicked.connect(self.create_color_scheme) l.addWidget(ncs) self.ecs = ecs = QPushButton(QIcon(I('format-fill-color.png')), _('&Edit color scheme'), cp) ecs.clicked.connect(self.edit_color_scheme) l.addWidget(ecs, l.rowCount() - 1, 1) self.rcs = rcs = QPushButton(QIcon(I('minus.png')), _('&Remove color scheme'), cp) rcs.clicked.connect(self.remove_color_scheme) l.addWidget(rcs, l.rowCount() - 1, 2) self.styles_page = sp = QWidget(st) st.addTab(sp, _('&Styles')) sp.l = l = QVBoxLayout() sp.setLayout(l) if for_global_prefs: msg = _( 'When generating covers, a style for the cover is chosen at random from the' ' styles below. You can prevent an individual style from being selected by' ' unchecking it. The preview on the right shows the currently selected style.' ) else: msg = _( 'Choose a style to be used for this generated cover.' ) + '<p>' + _( 'In normal cover generation, the style is chosen at random from the list of styles below. You' ' can prevent an individual style from being chosen by unchecking it here.' ) sp.la = la = QLabel('<p>' + msg) la.setWordWrap(True) l.addWidget(la) self.styles_list = sl = QListWidget(sp) l.addWidget(sl) self.style_map = OrderedDict() self.font_page = fp = QWidget(st) st.addTab(fp, _('&Fonts and sizes')) fp.l = l = QFormLayout() fp.setLayout(l) fp.f = [] def add_hline(): f = QFrame() fp.f.append(f) f.setFrameShape(QFrame.Shape.HLine) l.addRow(f) for x, label, size_label in ( ('title', _('&Title font family:'), _('&Title font size:')), ('subtitle', _('&Subtitle font family:'), _('&Subtitle font size:')), ('footer', _('&Footer font family:'), _('&Footer font size:')), ): attr = '%s_font_family' % x ff = FontFamilyChooser(fp) setattr(self, attr, ff) l.addRow(label, ff) ff.family_changed.connect(self.emit_changed) attr = '%s_font_size' % x fs = QSpinBox(fp) setattr(self, attr, fs) fs.setMinimum(8), fs.setMaximum(200), fs.setSuffix(' px') fs.setValue(prefs[attr]) fs.valueChanged.connect(self.emit_changed) l.addRow(size_label, fs) add_hline() self.changed_timer = t = QTimer(self) t.setSingleShot(True), t.setInterval(500), t.timeout.connect( self.emit_changed) def create_sz(label): ans = QSpinBox(self) ans.setSuffix(' px'), ans.setMinimum(100), ans.setMaximum(10000) l.addRow(label, ans) ans.valueChanged.connect(self.changed_timer.start) return ans self.cover_width = create_sz(_('Cover &width:')) self.cover_height = create_sz(_('Cover &height:')) fp.cla = la = QLabel( _('Note that the preview to the side is of fixed aspect ratio, so changing the cover' ' width above will not have any effect. If you change the height, you should also change the width nevertheless' ' as it will be used in actual cover generation.')) la.setWordWrap(True) l.addRow(la) self.templates_page = tp = QWidget(st) st.addTab(tp, _('&Text')) tp.l = l = QVBoxLayout() tp.setLayout(l) tp.la = la = QLabel( _('The text on the generated cover is taken from the metadata of the book.' ' This is controlled via templates. You can use the <b>, <i> and <br> tags' ' in the templates for bold, italic and line breaks, respectively. The' ' default templates use the title, series and authors. You can change them to use' ' whatever metadata you like.')) la.setWordWrap(True), la.setTextFormat(Qt.TextFormat.PlainText) l.addWidget(la) def create_template_widget(title, which, button): attr = which + '_template' heading = QLabel('<h2>' + title) setattr(tp, attr + '_heading', heading) l.addWidget(heading) la = QLabel() setattr(self, attr, la) l.addWidget(la), la.setTextFormat( Qt.TextFormat.PlainText), la.setStyleSheet( 'QLabel {font-family: monospace}') la.setWordWrap(True) b = QPushButton(button) b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) connect_lambda(b.clicked, self, lambda self: self.change_template(which)) setattr(self, attr + '_button', b) l.addWidget(b) if which != 'footer': f = QFrame(tp) setattr(tp, attr + '_sep', f), f.setFrameShape(QFrame.Shape.HLine) l.addWidget(f) l.addSpacing(10) create_template_widget(_('The title template'), 'title', _('Change the &title template')) create_template_widget(_('The sub-title template'), 'subtitle', _('Change the &sub-title template')) create_template_widget(_('The footer template'), 'footer', _('Change the &footer template')) l.addStretch(2) self.apply_prefs(prefs) self.changed.connect(self.update_preview) self.styles_list.itemSelectionChanged.connect(self.update_preview) self.colors_list.itemSelectionChanged.connect(self.update_preview) self.update_preview()
def __init__(self, device_settings, all_formats, supports_subdirs, must_read_metadata, supports_use_author_sort, extra_customization_message, device, extra_customization_choices=None, parent=None): QTabWidget.__init__(self, parent) self._device = weakref.ref(device) self.device_settings = device_settings self.all_formats = set(all_formats) self.supports_subdirs = supports_subdirs self.must_read_metadata = must_read_metadata self.supports_use_author_sort = supports_use_author_sort self.extra_customization_message = extra_customization_message self.extra_customization_choices = extra_customization_choices try: self.device_name = device.get_gui_name() except TypeError: self.device_name = getattr(device, 'gui_name', None) or _('Device') if device.USER_CAN_ADD_NEW_FORMATS: self.all_formats = set(self.all_formats) | set(BOOK_EXTENSIONS) self.base = QWidget(self) # self.insertTab(0, self.base, _('Configure %s') % self.device.current_friendly_name) self.insertTab(0, self.base, _("File formats")) l = self.base.l = QGridLayout(self.base) self.base.setLayout(l) self.formats = FormatsConfig(self.all_formats, device_settings.format_map) if device.HIDE_FORMATS_CONFIG_BOX: self.formats.hide() self.opt_use_subdirs = create_checkbox( _("Use sub-directories"), _('Place files in sub-directories if the device supports them'), device_settings.use_subdirs) self.opt_read_metadata = create_checkbox( _("Read metadata from files on device"), _('Read metadata from files on device'), device_settings.read_metadata) self.template = TemplateConfig(device_settings.save_template) self.opt_use_author_sort = create_checkbox( _("Use author sort for author"), _("Use author sort for author"), device_settings.read_metadata) self.opt_use_author_sort.setObjectName("opt_use_author_sort") self.base.la = la = QLabel( _('Choose the formats to send to the %s') % self.device_name) la.setWordWrap(True) l.addWidget(la, 1, 0, 1, 1) l.addWidget(self.formats, 2, 0, 1, 1) l.addWidget(self.opt_read_metadata, 3, 0, 1, 1) l.addWidget(self.opt_use_subdirs, 4, 0, 1, 1) l.addWidget(self.opt_use_author_sort, 5, 0, 1, 1) l.addWidget(self.template, 6, 0, 1, 1) l.setRowStretch(2, 10) if device.HIDE_FORMATS_CONFIG_BOX: self.formats.hide() if supports_subdirs: self.opt_use_subdirs.setChecked(device_settings.use_subdirs) else: self.opt_use_subdirs.hide() if not must_read_metadata: self.opt_read_metadata.setChecked(device_settings.read_metadata) else: self.opt_read_metadata.hide() if supports_use_author_sort: self.opt_use_author_sort.setChecked( device_settings.use_author_sort) else: self.opt_use_author_sort.hide() self.extra_tab = ExtraCustomization(self.extra_customization_message, self.extra_customization_choices, self.device_settings) # Only display the extra customization tab if there are options on it. if self.extra_tab.has_extra_customizations: self.addTab(self.extra_tab, _('Extra customization')) self.setCurrentIndex(0)
def __init__(self, device, parent=None, highlight_ignored_folders=False): QTabWidget.__init__(self, parent) self._device = weakref.ref(device) cd = msg = None if device.current_friendly_name is not None: if device.current_serial_num is None: msg = '<p>' + (_('The <b>%s</b> device has no serial number, ' 'it cannot be configured')%device.current_friendly_name) else: cd = 'device-'+device.current_serial_num else: msg = '<p>' + _('<b>No MTP device connected.</b><p>' ' You can only configure the MTP device plugin when a device' ' is connected.') self.current_device_key = cd if msg: msg += '<p>' + _('If you want to un-ignore a previously' ' ignored MTP device, use the "Ignored devices" tab.') l = QLabel(msg) l.setWordWrap(True) l.setStyleSheet('QLabel { margin-left: 2em }') l.setMinimumWidth(500) l.setMinimumHeight(400) self.insertTab(0, l, _('Cannot configure')) else: self.base = QWidget(self) self.insertTab(0, self.base, _('Configure %s')%self.device.current_friendly_name) l = self.base.l = QGridLayout(self.base) self.base.setLayout(l) self.rules = r = FormatRules(self.device, self.get_pref('rules')) self.formats = FormatsConfig(set(BOOK_EXTENSIONS), self.get_pref('format_map')) self.send_to = SendToConfig(self.get_pref('send_to'), self.device) self.template = TemplateConfig(self.get_pref('send_template')) self.base.la = la = QLabel(_( 'Choose the formats to send to the %s')%self.device.current_friendly_name) la.setWordWrap(True) self.base.b = b = QPushButton(QIcon(I('list_remove.png')), _('&Ignore the %s in calibre')%device.current_friendly_name, self.base) b.clicked.connect(self.ignore_device) self.config_ign_folders_button = cif = QPushButton( QIcon(I('tb_folder.png')), _('Change scanned &folders')) cif.setStyleSheet( 'QPushButton { font-weight: bold; }') if highlight_ignored_folders: cif.setIconSize(QSize(64, 64)) self.show_debug_button = bd = QPushButton(QIcon(I('debug.png')), _('Show device information')) bd.clicked.connect(self.show_debug_info) cif.clicked.connect(self.change_ignored_folders) l.addWidget(b, 0, 0, 1, 2) l.addWidget(la, 1, 0, 1, 1) l.addWidget(self.formats, 2, 0, 5, 1) l.addWidget(cif, 2, 1, 1, 1) l.addWidget(self.template, 3, 1, 1, 1) l.addWidget(self.send_to, 4, 1, 1, 1) l.addWidget(self.show_debug_button, 5, 1, 1, 1) l.setRowStretch(6, 10) l.addWidget(r, 7, 0, 1, 2) l.setRowStretch(7, 100) self.igntab = IgnoredDevices(self.device.prefs['history'], self.device.prefs['blacklist']) self.addTab(self.igntab, _('Ignored devices')) self.current_ignored_folders = self.get_pref('ignored_folders') self.initial_ignored_folders = self.current_ignored_folders self.setCurrentIndex(1 if msg else 0)