def sizeHint(self): return QSize(self.min_size)
def __init__(self, parent): QWidget.__init__(self, parent) self._layout = l = QHBoxLayout() self.setLayout(self._layout) self._layout.setContentsMargins(0, 5, 0, 0) x = QToolButton(self) x.setText(_('Vi&rtual Library')) x.setIcon(QIcon(I('lt.png'))) x.setObjectName("virtual_library") x.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) l.addWidget(x) parent.virtual_library = x x = QLabel(self) x.setObjectName("search_count") l.addWidget(x) parent.search_count = x x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) parent.advanced_search_button = x = QToolButton(self) parent.advanced_search_toggle_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('advanced search toggle', _('Advanced search'), default_keys=(_("Shift+Ctrl+F"), ), action=ac) ac.triggered.connect(x.click) x.setIcon(QIcon(I('search.png'))) l.addWidget(x) x.setToolTip(_("Advanced search")) x = parent.search = SearchBox2(self) x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) x.setObjectName("search") x.setToolTip( _("<p>Search the list of books by title, author, publisher, " "tags, comments, etc.<br><br>Words separated by spaces are ANDed" )) x.setMinimumContentsLength(10) l.addWidget(x) self.search_button = QToolButton() self.search_button.setToolButtonStyle(Qt.ToolButtonTextOnly) self.search_button.setText(_('&Go!')) l.addWidget(self.search_button) self.search_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.search_button.clicked.connect(parent.do_search_button) self.search_button.setToolTip( _('Do Quick Search (you can also press the Enter key)')) x = parent.clear_button = QToolButton(self) x.setIcon(QIcon(I('clear_left.png'))) x.setObjectName("clear_button") l.addWidget(x) x.setToolTip(_("Reset Quick Search")) x = parent.highlight_only_button = QToolButton(self) x.setIcon(QIcon(I('arrow-down.png'))) l.addWidget(x) x = parent.saved_search = SavedSearchBox(self) x.setMaximumSize(QSize(150, 16777215)) x.setMinimumContentsLength(10) x.setObjectName("saved_search") l.addWidget(x) x = parent.copy_search_button = QToolButton(self) x.setIcon(QIcon(I("search_copy_saved.png"))) x.setObjectName("copy_search_button") l.addWidget(x) x.setToolTip(_("Copy current search text (instead of search name)")) x = parent.save_search_button = QToolButton(self) x.setIcon(QIcon(I("search_add_saved.png"))) x.setObjectName("save_search_button") l.addWidget(x)
def minimumSize(self): return QSize(self.min_size)
def setupUi(self): """ Setup the UI for the command toolbar. """ #ninad 070123 : It's important to set the Vertical size policy of the # cmd toolbar widget. otherwise the flyout QToolbar messes up the #layout (makes the command toolbar twice as big) #I have set the vertical policy as fixed. Works fine. There are some # MainWindow resizing problems for but those are not due to this #size policy AFAIK self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) layout_cmdtoolbar = QHBoxLayout(self) layout_cmdtoolbar.setMargin(2) layout_cmdtoolbar.setSpacing(2) #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: self.cmdToolbarControlArea = QWidget(self) else: self.cmdToolbarControlArea = QToolBar_WikiHelp(self) self.cmdToolbarControlArea.setAutoFillBackground(True) self.ctrlAreaPalette = self.getCmdMgrCtrlAreaPalette() self.cmdToolbarControlArea.setPalette(self.ctrlAreaPalette) self.cmdToolbarControlArea.setMinimumHeight(62) self.cmdToolbarControlArea.setMinimumWidth(380) self.cmdToolbarControlArea.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: layout_controlArea = QHBoxLayout(self.cmdToolbarControlArea) layout_controlArea.setMargin(0) layout_controlArea.setSpacing(0) self.cmdButtonGroup = QButtonGroup() btn_index = 0 for name in ('Build', 'Insert', 'Tools', 'Move', 'Simulation'): btn = QToolButton(self.cmdToolbarControlArea) btn.setObjectName(name) btn.setMinimumWidth(75) btn.setMaximumWidth(75) btn.setMinimumHeight(62) btn.setAutoRaise(True) btn.setCheckable(True) btn.setAutoExclusive(True) iconpath = "ui/actions/Command Toolbar/ControlArea/" + name + ".png" btn.setIcon(geticon(iconpath)) btn.setIconSize(QSize(22, 22)) btn.setText(name) btn.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btn.setPalette(self.ctrlAreaPalette) self.cmdButtonGroup.addButton(btn, btn_index) btn_index += 1 #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: layout_controlArea.addWidget(btn) else: self.cmdToolbarControlArea.layout().addWidget(btn) #following has issues. so not adding widget directly to the #toolbar. (instead adding it in its layout)-- ninad 070124 ##self.cmdToolbarControlArea.addWidget(btn) layout_cmdtoolbar.addWidget(self.cmdToolbarControlArea) #Flyout Toolbar in the command toolbar self.flyoutToolBar = FlyoutToolBar(self) layout_cmdtoolbar.addWidget(self.flyoutToolBar) #ninad 070116: Define a spacer item. It will have the exact geometry # as that of the flyout toolbar. it is added to the command toolbar # layout only when the Flyout Toolbar is hidden. It is required # to keep the 'Control Area' widget fixed in its place (otherwise, #after hiding the flyout toolbar, the layout adjusts the position of #remaining widget items) self.spacerItem = QSpacerItem(0, 0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.spacerItem.setGeometry = self.flyoutToolBar.geometry() for btn in self.cmdButtonGroup.buttons(): if str(btn.objectName()) == 'Build': btn.setMenu(self.win.buildStructuresMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Build Commands") whatsThisTextForCommandToolbarBuildButton(btn) if str(btn.objectName()) == 'Insert': btn.setMenu(self.win.insertMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Insert Commands") whatsThisTextForCommandToolbarInsertButton(btn) if str(btn.objectName()) == 'Tools': #fyi: cmd stands for 'command toolbar' - ninad070406 self.win.cmdToolsMenu = QtGui.QMenu(self.win) self.win.cmdToolsMenu.addAction(self.win.toolsExtrudeAction) self.win.cmdToolsMenu.addAction(self.win.toolsFuseChunksAction) self.win.cmdToolsMenu.addSeparator() self.win.cmdToolsMenu.addAction(self.win.modifyMergeAction) self.win.cmdToolsMenu.addAction(self.win.modifyMirrorAction) self.win.cmdToolsMenu.addAction(self.win.modifyInvertAction) self.win.cmdToolsMenu.addAction(self.win.modifyStretchAction) btn.setMenu(self.win.cmdToolsMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Tools") whatsThisTextForCommandToolbarToolsButton(btn) if str(btn.objectName()) == 'Move': self.win.moveMenu = QtGui.QMenu(self.win) self.win.moveMenu.addAction(self.win.toolsMoveMoleculeAction) self.win.moveMenu.addAction(self.win.rotateComponentsAction) self.win.moveMenu.addSeparator() self.win.moveMenu.addAction( self.win.modifyAlignCommonAxisAction) ##self.win.moveMenu.addAction(\ ## self.win.modifyCenterCommonAxisAction) btn.setMenu(self.win.moveMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Move Commands") whatsThisTextForCommandToolbarMoveButton(btn) if str(btn.objectName()) == 'Dimension': btn.setMenu(self.win.dimensionsMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Dimensioning Commands") if str(btn.objectName()) == 'Simulation': btn.setMenu(self.win.simulationMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Simulation Commands") whatsThisTextForCommandToolbarSimulationButton(btn) # Convert all "img" tags in the button's "What's This" text # into abs paths (from their original rel paths). # Partially fixes bug 2943. --mark 2008-12-07 # [bruce 081209 revised this -- removed mac = False] fix_QAction_whatsthis(btn) return
def __init__(self): self.vl_tabs = VLTabs(self) self.centralwidget.layout().addWidget(self.vl_tabs) if config['gui_layout'] == 'narrow': # narrow {{{ self.book_details = BookDetails(False, self) self.stack = Stack(self) self.bd_splitter = Splitter('book_details_splitter', _('Book Details'), I('book.png'), orientation=Qt.Vertical, parent=self, side_index=1, shortcut=_('Shift+Alt+D')) self.bd_splitter.addWidget(self.stack) self.bd_splitter.addWidget(self.book_details) self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False) self.centralwidget.layout().addWidget(self.bd_splitter) button_order = ('tb', 'bd', 'gv', 'cb') # }}} else: # wide {{{ self.bd_splitter = Splitter('book_details_splitter', _('Book Details'), I('book.png'), initial_side_size=200, orientation=Qt.Horizontal, parent=self, side_index=1, shortcut=_('Shift+Alt+D')) self.stack = Stack(self) self.bd_splitter.addWidget(self.stack) self.book_details = BookDetails(True, self) self.bd_splitter.addWidget(self.book_details) self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False) self.bd_splitter.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.centralwidget.layout().addWidget(self.bd_splitter) button_order = ('tb', 'cb', 'gv', 'bd') # }}} self.status_bar = StatusBar(self) stylename = unicode(self.style().objectName()) self.grid_view_button = GridViewButton(self) self.grid_view_button.toggled.connect(self.toggle_grid_view) for x in button_order: button = self.grid_view_button if x == 'gv' else getattr( self, x + '_splitter').button button.setIconSize(QSize(24, 24)) if isosx and stylename != u'Calibre': button.setStyleSheet(''' QToolButton { background: none; border:none; padding: 0px; } QToolButton:checked { background: rgba(0, 0, 0, 25%); } ''') self.status_bar.addPermanentWidget(button) self.status_bar.addPermanentWidget(self.jobs_button) self.setStatusBar(self.status_bar) self.status_bar.update_label.linkActivated.connect( self.update_link_clicked)
def set_icon(self, boton, ruta, text=''): icon = QIcon() archivo = pilasengine.utils.obtener_ruta_al_recurso(ruta) icon.addFile(archivo, QSize(), QIcon.Normal, QIcon.Off) boton.setIcon(icon) boton.setText(text)
def sizeHint(self): return QSize(800, 600)
self.model.commit(prefs) # }}} if __name__ == '__main__': app = QApplication([]) from calibre.library import db db = db() if True: d = RuleEditor(db.field_metadata) d.add_blank_condition() d.exec_() col, r = d.rule print ('Column to be colored:', col) print ('Template:') print (r.template) else: d = EditRules() d.resize(QSize(800, 600)) d.initialize(db.field_metadata, db.prefs, None) d.show() app.exec_() d.commit(db.prefs)
def sizeHint(self): return QSize(self.width_hint, self.height_hint)
def __init__( self, parentWidget, label='Color:', labelColumn=0, colorList=[], colorNames=[], color=white, setAsDefault=True, spanWidth=False, ): """ Appends a color chooser widget to <parentWidget>, a property manager group box. @param parentWidget: the parent group box containing this widget. @type parentWidget: PM_GroupBox @param label: The label that appears to the left or right of the color frame (and "Browse" button). If spanWidth is True, the label will be displayed on its own row directly above the lineedit (and button). To suppress the label, set I{label} to an empty string. @type label: str @param labelColumn: The column number of the label in the group box grid layout. The only valid values are 0 (left column) and 1 (right column). The default is 0 (left column). @type labelColumn: int @param colorList: List of colors. @type colorList: List where each item contains 3 floats (r, g, b) @param colorNames: List of color names. @type colorNames: List of strings @param color: The initial color. White is the default. If I{color} is not in I{colorList}, then the initial color will be set to the last color item (i.e. "Other color..."). @type color: tuple of 3 floats (r, g, b) @param setAsDefault: if True, will restore L{color} when the "Restore Defaults" button is clicked. @type setAsDefault: boolean @param spanWidth: if True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: boolean """ if len(colorNames) and len(colorList): assert len(colorNames) == len(colorList) self.colorNames = colorNames self.colorList = colorList self.colorDict = dict(zip(self.colorNames, self.colorList)) PM_ComboBox.__init__( self, parentWidget, label=label, labelColumn=labelColumn, choices=self.colorNames, index=0, # Gets (re)set by setColor() setAsDefault=setAsDefault, spanWidth=spanWidth) # Load QComboBox widget choices and set initial choice (index). idx = 0 for colorName in self.colorNames: pixmap = QPixmap(12, 12) qcolor = RGBf_to_QColor(self.colorDict[str(colorName)]) pixmap.fill(qcolor) self.setItemIcon(idx, QIcon(pixmap)) idx += 1 self.setIconSize(QSize(12, 12)) # Default is 16x16. self.setColor(color) # Sets current index. self.connect(self, SIGNAL("activated(QString)"), self._setColorFromName) return
def sizeHint(self): sz = QSize(self.frame_size[0], self.frame_size[1]) return sz
model = DummyImageList() cf.setImages(model) cf.setCurrentSlide(39000) w.setCentralWidget(cf) w.show() cf.setFocus(Qt.OtherFocusReason) sys.exit(app.exec_()) def main(args=sys.argv): return 0 if __name__ == '__main__': from PyQt4.QtGui import QApplication, QMainWindow app = QApplication([]) w = QMainWindow() cf = CoverFlow() cf.resize(int(available_width() / 1.5), available_height() - 60) w.resize(cf.size() + QSize(30, 20)) path = sys.argv[1] model = FileSystemImages(sys.argv[1]) cf.currentChanged[int].connect(model.currentChanged) cf.setImages(model) w.setCentralWidget(cf) w.show() cf.setFocus(Qt.OtherFocusReason) sys.exit(app.exec_())
def _initialize_controls(self): self.setWindowTitle(_('User plugins')) self.setWindowIcon(QIcon(I('plugins/plugin_updater.png'))) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'plugins/plugin_updater.png', _('User Plugins')) layout.addLayout(title_layout) header_layout = QHBoxLayout() layout.addLayout(header_layout) self.filter_combo = PluginFilterComboBox(self) self.filter_combo.setMinimumContentsLength(20) self.filter_combo.currentIndexChanged[int].connect( self._filter_combo_changed) header_layout.addWidget(QLabel( _('Filter list of plugins') + ':', self)) header_layout.addWidget(self.filter_combo) header_layout.addStretch(10) # filter plugins by name header_layout.addWidget(QLabel(_('Filter by name') + ':', self)) self.filter_by_name_lineedit = QLineEdit(self) self.filter_by_name_lineedit.setText("") self.filter_by_name_lineedit.textChanged.connect( self._filter_name_lineedit_changed) header_layout.addWidget(self.filter_by_name_lineedit) self.plugin_view = QTableView(self) self.plugin_view.horizontalHeader().setStretchLastSection(True) self.plugin_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.plugin_view.setSelectionMode(QAbstractItemView.SingleSelection) self.plugin_view.setAlternatingRowColors(True) self.plugin_view.setSortingEnabled(True) self.plugin_view.setIconSize(QSize(28, 28)) layout.addWidget(self.plugin_view) details_layout = QHBoxLayout() layout.addLayout(details_layout) forum_label = self.forum_label = QLabel('') forum_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) forum_label.linkActivated.connect(self._forum_label_activated) details_layout.addWidget(QLabel(_('Description') + ':', self), 0, Qt.AlignLeft) details_layout.addWidget(forum_label, 1, Qt.AlignRight) self.description = QLabel(self) self.description.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.description.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.description.setMinimumHeight(40) self.description.setWordWrap(True) layout.addWidget(self.description) self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.reject) self.finished.connect(self._finished) self.install_button = self.button_box.addButton( _('&Install'), QDialogButtonBox.AcceptRole) self.install_button.setToolTip(_('Install the selected plugin')) self.install_button.clicked.connect(self._install_clicked) self.install_button.setEnabled(False) self.configure_button = self.button_box.addButton( ' ' + _('&Customize plugin ') + ' ', QDialogButtonBox.ResetRole) self.configure_button.setToolTip( _('Customize the options for this plugin')) self.configure_button.clicked.connect(self._configure_clicked) self.configure_button.setEnabled(False) layout.addWidget(self.button_box)
class PluginUpdaterDialog(SizePersistedDialog): initial_extra_size = QSize(350, 100) forum_label_text = _('Plugin homepage') def __init__(self, gui, initial_filter=FILTER_UPDATE_AVAILABLE): SizePersistedDialog.__init__( self, gui, 'Plugin Updater plugin:plugin updater dialog') self.gui = gui self.forum_link = None self.zip_url = None self.model = None self.do_restart = False self._initialize_controls() self._create_context_menu() display_plugins = read_available_plugins() if display_plugins: self.model = DisplayPluginModel(display_plugins) self.proxy_model = DisplayPluginSortFilterModel(self) self.proxy_model.setSourceModel(self.model) self.plugin_view.setModel(self.proxy_model) self.plugin_view.resizeColumnsToContents() self.plugin_view.selectionModel().currentRowChanged.connect( self._plugin_current_changed) self.plugin_view.doubleClicked.connect(self.install_button.click) self.filter_combo.setCurrentIndex(initial_filter) self._select_and_focus_view() else: error_dialog(self.gui, _('Update Check Failed'), _('Unable to reach the plugin index page.'), det_msg=INDEX_URL, show=True) self.filter_combo.setEnabled(False) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() def _initialize_controls(self): self.setWindowTitle(_('User plugins')) self.setWindowIcon(QIcon(I('plugins/plugin_updater.png'))) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'plugins/plugin_updater.png', _('User Plugins')) layout.addLayout(title_layout) header_layout = QHBoxLayout() layout.addLayout(header_layout) self.filter_combo = PluginFilterComboBox(self) self.filter_combo.setMinimumContentsLength(20) self.filter_combo.currentIndexChanged[int].connect( self._filter_combo_changed) header_layout.addWidget(QLabel( _('Filter list of plugins') + ':', self)) header_layout.addWidget(self.filter_combo) header_layout.addStretch(10) # filter plugins by name header_layout.addWidget(QLabel(_('Filter by name') + ':', self)) self.filter_by_name_lineedit = QLineEdit(self) self.filter_by_name_lineedit.setText("") self.filter_by_name_lineedit.textChanged.connect( self._filter_name_lineedit_changed) header_layout.addWidget(self.filter_by_name_lineedit) self.plugin_view = QTableView(self) self.plugin_view.horizontalHeader().setStretchLastSection(True) self.plugin_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.plugin_view.setSelectionMode(QAbstractItemView.SingleSelection) self.plugin_view.setAlternatingRowColors(True) self.plugin_view.setSortingEnabled(True) self.plugin_view.setIconSize(QSize(28, 28)) layout.addWidget(self.plugin_view) details_layout = QHBoxLayout() layout.addLayout(details_layout) forum_label = self.forum_label = QLabel('') forum_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) forum_label.linkActivated.connect(self._forum_label_activated) details_layout.addWidget(QLabel(_('Description') + ':', self), 0, Qt.AlignLeft) details_layout.addWidget(forum_label, 1, Qt.AlignRight) self.description = QLabel(self) self.description.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.description.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.description.setMinimumHeight(40) self.description.setWordWrap(True) layout.addWidget(self.description) self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.reject) self.finished.connect(self._finished) self.install_button = self.button_box.addButton( _('&Install'), QDialogButtonBox.AcceptRole) self.install_button.setToolTip(_('Install the selected plugin')) self.install_button.clicked.connect(self._install_clicked) self.install_button.setEnabled(False) self.configure_button = self.button_box.addButton( ' ' + _('&Customize plugin ') + ' ', QDialogButtonBox.ResetRole) self.configure_button.setToolTip( _('Customize the options for this plugin')) self.configure_button.clicked.connect(self._configure_clicked) self.configure_button.setEnabled(False) layout.addWidget(self.button_box) def update_forum_label(self): txt = '' if self.forum_link: txt = '<a href="%s">%s</a>' % (self.forum_link, self.forum_label_text) self.forum_label.setText(txt) def _create_context_menu(self): self.plugin_view.setContextMenuPolicy(Qt.ActionsContextMenu) self.install_action = QAction( QIcon(I('plugins/plugin_upgrade_ok.png')), _('&Install'), self) self.install_action.setToolTip(_('Install the selected plugin')) self.install_action.triggered.connect(self._install_clicked) self.install_action.setEnabled(False) self.plugin_view.addAction(self.install_action) self.history_action = QAction(QIcon(I('chapters.png')), _('Version &History'), self) self.history_action.setToolTip( _('Show history of changes to this plugin')) self.history_action.triggered.connect(self._history_clicked) self.history_action.setEnabled(False) self.plugin_view.addAction(self.history_action) self.forum_action = QAction(QIcon(I('plugins/mobileread.png')), _('Plugin &Forum Thread'), self) self.forum_action.triggered.connect(self._forum_label_activated) self.forum_action.setEnabled(False) self.plugin_view.addAction(self.forum_action) sep1 = QAction(self) sep1.setSeparator(True) self.plugin_view.addAction(sep1) self.toggle_enabled_action = QAction(_('Enable/&Disable plugin'), self) self.toggle_enabled_action.setToolTip( _('Enable or disable this plugin')) self.toggle_enabled_action.triggered.connect( self._toggle_enabled_clicked) self.toggle_enabled_action.setEnabled(False) self.plugin_view.addAction(self.toggle_enabled_action) self.uninstall_action = QAction(_('&Remove plugin'), self) self.uninstall_action.setToolTip(_('Uninstall the selected plugin')) self.uninstall_action.triggered.connect(self._uninstall_clicked) self.uninstall_action.setEnabled(False) self.plugin_view.addAction(self.uninstall_action) sep2 = QAction(self) sep2.setSeparator(True) self.plugin_view.addAction(sep2) self.donate_enabled_action = QAction(QIcon(I('donate.png')), _('Donate to developer'), self) self.donate_enabled_action.setToolTip( _('Donate to the developer of this plugin')) self.donate_enabled_action.triggered.connect(self._donate_clicked) self.donate_enabled_action.setEnabled(False) self.plugin_view.addAction(self.donate_enabled_action) sep3 = QAction(self) sep3.setSeparator(True) self.plugin_view.addAction(sep3) self.configure_action = QAction(QIcon(I('config.png')), _('&Customize plugin'), self) self.configure_action.setToolTip( _('Customize the options for this plugin')) self.configure_action.triggered.connect(self._configure_clicked) self.configure_action.setEnabled(False) self.plugin_view.addAction(self.configure_action) def _finished(self, *args): if self.model: update_plugins = filter(filter_upgradeable_plugins, self.model.display_plugins) self.gui.recalc_update_label(len(update_plugins)) def _plugin_current_changed(self, current, previous): if current.isValid(): actual_idx = self.proxy_model.mapToSource(current) display_plugin = self.model.display_plugins[actual_idx.row()] self.description.setText(display_plugin.description) self.forum_link = display_plugin.forum_link self.zip_url = display_plugin.zip_url self.forum_action.setEnabled(bool(self.forum_link)) self.install_button.setEnabled( display_plugin.is_valid_to_install()) self.install_action.setEnabled(self.install_button.isEnabled()) self.uninstall_action.setEnabled(display_plugin.is_installed()) self.history_action.setEnabled(display_plugin.has_changelog) self.configure_button.setEnabled(display_plugin.is_installed()) self.configure_action.setEnabled(self.configure_button.isEnabled()) self.toggle_enabled_action.setEnabled( display_plugin.is_installed()) self.donate_enabled_action.setEnabled( bool(display_plugin.donation_link)) else: self.description.setText('') self.forum_link = None self.zip_url = None self.forum_action.setEnabled(False) self.install_button.setEnabled(False) self.install_action.setEnabled(False) self.uninstall_action.setEnabled(False) self.history_action.setEnabled(False) self.configure_button.setEnabled(False) self.configure_action.setEnabled(False) self.toggle_enabled_action.setEnabled(False) self.donate_enabled_action.setEnabled(False) self.update_forum_label() def _donate_clicked(self): plugin = self._selected_display_plugin() if plugin and plugin.donation_link: open_url(QUrl(plugin.donation_link)) def _select_and_focus_view(self, change_selection=True): if change_selection and self.plugin_view.model().rowCount() > 0: self.plugin_view.selectRow(0) else: idx = self.plugin_view.selectionModel().currentIndex() self._plugin_current_changed(idx, 0) self.plugin_view.setFocus() def _filter_combo_changed(self, idx): self.filter_by_name_lineedit.setText( "" ) # clear the name filter text when a different group was selected self.proxy_model.set_filter_criteria(idx) if idx == FILTER_NOT_INSTALLED: self.plugin_view.sortByColumn(5, Qt.DescendingOrder) else: self.plugin_view.sortByColumn(0, Qt.AscendingOrder) self._select_and_focus_view() def _filter_name_lineedit_changed(self, text): self.proxy_model.set_filter_text( text) # set the filter text for filterAcceptsRow def _forum_label_activated(self): if self.forum_link: open_url(QUrl(self.forum_link)) def _selected_display_plugin(self): idx = self.plugin_view.selectionModel().currentIndex() actual_idx = self.proxy_model.mapToSource(idx) return self.model.display_plugins[actual_idx.row()] def _uninstall_plugin(self, name_to_remove): if DEBUG: prints('Removing plugin: ', name_to_remove) remove_plugin(name_to_remove) # Make sure that any other plugins that required this plugin # to be uninstalled first have the requirement removed for display_plugin in self.model.display_plugins: # Make sure we update the status and display of the # plugin we just uninstalled if name_to_remove in display_plugin.uninstall_plugins: if DEBUG: prints('Removing uninstall dependency for: ', display_plugin.name) display_plugin.uninstall_plugins.remove(name_to_remove) if display_plugin.name == name_to_remove: if DEBUG: prints('Resetting plugin to uninstalled status: ', display_plugin.name) display_plugin.installed_version = None display_plugin.plugin = None display_plugin.uninstall_plugins = [] if self.proxy_model.filter_criteria not in [ FILTER_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.refresh_plugin(display_plugin) def _uninstall_clicked(self): display_plugin = self._selected_display_plugin() if not question_dialog( self, _('Are you sure?'), '<p>' + _('Are you sure you want to uninstall the <b>%s</b> plugin?') % display_plugin.name, show_copy_button=False): return self._uninstall_plugin(display_plugin.name) if self.proxy_model.filter_criteria in [ FILTER_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.reset() self._select_and_focus_view() else: self._select_and_focus_view(change_selection=False) def _install_clicked(self): display_plugin = self._selected_display_plugin() if not question_dialog( self, _('Install %s') % display_plugin.name, '<p>' + _('Installing plugins is a <b>security risk</b>. ' 'Plugins can contain a virus/malware. ' 'Only install it if you got it from a trusted source.' ' Are you sure you want to proceed?'), show_copy_button=False): return if display_plugin.uninstall_plugins: uninstall_names = list(display_plugin.uninstall_plugins) if DEBUG: prints('Uninstalling plugin: ', ', '.join(uninstall_names)) for name_to_remove in uninstall_names: self._uninstall_plugin(name_to_remove) plugin_zip_url = display_plugin.zip_url if DEBUG: prints('Downloading plugin zip attachment: ', plugin_zip_url) self.gui.status_bar.showMessage( _('Downloading plugin zip attachment: %s') % plugin_zip_url) zip_path = self._download_zip(plugin_zip_url) if DEBUG: prints('Installing plugin: ', zip_path) self.gui.status_bar.showMessage(_('Installing plugin: %s') % zip_path) do_restart = False try: try: plugin = add_plugin(zip_path) except NameConflict as e: return error_dialog(self.gui, _('Already exists'), unicode(e), show=True) # Check for any toolbars to add to. widget = ConfigWidget(self.gui) widget.gui = self.gui widget.check_for_add_to_toolbars(plugin) self.gui.status_bar.showMessage( _('Plugin installed: %s') % display_plugin.name) d = info_dialog( self.gui, _('Success'), _('Plugin <b>{0}</b> successfully installed under <b>' ' {1} plugins</b>. You may have to restart calibre ' 'for the plugin to take effect.').format( plugin.name, plugin.type), show_copy_button=False) b = d.bb.addButton(_('Restart calibre now'), d.bb.AcceptRole) b.setIcon(QIcon(I('lt.png'))) d.do_restart = False def rf(): d.do_restart = True b.clicked.connect(rf) d.set_details('') d.exec_() b.clicked.disconnect() do_restart = d.do_restart display_plugin.plugin = plugin # We cannot read the 'actual' version information as the plugin will not be loaded yet display_plugin.installed_version = display_plugin.available_version except: if DEBUG: prints('ERROR occurred while installing plugin: %s' % display_plugin.name) traceback.print_exc() error_dialog( self.gui, _('Install Plugin Failed'), _('A problem occurred while installing this plugin.' ' This plugin will now be uninstalled.' ' Please post the error message in details below into' ' the forum thread for this plugin and restart Calibre.'), det_msg=traceback.format_exc(), show=True) if DEBUG: prints('Due to error now uninstalling plugin: %s' % display_plugin.name) remove_plugin(display_plugin.name) display_plugin.plugin = None display_plugin.uninstall_plugins = [] if self.proxy_model.filter_criteria in [ FILTER_NOT_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.reset() self._select_and_focus_view() else: self.model.refresh_plugin(display_plugin) self._select_and_focus_view(change_selection=False) if do_restart: self.do_restart = True self.accept() def _history_clicked(self): display_plugin = self._selected_display_plugin() text = self._read_version_history_html(display_plugin.forum_link) if text: dlg = VersionHistoryDialog(self, display_plugin.name, text) dlg.exec_() else: return error_dialog( self, _('Version history missing'), _('Unable to find the version history for %s') % display_plugin.name, show=True) def _configure_clicked(self): display_plugin = self._selected_display_plugin() plugin = display_plugin.plugin if not plugin.is_customizable(): return info_dialog(self, _('Plugin not customizable'), _('Plugin: %s does not need customization') % plugin.name, show=True) from calibre.customize import InterfaceActionBase if isinstance(plugin, InterfaceActionBase) and not getattr( plugin, 'actual_iaction_plugin_loaded', False): return error_dialog(self, _('Must restart'), _('You must restart calibre before you can' ' configure the <b>%s</b> plugin') % plugin.name, show=True) plugin.do_user_config(self.parent()) def _toggle_enabled_clicked(self): display_plugin = self._selected_display_plugin() plugin = display_plugin.plugin if not plugin.can_be_disabled: return error_dialog(self, _('Plugin cannot be disabled'), _('The plugin: %s cannot be disabled') % plugin.name, show=True) if is_disabled(plugin): enable_plugin(plugin) else: disable_plugin(plugin) self.model.refresh_plugin(display_plugin) def _read_version_history_html(self, forum_link): br = browser() br.set_handle_gzip(True) try: raw = br.open_novisit(forum_link).read() if not raw: return None except: traceback.print_exc() return None raw = raw.decode('utf-8', errors='replace') root = html.fromstring(raw) spoiler_nodes = root.xpath( '//div[@class="smallfont" and strong="Spoiler"]') for spoiler_node in spoiler_nodes: try: if spoiler_node.getprevious() is None: # This is a spoiler node that has been indented using [INDENT] # Need to go up to parent div, then previous node to get header heading_node = spoiler_node.getparent().getprevious() else: # This is a spoiler node after a BR tag from the heading heading_node = spoiler_node.getprevious().getprevious() if heading_node is None: continue if heading_node.text_content().lower().find( 'version history') != -1: div_node = spoiler_node.xpath('div')[0] text = html.tostring(div_node, method='html', encoding=unicode) return re.sub('<div\s.*?>', '<div>', text) except: if DEBUG: prints('======= MobileRead Parse Error =======') traceback.print_exc() prints(html.tostring(spoiler_node)) return None def _download_zip(self, plugin_zip_url): from calibre.ptempfile import PersistentTemporaryFile br = browser(user_agent='%s %s' % (__appname__, __version__)) raw = br.open_novisit(plugin_zip_url).read() with PersistentTemporaryFile('.zip') as pt: pt.write(raw) return pt.name