class MainWindowMixin(object): # {{{ def __init__(self, db): self.setObjectName('MainWindow') self.setWindowIcon(QIcon(I('lt.png'))) self.setWindowTitle(__appname__) self.setContextMenuPolicy(Qt.NoContextMenu) self.centralwidget = QWidget(self) self.setCentralWidget(self.centralwidget) self._central_widget_layout = QVBoxLayout() self.centralwidget.setLayout(self._central_widget_layout) self.resize(1012, 740) self.donate_button = ThrobbingButton() self.location_manager = LocationManager(self) self.iactions['Fetch News'].init_scheduler(db) self.search_bar = SearchBar(self) self.bars_manager = BarsManager(self.donate_button, self.location_manager, self) for bar in self.bars_manager.main_bars: self.addToolBar(Qt.TopToolBarArea, bar) for bar in self.bars_manager.child_bars: self.addToolBar(Qt.BottomToolBarArea, bar) self.bars_manager.update_bars() # This is disabled because it introduces various toolbar related bugs # The width of the toolbar becomes the sum of both toolbars if tweaks['unified_title_toolbar_on_osx']: self.setUnifiedTitleAndToolBarOnMac(True) l = self.centralwidget.layout() l.addWidget(self.search_bar)
class MainWindowMixin(object): # {{{ def __init__(self, db): self.setObjectName('MainWindow') self.setWindowIcon(QIcon(I('lt.png'))) self.setWindowTitle(__appname__) self.setContextMenuPolicy(Qt.NoContextMenu) self.centralwidget = QWidget(self) self.setCentralWidget(self.centralwidget) self._central_widget_layout = QVBoxLayout() self.centralwidget.setLayout(self._central_widget_layout) self.resize(1012, 740) self.donate_button = ThrobbingButton() self.location_manager = LocationManager(self) self.iactions['Fetch News'].init_scheduler(db) self.search_bar = SearchBar(self) self.bars_manager = BarsManager(self.donate_button, self.location_manager, self) for bar in self.bars_manager.main_bars: self.addToolBar(Qt.TopToolBarArea, bar) for bar in self.bars_manager.child_bars: self.addToolBar(Qt.BottomToolBarArea, bar) self.bars_manager.update_bars() # This is disabled because it introduces various toolbar related bugs # The width of the toolbar becomes the sum of both toolbars if tweaks['unified_title_toolbar_on_osx']: self.setUnifiedTitleAndToolBarOnMac(True) l = self.centralwidget.layout() l.addWidget(self.search_bar)
def create_donate_widget(button): w = QWidget() w.setLayout(QVBoxLayout()) w.layout().addWidget(button) if isosx: w.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }') w.layout().setContentsMargins(0,0,0,0) w.setContentsMargins(0,0,0,0) w.filler = QLabel(u'\u00a0') w.layout().addWidget(w.filler) return w
def create_donate_widget(button): w = QWidget() w.setLayout(QVBoxLayout()) w.layout().addWidget(button) if isosx: w.setStyleSheet( 'QWidget, QToolButton {background-color: none; border: none; }') w.layout().setContentsMargins(0, 0, 0, 0) w.setContentsMargins(0, 0, 0, 0) w.filler = QLabel(u'\u00a0') w.layout().addWidget(w.filler) return w
class RuleEditor(QDialog): # {{{ def __init__(self, fm, parent=None): QDialog.__init__(self, parent) self.fm = fm self.setWindowIcon(QIcon(I('format-fill-color.png'))) self.setWindowTitle(_('Create/edit a column coloring rule')) self.l = l = QGridLayout(self) self.setLayout(l) self.l1 = l1 = QLabel(_('Create a coloring rule by' ' filling in the boxes below')) l.addWidget(l1, 0, 0, 1, 5) self.f1 = QFrame(self) self.f1.setFrameShape(QFrame.HLine) l.addWidget(self.f1, 1, 0, 1, 5) self.l2 = l2 = QLabel(_('Set the color of the column:')) l.addWidget(l2, 2, 0) self.column_box = QComboBox(self) l.addWidget(self.column_box, 2, 1) self.l3 = l3 = QLabel(_('to')) l.addWidget(l3, 2, 2) self.color_box = QComboBox(self) self.color_label = QLabel('Sample text Sample text') self.color_label.setTextFormat(Qt.RichText) l.addWidget(self.color_box, 2, 3) l.addWidget(self.color_label, 2, 4) l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 5) self.l4 = l4 = QLabel( _('Only if the following conditions are all satisfied:')) l.addWidget(l4, 3, 0, 1, 6) self.scroll_area = sa = QScrollArea(self) sa.setMinimumHeight(300) sa.setMinimumWidth(950) sa.setWidgetResizable(True) l.addWidget(sa, 4, 0, 1, 6) self.add_button = b = QPushButton(QIcon(I('plus.png')), _('Add another condition')) l.addWidget(b, 5, 0, 1, 6) b.clicked.connect(self.add_blank_condition) self.l5 = l5 = QLabel(_('You can disable a condition by' ' blanking all of its boxes')) l.addWidget(l5, 6, 0, 1, 6) self.bb = bb = QDialogButtonBox( QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) l.addWidget(bb, 7, 0, 1, 6) self.conditions_widget = QWidget(self) sa.setWidget(self.conditions_widget) self.conditions_widget.setLayout(QVBoxLayout()) self.conditions_widget.layout().setAlignment(Qt.AlignTop) self.conditions = [] for b in (self.column_box, self.color_box): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(15) for key in sorted( displayable_columns(fm), key=sort_key): name = fm[key]['name'] if name: self.column_box.addItem(key, key) self.column_box.setCurrentIndex(0) self.color_box.addItems(QColor.colorNames()) self.color_box.setCurrentIndex(0) self.update_color_label() self.color_box.currentIndexChanged.connect(self.update_color_label) self.resize(self.sizeHint()) def update_color_label(self): pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) c = unicode(self.color_box.currentText()) self.color_label.setText(''' <span style="color: {c}; background-color: {bg1}"> {st} </span> <span style="color: {c}; background-color: {bg2}"> {st} </span> '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) def add_blank_condition(self): c = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(c) self.conditions_widget.layout().addWidget(c) def apply_rule(self, col, rule): for i in range(self.column_box.count()): c = unicode(self.column_box.itemData(i).toString()) if col == c: self.column_box.setCurrentIndex(i) break if rule.color: idx = self.color_box.findText(rule.color) if idx >= 0: self.color_box.setCurrentIndex(idx) for c in rule.conditions: ce = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(ce) self.conditions_widget.layout().addWidget(ce) try: ce.condition = c except: import traceback traceback.print_exc() def accept(self): if self.validate(): QDialog.accept(self) def validate(self): r = Rule(self.fm) for c in self.conditions: condition = c.condition if condition is not None: try: r.add_condition(*condition) except Exception as e: import traceback error_dialog(self, _('Invalid condition'), _('One of the conditions for this rule is' ' invalid: <b>%s</b>')%e, det_msg=traceback.format_exc(), show=True) return False if len(r.conditions) < 1: error_dialog(self, _('No conditions'), _('You must specify at least one non-empty condition' ' for this rule'), show=True) return False return True @property def rule(self): r = Rule(self.fm) r.color = unicode(self.color_box.currentText()) idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: condition = c.condition if condition is not None: r.add_condition(*condition) return col, r
def start_animation(self): if config['disable_animations']: return if self.animation.state( ) != self.animation.Stopped or not self.isVisible(): return size = self.normal_icon_size.width() smaller = int(0.7 * size) self.animation.setStartValue(QSize(smaller, smaller)) self.animation.setEndValue(self.normal_icon_size) QMetaObject.invokeMethod(self.animation, 'start', Qt.QueuedConnection) def stop_animation(self): self.animation.stop() self.animation_finished() if __name__ == '__main__': from PyQt4.Qt import QApplication, QWidget, QHBoxLayout, QIcon app = QApplication([]) w = QWidget() w.setLayout(QHBoxLayout()) b = ThrobbingButton() b.setIcon(QIcon(I('donate.png'))) w.layout().addWidget(b) w.show() b.set_normal_icon_size(64, 64) b.start_animation() app.exec_()
class ToolBar(QToolBar): # {{{ def __init__(self, donate, location_manager, parent): QToolBar.__init__(self, parent) self.setMovable(False) self.setFloatable(False) self.setOrientation(Qt.Horizontal) self.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) self.setStyleSheet('QToolButton:checked { font-weight: bold }') self.preferred_width = self.sizeHint().width() self.gui = parent self.donate_button = donate self.added_actions = [] self.location_manager = location_manager donate.setAutoRaise(True) donate.setCursor(Qt.PointingHandCursor) self.setAcceptDrops(True) self.showing_donate = False def resizeEvent(self, ev): QToolBar.resizeEvent(self, ev) style = self.get_text_style() self.setToolButtonStyle(style) if hasattr(self, 'd_widget') and hasattr(self.d_widget, 'filler'): self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly) def get_text_style(self): style = Qt.ToolButtonTextUnderIcon s = gprefs['toolbar_icon_size'] if s != 'off': p = gprefs['toolbar_text'] if p == 'never': style = Qt.ToolButtonIconOnly elif p == 'auto' and self.preferred_width > self.width() + 35: style = Qt.ToolButtonIconOnly return style def contextMenuEvent(self, ev): ac = self.actionAt(ev.pos()) if ac is None: return ch = self.widgetForAction(ac) sm = getattr(ch, 'showMenu', None) if callable(sm): ev.accept() sm() def update_lm_actions(self): for ac in self.added_actions: if ac in self.location_manager.all_actions: ac.setVisible(ac in self.location_manager.available_actions) def init_bar(self, actions): self.showing_donate = False for ac in self.added_actions: m = ac.menu() if m is not None: m.setVisible(False) self.clear() self.added_actions = [] bar = self for what in actions: if what is None: bar.addSeparator() elif what == 'Location Manager': for ac in self.location_manager.all_actions: bar.addAction(ac) bar.added_actions.append(ac) bar.setup_tool_button(bar, ac, QToolButton.MenuButtonPopup) ac.setVisible(False) elif what == 'Donate': self.d_widget = QWidget() self.d_widget.setLayout(QVBoxLayout()) self.d_widget.layout().addWidget(self.donate_button) if isosx: self.d_widget.setStyleSheet( 'QWidget, QToolButton {background-color: none; border: none; }' ) self.d_widget.layout().setContentsMargins(0, 0, 0, 0) self.d_widget.setContentsMargins(0, 0, 0, 0) self.d_widget.filler = QLabel(u'\u00a0') self.d_widget.layout().addWidget(self.d_widget.filler) bar.addWidget(self.d_widget) self.showing_donate = True elif what in self.gui.iactions: action = self.gui.iactions[what] bar.addAction(action.qaction) self.added_actions.append(action.qaction) self.setup_tool_button(bar, action.qaction, action.popup_type) self.preferred_width = self.sizeHint().width() def setup_tool_button(self, bar, ac, menu_mode=None): ch = bar.widgetForAction(ac) if ch is None: ch = self.child_bar.widgetForAction(ac) ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) if ac.menu() is not None and menu_mode is not None: ch.setPopupMode(menu_mode) return ch # support drag&drop from/to library, from/to reader/card, enabled plugins def check_iactions_for_drag(self, event, md, func): if self.added_actions: pos = event.pos() for iac in self.gui.iactions.itervalues(): if iac.accepts_drops: aa = iac.qaction w = self.widgetForAction(aa) m = aa.menu() if (((w is not None and w.geometry().contains(pos)) or (m is not None and m.isVisible() and m.geometry().contains(pos))) and getattr(iac, func)(event, md)): return True return False def dragEnterEvent(self, event): md = event.mimeData() if md.hasFormat("application/calibre+from_library") or \ md.hasFormat("application/calibre+from_device"): event.setDropAction(Qt.CopyAction) event.accept() return if self.check_iactions_for_drag(event, md, 'accept_enter_event'): event.accept() else: event.ignore() def dragMoveEvent(self, event): allowed = False md = event.mimeData() # Drop is only allowed in the location manager widget's different from the selected one for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None: if ( md.hasFormat("application/calibre+from_library") or \ md.hasFormat("application/calibre+from_device") ) and \ w.geometry().contains(event.pos()) and \ isinstance(w, QToolButton) and not w.isChecked(): allowed = True break if allowed: event.acceptProposedAction() return if self.check_iactions_for_drag(event, md, 'accept_drag_move_event'): event.acceptProposedAction() else: event.ignore() def dropEvent(self, event): data = event.mimeData() mime = 'application/calibre+from_library' if data.hasFormat(mime): ids = list(map(int, str(data.data(mime)).split())) tgt = None for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None and w.geometry().contains(event.pos()): tgt = ac.calibre_name if tgt is not None: if tgt == 'main': tgt = None self.gui.sync_to_device(tgt, False, send_ids=ids) event.accept() return mime = 'application/calibre+from_device' if data.hasFormat(mime): paths = [unicode(u.toLocalFile()) for u in data.urls()] if paths: self.gui.iactions['Add Books'].add_books_from_device( self.gui.current_view(), paths=paths) event.accept() return # Give added_actions an opportunity to process the drag&drop event if self.check_iactions_for_drag(event, data, 'drop_event'): event.accept() else: event.ignore()
def stop_animation(self): self.animation.stop() self.animation_finished() def create_donate_widget(button): w = QWidget() w.setLayout(QVBoxLayout()) w.layout().addWidget(button) if isosx: w.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }') w.layout().setContentsMargins(0,0,0,0) w.setContentsMargins(0,0,0,0) w.filler = QLabel(u'\u00a0') w.layout().addWidget(w.filler) return w if __name__ == '__main__': from PyQt4.Qt import QApplication, QHBoxLayout, QIcon app = QApplication([]) w = QWidget() w.setLayout(QHBoxLayout()) b = ThrobbingButton() b.setIcon(QIcon(I('donate.png'))) w.layout().addWidget(b) w.show() b.set_normal_icon_size(64, 64) b.start_animation() app.exec_()
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle("My Main Window") self.setMinimumWidth(MAIN_WINDOW_SIZE[0]) self.setMinimumHeight(MAIN_WINDOW_SIZE[1]) self.statusbar = QtGui.QStatusBar(self) self.statusbar.showMessage("Status message") self.setStatusBar(self.statusbar) ################################################ self.menubar = self.menuBar() # Any menu action makes the status bar message disappear fileMenu = QtGui.QMenu(self.menubar) fileMenu.setTitle("File") self.menubar.addAction(fileMenu.menuAction()) newAction = QtGui.QAction("New", self) newAction.setIcon(QtGui.QtIcon(icons + '/GroupPropDialog_image0.png')) fileMenu.addAction(newAction) openAction = QtGui.QAction("Open", self) openAction.setIcon(QtGui.QtIcon(icons + "/MainWindowUI_image1")) fileMenu.addAction(openAction) saveAction = QtGui.QAction("Save", self) saveAction.setIcon(QtGui.QtIcon(icons + "/MainWindowUI_image2")) fileMenu.addAction(saveAction) self.connect(newAction, SIGNAL("activated()"), self.fileNew) self.connect(openAction, SIGNAL("activated()"), self.fileOpen) self.connect(saveAction, SIGNAL("activated()"), self.fileSave) for otherMenuName in ('Edit', 'View', 'Display', 'Select', 'Modify', 'NanoHive-1'): otherMenu = QtGui.QMenu(self.menubar) otherMenu.setTitle(otherMenuName) self.menubar.addAction(otherMenu.menuAction()) helpMenu = QtGui.QMenu(self.menubar) helpMenu.setTitle("Help") self.menubar.addAction(helpMenu.menuAction()) aboutAction = QtGui.QAction("About", self) aboutAction.setIcon(QtGui.QtIcon(icons + '/MainWindowUI_image0.png')) helpMenu.addAction(aboutAction) self.connect(aboutAction, SIGNAL("activated()"), self.helpAbout) ############################################## self.setMenuBar(self.menubar) centralwidget = QWidget() self.setCentralWidget(centralwidget) layout = QVBoxLayout(centralwidget) layout.setMargin(0) layout.setSpacing(0) middlewidget = QWidget() self.bigButtons = QWidget() bblo = QHBoxLayout(self.bigButtons) bblo.setMargin(0) bblo.setSpacing(0) self.bigButtons.setMinimumHeight(50) self.bigButtons.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) for name in ('Features', 'Sketch', 'Build', 'Dimension', 'Simulator'): btn = QPushButton(self.bigButtons) btn.setMaximumWidth(80) btn.setMinimumHeight(50) btn.setText(name) self.bigButtons.layout().addWidget(btn) self.bigButtons.hide() layout.addWidget(self.bigButtons) self.littleIcons = QWidget() self.littleIcons.setMinimumHeight(30) self.littleIcons.setMaximumHeight(30) lilo = QHBoxLayout(self.littleIcons) lilo.setMargin(0) lilo.setSpacing(0) pb = QPushButton(self.littleIcons) pb.setIcon(QIcon(icons + '/GroupPropDialog_image0.png')) self.connect(pb, SIGNAL("clicked()"), self.fileNew) lilo.addWidget(pb) for x in "1 2 4 5 6 7 8 18 42 10 43 150 93 94 97 137".split(): pb = QPushButton(self.littleIcons) pb.setIcon(QIcon(icons + '/MainWindowUI_image' + x + '.png')) lilo.addWidget(pb) layout.addWidget(self.littleIcons) layout.addWidget(middlewidget) self.layout = QGridLayout(middlewidget) self.layout.setMargin(0) self.layout.setSpacing(2) self.gridPosition = GridPosition() self.numParts = 0 self.show() explainWindow = AboutWindow( "Select <b>Help->About</b>" " for instructions...", 200, 3) def removePartWindow(self, pw): self.layout.removeWidget(pw) self.gridPosition.removeWidget(pw) self.numParts -= 1 if self.numParts == 0: self.bigButtons.hide() def fileNew(self): if self.numParts == 0: self.bigButtons.show() self.numParts += 1 pw = PartWindow(self) row, col = self.gridPosition.next(pw) self.layout.addWidget(pw, row, col) def fileOpen(self): print "Let's pretend we're opening a file" def fileSave(self): print "Let's pretend we're saving a file" def helpAbout(self): AboutWindow(__doc__)
class RuleEditor(QDialog): # {{{ 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 = _('coloring') else: self.rule_kind = 'icon' rule_text = _('icon') self.setWindowIcon(QIcon(I('format-fill-color.png'))) self.setWindowTitle(_('Create/edit a column {0} rule').format(rule_text)) self.l = l = QGridLayout(self) self.setLayout(l) self.l1 = l1 = QLabel(_('Create a column {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(_('Set the')) l.addWidget(l2, 2, 0) if self.rule_kind == 'color': l.addWidget(QLabel(_('color'))) else: 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.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 == 'color': self.color_box = QComboBox(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) else: self.filename_box = QComboBox() self.filename_box.setInsertPolicy(self.filename_box.InsertAlphabetically) d = os.path.join(config_dir, 'cc_icons') self.icon_file_names = [] if os.path.exists(d): for icon_file in os.listdir(d): icon_file = lower(icon_file) if os.path.exists(os.path.join(d, icon_file)): if icon_file.endswith('.png'): self.icon_file_names.append(icon_file) self.icon_file_names.sort(key=sort_key) self.update_filename_box() l.addWidget(self.filename_box, 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) 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, self.color_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 0): 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.addItems(QColor.colorNames()) self.color_box.setCurrentIndex(0) self.update_color_label() self.color_box.currentIndexChanged.connect(self.update_color_label) else: self.filename_button.clicked.connect(self.filename_button_clicked) self.resize(self.sizeHint()) def update_filename_box(self): self.filename_box.clear() self.icon_file_names.sort(key=sort_key) self.filename_box.addItem('') self.filename_box.addItems(self.icon_file_names) for i,filename in enumerate(self.icon_file_names): icon = QIcon(os.path.join(config_dir, 'cc_icons', filename)) self.filename_box.setItemIcon(i+1, icon) def update_color_label(self): pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) c = unicode(self.color_box.currentText()) self.color_label.setText(''' <span style="color: {c}; background-color: {bg1}"> {st} </span> <span style="color: {c}; background-color: {bg2}"> {st} </span> '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) def filename_button_clicked(self): try: path = choose_files(self, 'choose_category_icon', _('Select Icon'), filters=[ ('Images', ['png', 'gif', 'jpg', 'jpeg'])], all_files=False, select_only_single_file=True) if path: icon_path = path[0] icon_name = sanitize_file_name_unicode( os.path.splitext( os.path.basename(icon_path))[0]+'.png') if icon_name not in self.icon_file_names: self.icon_file_names.append(icon_name) self.update_filename_box() try: p = QIcon(icon_path).pixmap(QSize(128, 128)) d = os.path.join(config_dir, 'cc_icons') if not os.path.exists(os.path.join(d, icon_name)): if not os.path.exists(d): os.makedirs(d) with open(os.path.join(d, icon_name), 'wb') as f: f.write(pixmap_to_data(p, format='PNG')) except: import traceback traceback.print_exc() self.filename_box.setCurrentIndex(self.filename_box.findText(icon_name)) self.filename_box.adjustSize() except: import traceback traceback.print_exc() return def add_blank_condition(self): c = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(c) self.conditions_widget.layout().addWidget(c) def apply_rule(self, kind, col, rule): if kind == 'color': if rule.color: idx = self.color_box.findText(rule.color) if idx >= 0: self.color_box.setCurrentIndex(idx) else: self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1) if rule.color: idx = self.filename_box.findText(rule.color) if idx >= 0: self.filename_box.setCurrentIndex(idx) else: self.filename_box.setCurrentIndex(0) for i in range(self.column_box.count()): c = unicode(self.column_box.itemData(i).toString()) if col == c: self.column_box.setCurrentIndex(i) break for c in rule.conditions: ce = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(ce) self.conditions_widget.layout().addWidget(ce) try: ce.condition = c except: import traceback traceback.print_exc() def accept(self): if self.rule_kind != 'color': fname = lower(unicode(self.filename_box.currentText())) if not fname: error_dialog(self, _('No icon selected'), _('You must choose an icon for this rule'), show=True) return if self.validate(): QDialog.accept(self) def validate(self): r = Rule(self.fm) for c in self.conditions: condition = c.condition if condition is not None: try: r.add_condition(*condition) except Exception as e: import traceback error_dialog(self, _('Invalid condition'), _('One of the conditions for this rule is' ' invalid: <b>%s</b>')%e, det_msg=traceback.format_exc(), show=True) return False if len(r.conditions) < 1: error_dialog(self, _('No conditions'), _('You must specify at least one non-empty condition' ' for this rule'), show=True) return False return True @property def rule(self): r = Rule(self.fm) if self.rule_kind != 'color': r.color = unicode(self.filename_box.currentText()) else: r.color = unicode(self.color_box.currentText()) idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: condition = c.condition if condition is not None: r.add_condition(*condition) if self.rule_kind == 'icon': kind = unicode(self.kind_box.itemData( self.kind_box.currentIndex()).toString()) else: kind = 'color' return kind, col, r
class ToolBar(QToolBar): # {{{ def __init__(self, donate, location_manager, parent): QToolBar.__init__(self, parent) self.setMovable(False) self.setFloatable(False) self.setOrientation(Qt.Horizontal) self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea) self.setStyleSheet('QToolButton:checked { font-weight: bold }') self.preferred_width = self.sizeHint().width() self.gui = parent self.donate_button = donate self.added_actions = [] self.location_manager = location_manager donate.setAutoRaise(True) donate.setCursor(Qt.PointingHandCursor) self.setAcceptDrops(True) self.showing_donate = False def resizeEvent(self, ev): QToolBar.resizeEvent(self, ev) style = self.get_text_style() self.setToolButtonStyle(style) if hasattr(self, 'd_widget') and hasattr(self.d_widget, 'filler'): self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly) def get_text_style(self): style = Qt.ToolButtonTextUnderIcon s = gprefs['toolbar_icon_size'] if s != 'off': p = gprefs['toolbar_text'] if p == 'never': style = Qt.ToolButtonIconOnly elif p == 'auto' and self.preferred_width > self.width()+35: style = Qt.ToolButtonIconOnly return style def contextMenuEvent(self, ev): ac = self.actionAt(ev.pos()) if ac is None: return ch = self.widgetForAction(ac) sm = getattr(ch, 'showMenu', None) if callable(sm): ev.accept() sm() def update_lm_actions(self): for ac in self.added_actions: if ac in self.location_manager.all_actions: ac.setVisible(ac in self.location_manager.available_actions) def init_bar(self, actions): self.showing_donate = False for ac in self.added_actions: m = ac.menu() if m is not None: m.setVisible(False) self.clear() self.added_actions = [] bar = self for what in actions: if what is None: bar.addSeparator() elif what == 'Location Manager': for ac in self.location_manager.all_actions: bar.addAction(ac) bar.added_actions.append(ac) bar.setup_tool_button(bar, ac, QToolButton.MenuButtonPopup) ac.setVisible(False) elif what == 'Donate': self.d_widget = QWidget() self.d_widget.setLayout(QVBoxLayout()) self.d_widget.layout().addWidget(self.donate_button) if isosx: self.d_widget.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }') self.d_widget.layout().setContentsMargins(0,0,0,0) self.d_widget.setContentsMargins(0,0,0,0) self.d_widget.filler = QLabel(u'\u00a0') self.d_widget.layout().addWidget(self.d_widget.filler) bar.addWidget(self.d_widget) self.showing_donate = True elif what in self.gui.iactions: action = self.gui.iactions[what] bar.addAction(action.qaction) self.added_actions.append(action.qaction) self.setup_tool_button(bar, action.qaction, action.popup_type) self.preferred_width = self.sizeHint().width() def setup_tool_button(self, bar, ac, menu_mode=None): ch = bar.widgetForAction(ac) if ch is None: ch = self.child_bar.widgetForAction(ac) ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) if ac.menu() is not None and menu_mode is not None: ch.setPopupMode(menu_mode) return ch # support drag&drop from/to library, from/to reader/card, enabled plugins def check_iactions_for_drag(self, event, md, func): if self.added_actions: pos = event.pos() for iac in self.gui.iactions.itervalues(): if iac.accepts_drops: aa = iac.qaction w = self.widgetForAction(aa) m = aa.menu() if (( (w is not None and w.geometry().contains(pos)) or (m is not None and m.isVisible() and m.geometry().contains(pos)) ) and getattr(iac, func)(event, md)): return True return False def dragEnterEvent(self, event): md = event.mimeData() if md.hasFormat("application/calibre+from_library") or \ md.hasFormat("application/calibre+from_device"): event.setDropAction(Qt.CopyAction) event.accept() return if self.check_iactions_for_drag(event, md, 'accept_enter_event'): event.accept() else: event.ignore() def dragMoveEvent(self, event): allowed = False md = event.mimeData() # Drop is only allowed in the location manager widget's different from the selected one for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None: if ( md.hasFormat("application/calibre+from_library") or \ md.hasFormat("application/calibre+from_device") ) and \ w.geometry().contains(event.pos()) and \ isinstance(w, QToolButton) and not w.isChecked(): allowed = True break if allowed: event.acceptProposedAction() return if self.check_iactions_for_drag(event, md, 'accept_drag_move_event'): event.acceptProposedAction() else: event.ignore() def dropEvent(self, event): data = event.mimeData() mime = 'application/calibre+from_library' if data.hasFormat(mime): ids = list(map(int, str(data.data(mime)).split())) tgt = None for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None and w.geometry().contains(event.pos()): tgt = ac.calibre_name if tgt is not None: if tgt == 'main': tgt = None self.gui.sync_to_device(tgt, False, send_ids=ids) event.accept() return mime = 'application/calibre+from_device' if data.hasFormat(mime): paths = [unicode(u.toLocalFile()) for u in data.urls()] if paths: self.gui.iactions['Add Books'].add_books_from_device( self.gui.current_view(), paths=paths) event.accept() return # Give added_actions an opportunity to process the drag&drop event if self.check_iactions_for_drag(event, data, 'drop_event'): event.accept() else: event.ignore()
class RuleEditor(QDialog): # {{{ @property def doing_multiple(self): return hasattr(self, 'multiple_icon_cb') and self.multiple_icon_cb.isChecked() 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() 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 image'), bb.ActionRole) b.setIcon(QIcon(I('minus.png'))) b.setMenu(QMenu()) 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 0): 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 multiple_box_clicked(self): self.update_filename_box() self.update_icon_filenames_in_box() @property def icon_folder(self): return os.path.join(config_dir, 'cc_icons') def populate_icon_filenames(self): d = self.icon_folder self.icon_file_names = [] if os.path.exists(d): for icon_file in os.listdir(d): icon_file = lower(icon_file) if os.path.exists(os.path.join(d, icon_file)) and icon_file.endswith('.png'): self.icon_file_names.append(icon_file) self.icon_file_names.sort(key=sort_key) def update_filename_box(self): doing_multiple = self.doing_multiple model = QStandardItemModel() self.filename_box.setModel(model) self.icon_file_names.sort(key=sort_key) if doing_multiple: item = QStandardItem(_('Open to see checkboxes')) else: item = QStandardItem('') model.appendRow(item) for i,filename in enumerate(self.icon_file_names): item = QStandardItem(filename) if doing_multiple: item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(Qt.Unchecked, Qt.CheckStateRole) else: item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) icon = QIcon(os.path.join(self.icon_folder, filename)) item.setIcon(icon) model.appendRow(item) def update_color_label(self): pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) c = self.color_box.color self.color_label.setText(''' <span style="color: {c}; background-color: {bg1}"> {st} </span> <span style="color: {c}; background-color: {bg2}"> {st} </span> '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) def filename_button_clicked(self): try: path = choose_files(self, 'choose_category_icon', _('Select Icon'), filters=[ ('Images', ['png', 'gif', 'jpg', 'jpeg'])], all_files=False, select_only_single_file=True) if path: icon_path = path[0] icon_name = lower(sanitize_file_name_unicode( os.path.splitext( os.path.basename(icon_path))[0]+'.png')) if icon_name not in self.icon_file_names: self.icon_file_names.append(icon_name) self.update_filename_box() self.update_remove_button() try: p = QIcon(icon_path).pixmap(QSize(128, 128)) d = self.icon_folder if not os.path.exists(os.path.join(d, icon_name)): if not os.path.exists(d): os.makedirs(d) with open(os.path.join(d, icon_name), 'wb') as f: f.write(pixmap_to_data(p, format='PNG')) except: import traceback traceback.print_exc() if self.doing_multiple: if icon_name not in self.rule_icon_files: self.rule_icon_files.append(icon_name) self.update_icon_filenames_in_box() else: self.filename_box.setCurrentIndex(self.filename_box.findText(icon_name)) self.filename_box.adjustSize() except: import traceback traceback.print_exc() return def get_filenames_from_box(self): if self.doing_multiple: model = self.filename_box.model() fnames = [] for i in range(1, model.rowCount()): item = model.item(i, 0) if item.checkState() == Qt.Checked: fnames.append(lower(unicode(item.text()))) fname = ' : '.join(fnames) else: fname = lower(unicode(self.filename_box.currentText())) return fname def update_icon_filenames_in_box(self): if self.rule_icon_files: if not self.doing_multiple: idx = self.filename_box.findText(self.rule_icon_files[0]) if idx >= 0: self.filename_box.setCurrentIndex(idx) else: self.filename_box.setCurrentIndex(0) else: model = self.filename_box.model() for icon in self.rule_icon_files: idx = self.filename_box.findText(icon) if idx >= 0: item = model.item(idx) item.setCheckState(Qt.Checked) def update_remove_button(self): m = self.remove_button.menu() m.clear() for name in self.icon_file_names: m.addAction(QIcon(os.path.join(self.icon_folder, name)), name).triggered.connect(partial( self.remove_image, name)) def remove_image(self, name): try: os.remove(os.path.join(self.icon_folder, name)) except EnvironmentError: pass else: self.populate_icon_filenames() self.update_remove_button() self.update_filename_box() self.update_icon_filenames_in_box() def add_blank_condition(self): c = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(c) self.conditions_widget.layout().addWidget(c) def apply_rule(self, kind, col, rule): if kind == 'color': if rule.color: self.color_box.color = rule.color else: if self.rule_kind == 'icon': for i, tup in enumerate(icon_rule_kinds): if kind == tup[1]: self.kind_box.setCurrentIndex(i) break self.rule_icon_files = [ic.strip() for ic in rule.color.split(':')] if len(self.rule_icon_files) > 1: self.multiple_icon_cb.setChecked(True) self.update_filename_box() self.update_icon_filenames_in_box() for i in range(self.column_box.count()): c = unicode(self.column_box.itemData(i).toString()) if col == c: self.column_box.setCurrentIndex(i) break for c in rule.conditions: ce = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(ce) self.conditions_widget.layout().addWidget(ce) try: ce.condition = c except: import traceback traceback.print_exc() def accept(self): if self.rule_kind != 'color': fname = self.get_filenames_from_box() if not fname: error_dialog(self, _('No icon selected'), _('You must choose an icon for this rule'), show=True) return if self.validate(): QDialog.accept(self) def validate(self): r = Rule(self.fm) for c in self.conditions: condition = c.condition if condition is not None: try: r.add_condition(*condition) except Exception as e: import traceback error_dialog(self, _('Invalid condition'), _('One of the conditions for this rule is' ' invalid: <b>%s</b>')%e, det_msg=traceback.format_exc(), show=True) return False if len(r.conditions) < 1: error_dialog(self, _('No conditions'), _('You must specify at least one non-empty condition' ' for this rule'), show=True) return False return True @property def rule(self): r = Rule(self.fm) if self.rule_kind != 'color': r.color = self.get_filenames_from_box() else: r.color = self.color_box.color idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: condition = c.condition if condition is not None: r.add_condition(*condition) if self.rule_kind == 'icon': kind = unicode(self.kind_box.itemData( self.kind_box.currentIndex()).toString()) else: kind = self.rule_kind return kind, col, r
class ToolBar(QToolBar): # {{{ def __init__(self, donate, location_manager, parent): QToolBar.__init__(self, parent) self.setMovable(False) self.setFloatable(False) self.setOrientation(Qt.Horizontal) self.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) self.setStyleSheet("QToolButton:checked { font-weight: bold }") self.preferred_width = self.sizeHint().width() self.gui = parent self.donate_button = donate self.added_actions = [] self.location_manager = location_manager donate.setAutoRaise(True) donate.setCursor(Qt.PointingHandCursor) self.setAcceptDrops(True) self.showing_donate = False def resizeEvent(self, ev): QToolBar.resizeEvent(self, ev) style = self.get_text_style() self.setToolButtonStyle(style) if hasattr(self, "d_widget") and hasattr(self.d_widget, "filler"): self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly) def get_text_style(self): style = Qt.ToolButtonTextUnderIcon s = gprefs["toolbar_icon_size"] if s != "off": p = gprefs["toolbar_text"] if p == "never": style = Qt.ToolButtonIconOnly elif p == "auto" and self.preferred_width > self.width() + 35: style = Qt.ToolButtonIconOnly return style def contextMenuEvent(self, ev): ac = self.actionAt(ev.pos()) if ac is None: return ch = self.widgetForAction(ac) sm = getattr(ch, "showMenu", None) if callable(sm): ev.accept() sm() def update_lm_actions(self): for ac in self.added_actions: if ac in self.location_manager.all_actions: ac.setVisible(ac in self.location_manager.available_actions) def init_bar(self, actions): self.showing_donate = False for ac in self.added_actions: m = ac.menu() if m is not None: m.setVisible(False) self.clear() self.added_actions = [] bar = self for what in actions: if what is None: bar.addSeparator() elif what == "Location Manager": for ac in self.location_manager.all_actions: bar.addAction(ac) bar.added_actions.append(ac) bar.setup_tool_button(bar, ac, QToolButton.MenuButtonPopup) ac.setVisible(False) elif what == "Donate": self.d_widget = QWidget() self.d_widget.setLayout(QVBoxLayout()) self.d_widget.layout().addWidget(self.donate_button) if isosx: self.d_widget.setStyleSheet("QWidget, QToolButton {background-color: none; border: none; }") self.d_widget.layout().setContentsMargins(0, 0, 0, 0) self.d_widget.setContentsMargins(0, 0, 0, 0) self.d_widget.filler = QLabel("\u00a0") self.d_widget.layout().addWidget(self.d_widget.filler) bar.addWidget(self.d_widget) self.showing_donate = True elif what in self.gui.iactions: action = self.gui.iactions[what] bar.addAction(action.qaction) self.added_actions.append(action.qaction) self.setup_tool_button(bar, action.qaction, action.popup_type) self.preferred_width = self.sizeHint().width() def setup_tool_button(self, bar, ac, menu_mode=None): ch = bar.widgetForAction(ac) if ch is None: ch = self.child_bar.widgetForAction(ac) ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) if ac.menu() is not None and menu_mode is not None: ch.setPopupMode(menu_mode) return ch # support drag&drop from/to library from/to reader/card def dragEnterEvent(self, event): md = event.mimeData() if md.hasFormat("application/calibre+from_library") or md.hasFormat("application/calibre+from_device"): event.setDropAction(Qt.CopyAction) event.accept() else: event.ignore() def dragMoveEvent(self, event): allowed = False md = event.mimeData() # Drop is only allowed in the location manager widget's different from the selected one for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None: if ( ( md.hasFormat("application/calibre+from_library") or md.hasFormat("application/calibre+from_device") ) and w.geometry().contains(event.pos()) and isinstance(w, QToolButton) and not w.isChecked() ): allowed = True break if allowed: event.acceptProposedAction() else: event.ignore() def dropEvent(self, event): data = event.mimeData() mime = "application/calibre+from_library" if data.hasFormat(mime): ids = list(map(int, str(data.data(mime)).split())) tgt = None for ac in self.location_manager.available_actions: w = self.widgetForAction(ac) if w is not None and w.geometry().contains(event.pos()): tgt = ac.calibre_name if tgt is not None: if tgt == "main": tgt = None self.gui.sync_to_device(tgt, False, send_ids=ids) event.accept() mime = "application/calibre+from_device" if data.hasFormat(mime): paths = [unicode(u.toLocalFile()) for u in data.urls()] if paths: self.gui.iactions["Add Books"].add_books_from_device(self.gui.current_view(), paths=paths) event.accept()
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle("My Main Window") self.setMinimumWidth(MAIN_WINDOW_SIZE[0]) self.setMinimumHeight(MAIN_WINDOW_SIZE[1]) self.statusbar = QtGui.QStatusBar(self) self.statusbar.showMessage("Status message") self.setStatusBar(self.statusbar) ################################################ self.menubar = self.menuBar() # Any menu action makes the status bar message disappear fileMenu = QtGui.QMenu(self.menubar) fileMenu.setTitle("File") self.menubar.addAction(fileMenu.menuAction()) newAction = QtGui.QAction("New", self) newAction.setIcon(QtGui.QtIcon(icons + '/GroupPropDialog_image0.png')) fileMenu.addAction(newAction) openAction = QtGui.QAction("Open", self) openAction.setIcon(QtGui.QtIcon(icons + "/MainWindowUI_image1")) fileMenu.addAction(openAction) saveAction = QtGui.QAction("Save", self) saveAction.setIcon(QtGui.QtIcon(icons + "/MainWindowUI_image2")) fileMenu.addAction(saveAction) self.connect(newAction,SIGNAL("activated()"),self.fileNew) self.connect(openAction,SIGNAL("activated()"),self.fileOpen) self.connect(saveAction,SIGNAL("activated()"),self.fileSave) for otherMenuName in ('Edit', 'View', 'Display', 'Select', 'Modify', 'NanoHive-1'): otherMenu = QtGui.QMenu(self.menubar) otherMenu.setTitle(otherMenuName) self.menubar.addAction(otherMenu.menuAction()) helpMenu = QtGui.QMenu(self.menubar) helpMenu.setTitle("Help") self.menubar.addAction(helpMenu.menuAction()) aboutAction = QtGui.QAction("About", self) aboutAction.setIcon(QtGui.QtIcon(icons + '/MainWindowUI_image0.png')) helpMenu.addAction(aboutAction) self.connect(aboutAction,SIGNAL("activated()"),self.helpAbout) ############################################## self.setMenuBar(self.menubar) centralwidget = QWidget() self.setCentralWidget(centralwidget) layout = QVBoxLayout(centralwidget) layout.setMargin(0) layout.setSpacing(0) middlewidget = QWidget() self.bigButtons = QWidget() bblo = QHBoxLayout(self.bigButtons) bblo.setMargin(0) bblo.setSpacing(0) self.bigButtons.setMinimumHeight(50) self.bigButtons.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) for name in ('Features', 'Sketch', 'Build', 'Dimension', 'Simulator'): btn = QPushButton(self.bigButtons) btn.setMaximumWidth(80) btn.setMinimumHeight(50) btn.setText(name) self.bigButtons.layout().addWidget(btn) self.bigButtons.hide() layout.addWidget(self.bigButtons) self.littleIcons = QWidget() self.littleIcons.setMinimumHeight(30) self.littleIcons.setMaximumHeight(30) lilo = QHBoxLayout(self.littleIcons) lilo.setMargin(0) lilo.setSpacing(0) pb = QPushButton(self.littleIcons) pb.setIcon(QIcon(icons + '/GroupPropDialog_image0.png')) self.connect(pb,SIGNAL("clicked()"),self.fileNew) lilo.addWidget(pb) for x in "1 2 4 5 6 7 8 18 42 10 43 150 93 94 97 137".split(): pb = QPushButton(self.littleIcons) pb.setIcon(QIcon(icons + '/MainWindowUI_image' + x + '.png')) lilo.addWidget(pb) layout.addWidget(self.littleIcons) layout.addWidget(middlewidget) self.layout = QGridLayout(middlewidget) self.layout.setMargin(0) self.layout.setSpacing(2) self.gridPosition = GridPosition() self.numParts = 0 self.show() explainWindow = AboutWindow("Select <b>Help->About</b>" " for instructions...", 200, 3) def removePartWindow(self, pw): self.layout.removeWidget(pw) self.gridPosition.removeWidget(pw) self.numParts -= 1 if self.numParts == 0: self.bigButtons.hide() def fileNew(self): if self.numParts == 0: self.bigButtons.show() self.numParts += 1 pw = PartWindow(self) row, col = self.gridPosition.next(pw) self.layout.addWidget(pw, row, col) def fileOpen(self): print "Let's pretend we're opening a file" def fileSave(self): print "Let's pretend we're saving a file" def helpAbout(self): AboutWindow(__doc__)
class RuleEditor(QDialog): # {{{ 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 = _('coloring') else: self.rule_kind = 'icon' rule_text = _('icon') self.setWindowIcon(QIcon(I('format-fill-color.png'))) self.setWindowTitle( _('Create/edit a column {0} rule').format(rule_text)) self.l = l = QGridLayout(self) self.setLayout(l) self.l1 = l1 = QLabel( _('Create a column {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(_('Set the')) l.addWidget(l2, 2, 0) if self.rule_kind == 'color': l.addWidget(QLabel(_('color'))) else: 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.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 == 'color': self.color_box = QComboBox(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) else: self.filename_box = QComboBox() self.filename_box.setInsertPolicy( self.filename_box.InsertAlphabetically) d = os.path.join(config_dir, 'cc_icons') self.icon_file_names = [] if os.path.exists(d): for icon_file in os.listdir(d): icon_file = lower(icon_file) if os.path.exists(os.path.join(d, icon_file)): if icon_file.endswith('.png'): self.icon_file_names.append(icon_file) self.icon_file_names.sort(key=sort_key) self.update_filename_box() l.addWidget(self.filename_box, 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) 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, self.color_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 0): 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.addItems(QColor.colorNames()) self.color_box.setCurrentIndex(0) self.update_color_label() self.color_box.currentIndexChanged.connect(self.update_color_label) else: self.filename_button.clicked.connect(self.filename_button_clicked) self.resize(self.sizeHint()) def update_filename_box(self): self.filename_box.clear() self.icon_file_names.sort(key=sort_key) self.filename_box.addItem('') self.filename_box.addItems(self.icon_file_names) for i, filename in enumerate(self.icon_file_names): icon = QIcon(os.path.join(config_dir, 'cc_icons', filename)) self.filename_box.setItemIcon(i + 1, icon) def update_color_label(self): pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) c = unicode(self.color_box.currentText()) self.color_label.setText(''' <span style="color: {c}; background-color: {bg1}"> {st} </span> <span style="color: {c}; background-color: {bg2}"> {st} </span> '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) def filename_button_clicked(self): try: path = choose_files(self, 'choose_category_icon', _('Select Icon'), filters=[('Images', ['png', 'gif', 'jpg', 'jpeg'])], all_files=False, select_only_single_file=True) if path: icon_path = path[0] icon_name = sanitize_file_name_unicode( os.path.splitext(os.path.basename(icon_path))[0] + '.png') if icon_name not in self.icon_file_names: self.icon_file_names.append(icon_name) self.update_filename_box() try: p = QIcon(icon_path).pixmap(QSize(128, 128)) d = os.path.join(config_dir, 'cc_icons') if not os.path.exists(os.path.join(d, icon_name)): if not os.path.exists(d): os.makedirs(d) with open(os.path.join(d, icon_name), 'wb') as f: f.write(pixmap_to_data(p, format='PNG')) except: import traceback traceback.print_exc() self.filename_box.setCurrentIndex( self.filename_box.findText(icon_name)) self.filename_box.adjustSize() except: import traceback traceback.print_exc() return def add_blank_condition(self): c = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(c) self.conditions_widget.layout().addWidget(c) def apply_rule(self, kind, col, rule): if kind == 'color': if rule.color: idx = self.color_box.findText(rule.color) if idx >= 0: self.color_box.setCurrentIndex(idx) else: self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1) if rule.color: idx = self.filename_box.findText(rule.color) if idx >= 0: self.filename_box.setCurrentIndex(idx) else: self.filename_box.setCurrentIndex(0) for i in range(self.column_box.count()): c = unicode(self.column_box.itemData(i).toString()) if col == c: self.column_box.setCurrentIndex(i) break for c in rule.conditions: ce = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(ce) self.conditions_widget.layout().addWidget(ce) try: ce.condition = c except: import traceback traceback.print_exc() def accept(self): if self.rule_kind != 'color': fname = lower(unicode(self.filename_box.currentText())) if not fname: error_dialog(self, _('No icon selected'), _('You must choose an icon for this rule'), show=True) return if self.validate(): QDialog.accept(self) def validate(self): r = Rule(self.fm) for c in self.conditions: condition = c.condition if condition is not None: try: r.add_condition(*condition) except Exception as e: import traceback error_dialog(self, _('Invalid condition'), _('One of the conditions for this rule is' ' invalid: <b>%s</b>') % e, det_msg=traceback.format_exc(), show=True) return False if len(r.conditions) < 1: error_dialog(self, _('No conditions'), _('You must specify at least one non-empty condition' ' for this rule'), show=True) return False return True @property def rule(self): r = Rule(self.fm) if self.rule_kind != 'color': r.color = unicode(self.filename_box.currentText()) else: r.color = unicode(self.color_box.currentText()) idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: condition = c.condition if condition is not None: r.add_condition(*condition) if self.rule_kind == 'icon': kind = unicode( self.kind_box.itemData( self.kind_box.currentIndex()).toString()) else: kind = 'color' return kind, col, r
class Preferences(QMainWindow): run_wizard_requested = pyqtSignal() def __init__(self, gui, initial_plugin=None, close_after_initial=False): QMainWindow.__init__(self, gui) self.gui = gui self.must_restart = False self.committed = False self.close_after_initial = close_after_initial self.resize(930, 720) nh, nw = min_available_height()-25, available_width()-10 if nh < 0: nh = 800 if nw < 0: nw = 600 nh = min(self.height(), nh) nw = min(self.width(), nw) self.resize(nw, nh) self.esc_action = QAction(self) self.addAction(self.esc_action) self.esc_action.setShortcut(QKeySequence(Qt.Key_Escape)) self.esc_action.triggered.connect(self.esc) geom = gprefs.get('preferences_window_geometry', None) if geom is not None: self.restoreGeometry(geom) # Center if islinux: self.move(gui.rect().center() - self.rect().center()) self.setWindowModality(Qt.WindowModal) self.setWindowTitle(__appname__ + ' - ' + _('Preferences')) self.setWindowIcon(QIcon(I('config.png'))) self.status_bar = StatusBar(self) self.setStatusBar(self.status_bar) self.stack = QStackedWidget(self) self.cw = QWidget(self) self.cw.setLayout(QVBoxLayout()) self.cw.layout().addWidget(self.stack) self.bb = QDialogButtonBox(QDialogButtonBox.Close) self.wizard_button = self.bb.addButton(_('Run welcome wizard'), self.bb.ActionRole) self.wizard_button.setIcon(QIcon(I('wizard.png'))) self.wizard_button.clicked.connect(self.run_wizard, type=Qt.QueuedConnection) self.cw.layout().addWidget(self.bb) self.bb.button(self.bb.Close).setDefault(True) self.bb.rejected.connect(self.close, type=Qt.QueuedConnection) self.setCentralWidget(self.cw) self.browser = Browser(self) self.browser.show_plugin.connect(self.show_plugin) self.stack.addWidget(self.browser) self.scroll_area = QScrollArea(self) self.stack.addWidget(self.scroll_area) self.scroll_area.setWidgetResizable(True) self.bar = QToolBar(self) self.addToolBar(self.bar) self.bar.setVisible(False) self.bar.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) self.bar.setMovable(False) self.bar.setFloatable(False) self.bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.apply_action = self.bar.addAction(QIcon(I('ok.png')), _('&Apply'), self.commit) self.cancel_action = self.bar.addAction(QIcon(I('window-close.png')), _('&Cancel'), self.cancel) self.bar_title = BarTitle(self.bar) self.bar.addWidget(self.bar_title) self.restore_action = self.bar.addAction(QIcon(I('clear_left.png')), _('Restore &defaults'), self.restore_defaults) for ac, tt in [('apply', _('Save changes')), ('cancel', _('Cancel and return to overview'))]: ac = getattr(self, ac+'_action') ac.setToolTip(tt) ac.setWhatsThis(tt) ac.setStatusTip(tt) for ch in self.bar.children(): if isinstance(ch, QToolButton): ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) self.stack.setCurrentIndex(0) if initial_plugin is not None: category, name = initial_plugin plugin = get_plugin(category, name) if plugin is not None: self.show_plugin(plugin) def run_wizard(self): self.close() self.run_wizard_requested.emit() def set_tooltips_for_labels(self): def process_child(child): for g in child.children(): if isinstance(g, QLabel): buddy = g.buddy() if buddy is not None and hasattr(buddy, 'toolTip'): htext = unicode(buddy.toolTip()).strip() etext = unicode(g.toolTip()).strip() if htext and not etext: g.setToolTip(htext) g.setWhatsThis(htext) else: process_child(g) process_child(self.showing_widget) def show_plugin(self, plugin): self.showing_widget = plugin.create_widget(self.scroll_area) self.showing_widget.genesis(self.gui) self.showing_widget.initialize() self.set_tooltips_for_labels() self.scroll_area.setWidget(self.showing_widget) self.stack.setCurrentIndex(1) self.showing_widget.show() self.setWindowTitle(__appname__ + ' - ' + _('Preferences') + ' - ' + plugin.gui_name) self.apply_action.setEnabled(False) self.showing_widget.changed_signal.connect(lambda : self.apply_action.setEnabled(True)) self.restore_action.setEnabled(self.showing_widget.supports_restoring_to_defaults) tt = self.showing_widget.restore_defaults_desc if not self.restore_action.isEnabled(): tt = _('Restoring to defaults not supported for') + ' ' + \ plugin.gui_name self.restore_action.setToolTip(textwrap.fill(tt)) self.restore_action.setWhatsThis(textwrap.fill(tt)) self.restore_action.setStatusTip(tt) self.bar_title.show_plugin(plugin) self.setWindowIcon(QIcon(plugin.icon)) self.bar.setVisible(True) self.bb.setVisible(False) def hide_plugin(self): self.showing_widget = QWidget(self.scroll_area) self.scroll_area.setWidget(self.showing_widget) self.setWindowTitle(__appname__ + ' - ' + _('Preferences')) self.bar.setVisible(False) self.stack.setCurrentIndex(0) self.setWindowIcon(QIcon(I('config.png'))) self.bb.setVisible(True) def esc(self, *args): if self.stack.currentIndex() == 1: self.cancel() elif self.stack.currentIndex() == 0: self.close() def commit(self, *args): try: must_restart = self.showing_widget.commit() except AbortCommit: return rc = self.showing_widget.restart_critical self.committed = True do_restart = False if must_restart: self.must_restart = True msg = _('Some of the changes you made require a restart.' ' Please restart calibre as soon as possible.') if rc: msg = _('The changes you have made require calibre be ' 'restarted immediately. You will not be allowed to ' 'set any more preferences, until you restart.') d = warning_dialog(self, _('Restart needed'), msg, 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 self.showing_widget.refresh_gui(self.gui) self.hide_plugin() if self.close_after_initial or (must_restart and rc) or do_restart: self.close() if do_restart: self.gui.quit(restart=True) def cancel(self, *args): if self.close_after_initial: self.close() else: self.hide_plugin() def restore_defaults(self, *args): self.showing_widget.restore_defaults() def closeEvent(self, *args): gprefs.set('preferences_window_geometry', bytearray(self.saveGeometry())) if self.committed: self.gui.must_restart_before_config = self.must_restart self.gui.tags_view.recount() self.gui.create_device_menu() self.gui.set_device_menu_items_state(bool(self.gui.device_connected)) self.gui.bars_manager.apply_settings() self.gui.bars_manager.update_bars() self.gui.build_context_menus() return QMainWindow.closeEvent(self, *args)
class RuleEditor(QDialog): # {{{ def __init__(self, fm, parent=None): QDialog.__init__(self, parent) self.fm = fm self.setWindowIcon(QIcon(I('format-fill-color.png'))) self.setWindowTitle(_('Create/edit a column coloring rule')) self.l = l = QGridLayout(self) self.setLayout(l) self.l1 = l1 = QLabel(_('Create a coloring rule by' ' filling in the boxes below')) l.addWidget(l1, 0, 0, 1, 5) self.f1 = QFrame(self) self.f1.setFrameShape(QFrame.HLine) l.addWidget(self.f1, 1, 0, 1, 5) self.l2 = l2 = QLabel(_('Set the color of the column:')) l.addWidget(l2, 2, 0) self.column_box = QComboBox(self) l.addWidget(self.column_box, 2, 1) self.l3 = l3 = QLabel(_('to')) l.addWidget(l3, 2, 2) self.color_box = QComboBox(self) self.color_label = QLabel('Sample text Sample text') self.color_label.setTextFormat(Qt.RichText) l.addWidget(self.color_box, 2, 3) l.addWidget(self.color_label, 2, 4) l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 5) self.l4 = l4 = QLabel( _('Only if the following conditions are all satisfied:')) l.addWidget(l4, 3, 0, 1, 6) self.scroll_area = sa = QScrollArea(self) sa.setMinimumHeight(300) sa.setMinimumWidth(950) sa.setWidgetResizable(True) l.addWidget(sa, 4, 0, 1, 6) self.add_button = b = QPushButton(QIcon(I('plus.png')), _('Add another condition')) l.addWidget(b, 5, 0, 1, 6) b.clicked.connect(self.add_blank_condition) self.l5 = l5 = QLabel(_('You can disable a condition by' ' blanking all of its boxes')) l.addWidget(l5, 6, 0, 1, 6) self.bb = bb = QDialogButtonBox( QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) l.addWidget(bb, 7, 0, 1, 6) self.conditions_widget = QWidget(self) sa.setWidget(self.conditions_widget) self.conditions_widget.setLayout(QVBoxLayout()) self.conditions_widget.layout().setAlignment(Qt.AlignTop) self.conditions = [] for b in (self.column_box, self.color_box): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(15) for key in sorted( displayable_columns(fm), key=sort_key): name = fm[key]['name'] if name: self.column_box.addItem(key, key) self.column_box.setCurrentIndex(0) self.color_box.addItems(QColor.colorNames()) self.color_box.setCurrentIndex(0) self.update_color_label() self.color_box.currentIndexChanged.connect(self.update_color_label) self.resize(self.sizeHint()) def update_color_label(self): pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) c = unicode(self.color_box.currentText()) self.color_label.setText(''' <span style="color: {c}; background-color: {bg1}"> {st} </span> <span style="color: {c}; background-color: {bg2}"> {st} </span> '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) def add_blank_condition(self): c = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(c) self.conditions_widget.layout().addWidget(c) def apply_rule(self, col, rule): for i in range(self.column_box.count()): c = unicode(self.column_box.itemData(i).toString()) if col == c: self.column_box.setCurrentIndex(i) break if rule.color: idx = self.color_box.findText(rule.color) if idx >= 0: self.color_box.setCurrentIndex(idx) for c in rule.conditions: ce = ConditionEditor(self.fm, parent=self.conditions_widget) self.conditions.append(ce) self.conditions_widget.layout().addWidget(ce) try: ce.condition = c except: import traceback traceback.print_exc() def accept(self): if self.validate(): QDialog.accept(self) def validate(self): r = Rule(self.fm) for c in self.conditions: condition = c.condition if condition is not None: try: r.add_condition(*condition) except Exception as e: import traceback error_dialog(self, _('Invalid condition'), _('One of the conditions for this rule is' ' invalid: <b>%s</b>')%e, det_msg=traceback.format_exc(), show=True) return False if len(r.conditions) < 1: error_dialog(self, _('No conditions'), _('You must specify at least one non-empty condition' ' for this rule'), show=True) return False return True @property def rule(self): r = Rule(self.fm) r.color = unicode(self.color_box.currentText()) idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: condition = c.condition if condition is not None: r.add_condition(*condition) return col, r