class Dialog(QDialog): def __init__(self, title, widget=None, closeButton=True, keySequence=None, isDialog=False, icon=None): QDialog.__init__(self, ctx.mainScreen) self.setObjectName("dialog") self.isDialog = isDialog self.layout = QVBoxLayout() self.setLayout(self.layout) self.wlayout= QHBoxLayout() if icon: self.setStyleSheet("""QDialog QLabel{ margin-left:16px;margin-right:10px} QDialog#dialog {background-image:url(':/images/%s.png'); background-repeat:no-repeat; background-position: top left; padding-left:500px;} """ % icon) self.windowTitle = windowTitle(self, closeButton) self.setTitle(title) self.layout.setMargin(0) self.layout.addWidget(self.windowTitle) if widget: self.addWidget(widget) QObject.connect(widget, SIGNAL("finished(int)"), self.reject) QObject.connect(widget, SIGNAL("resizeDialog(int,int)"), self.resize) if closeButton: QObject.connect(self.windowTitle.pushButton, SIGNAL("clicked()"), self.reject) if keySequence: shortCut = QShortcut(keySequence, self) QObject.connect(shortCut, SIGNAL("activated()"), self.reject) QMetaObject.connectSlotsByName(self) self.resize(10,10) def setTitle(self, title): self.windowTitle.label.setText(title) def addWidget(self, widget): self.content = widget self.wlayout.addWidget(self.content) if self.isDialog: widget.setStyleSheet("QMessageBox { background:none }") self.layout.addItem(QSpacerItem(10, 10, QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)) self.layout.setContentsMargins(0, 0, 0, 8) self.layout.addLayout(self.wlayout) def setCentered(self): self.move(ctx.mainScreen.width()/2 - self.width()/2, ctx.mainScreen.height()/2 - self.height()/2) def exec_(self): QTimer.singleShot(0, self.setCentered) return QDialog.exec_(self)
def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext=u""): QDialog.__init__(self, parent) self.parent = parent self.key_type_name = key_type_name self.plugin_keys = plugin_keys self.create_key = create_key self.keyfile_ext = keyfile_ext self.import_key = (keyfile_ext != u"") self.binary_file = (key_type_name == u"Adobe Digital Editions Key") self.json_file = (key_type_name == u"Kindle for Mac and PC Key") self.setWindowTitle("{0} {1}: Manage {2}s".format( PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) # Start Qt Gui dialog layout layout = QVBoxLayout(self) self.setLayout(layout) help_layout = QHBoxLayout() layout.addLayout(help_layout) # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self) help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_label.setAlignment(Qt.AlignRight) help_label.linkActivated.connect(self.help_link_activated) help_layout.addWidget(help_label) keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) layout.addWidget(keys_group_box) keys_group_box_layout = QHBoxLayout() keys_group_box.setLayout(keys_group_box_layout) self.listy = QListWidget(self) self.listy.setToolTip( u"{0}s that will be used to decrypt ebooks".format( self.key_type_name)) self.listy.setSelectionMode(QAbstractItemView.SingleSelection) self.populate_list() keys_group_box_layout.addWidget(self.listy) button_layout = QVBoxLayout() keys_group_box_layout.addLayout(button_layout) self._add_key_button = QtGui.QToolButton(self) self._add_key_button.setToolTip(u"Create new {0}".format( self.key_type_name)) self._add_key_button.setIcon(QIcon(I('plus.png'))) self._add_key_button.clicked.connect(self.add_key) button_layout.addWidget(self._add_key_button) self._delete_key_button = QtGui.QToolButton(self) self._delete_key_button.setToolTip(_(u"Delete highlighted key")) self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) self._delete_key_button.clicked.connect(self.delete_key) button_layout.addWidget(self._delete_key_button) if type(self.plugin_keys) == dict: self._rename_key_button = QtGui.QToolButton(self) self._rename_key_button.setToolTip(_(u"Rename highlighted key")) self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) self._rename_key_button.clicked.connect(self.rename_key) button_layout.addWidget(self._rename_key_button) self.export_key_button = QtGui.QToolButton(self) self.export_key_button.setToolTip( u"Save highlighted key to a .{0} file".format( self.keyfile_ext)) self.export_key_button.setIcon(QIcon(I('save.png'))) self.export_key_button.clicked.connect(self.export_key) button_layout.addWidget(self.export_key_button) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) layout.addSpacing(5) migrate_layout = QHBoxLayout() layout.addLayout(migrate_layout) if self.import_key: migrate_layout.setAlignment(Qt.AlignJustify) self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self) self.migrate_btn.setToolTip( u"Import *.{0} files (created using other tools).".format( self.keyfile_ext)) self.migrate_btn.clicked.connect(self.migrate_wrapper) migrate_layout.addWidget(self.migrate_btn) migrate_layout.addStretch() self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.close) migrate_layout.addWidget(self.button_box) self.resize(self.sizeHint())
def __init__(self, plugin): DefaultConfigWidget.__init__(self, plugin) c = plugin_prefs[STORE_NAME] all_tags = get_current_db().all_tags() self.gb.setMaximumHeight(80) genre_group_box = QGroupBox('Shelfari genre to calibre tag mappings', self) self.l.addWidget(genre_group_box, self.l.rowCount(), 0, 1, 2) genre_group_box_layout = QVBoxLayout() genre_group_box.setLayout(genre_group_box_layout) tags_layout = QHBoxLayout() genre_group_box_layout.addLayout(tags_layout) self.edit_table = GenreTagMappingsTableWidget(self, all_tags) tags_layout.addWidget(self.edit_table) button_layout = QVBoxLayout() tags_layout.addLayout(button_layout) add_mapping_button = QtGui.QToolButton(self) add_mapping_button.setToolTip('Add genre mapping') add_mapping_button.setIcon(QIcon(I('plus.png'))) add_mapping_button.clicked.connect(self.add_mapping) button_layout.addWidget(add_mapping_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem1) remove_mapping_button = QtGui.QToolButton(self) remove_mapping_button.setToolTip('Delete genre mapping') remove_mapping_button.setIcon(QIcon(I('minus.png'))) remove_mapping_button.clicked.connect(self.delete_mapping) button_layout.addWidget(remove_mapping_button) spacerItem3 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem3) rename_genre_button = QtGui.QToolButton(self) rename_genre_button.setToolTip('Rename Goodreads genre') rename_genre_button.setIcon(QIcon(I('edit-undo.png'))) rename_genre_button.clicked.connect(self.rename_genre) button_layout.addWidget(rename_genre_button) spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem2) reset_defaults_button = QtGui.QToolButton(self) reset_defaults_button.setToolTip('Reset to plugin default mappings') reset_defaults_button.setIcon(QIcon(I('clear_left.png'))) reset_defaults_button.clicked.connect(self.reset_to_defaults) button_layout.addWidget(reset_defaults_button) self.l.setRowStretch(self.l.rowCount()-1, 2) other_group_box = QGroupBox('Other options', self) self.l.addWidget(other_group_box, self.l.rowCount(), 0, 1, 2) other_group_box_layout = QVBoxLayout() other_group_box.setLayout(other_group_box_layout) self.get_editions_checkbox = QCheckBox('Scan multiple editions for title/author searches (slower)', self) self.get_editions_checkbox.setToolTip('When checked will perform an additional search to scan the top ranked\n' 'Shelfari editions (if available) to exclude audiobook editions.\n' 'Without this enabled you will get a faster search, using the "best".\n' 'edition ranked by Shelfari which can in some cases be an audiobook.') self.get_editions_checkbox.setChecked(c[KEY_GET_EDITIONS]) other_group_box_layout.addWidget(self.get_editions_checkbox) self.all_authors_checkbox = QCheckBox('Get all contributing authors (e.g. illustrators, series editors etc)', self) self.all_authors_checkbox.setToolTip('Shelfari for some books will list all of the contributing authors and\n' 'the type of contribution like (Editor), (Illustrator) etc.\n\n' 'When this option is checked, all contributing authors are retrieved.\n\n' 'When unchecked (default) only the primary author(s) are returned which\n' 'are those that either have no contribution type specified, or have the\n' 'value of (Shelfari Author).\n\n' 'If there is no primary author then only those with the same contribution\n' 'type as the first author are returned.\n' 'e.g. "A, B (Illustrator)" will return author A\n' 'e.g. "A (Shelfari Author)" will return author A\n' 'e.g. "A (Editor), B (Editor), C (Illustrator)" will return authors A & B\n' 'e.g. "A (Editor), B (Series Editor)" will return author A\n') self.all_authors_checkbox.setChecked(c[KEY_GET_ALL_AUTHORS]) other_group_box_layout.addWidget(self.all_authors_checkbox) self.edit_table.populate_table(c[KEY_GENRE_MAPPINGS])
def __init__(self, parent=None, desc=None, name=None, modal=0, fl=0, env=None, type="QDialog"): if env is None: import foundation.env as env # this is a little weird... probably it'll be ok, and logically it seems correct. self.desc = desc self.typ = type if type == "QDialog": QDialog.__init__(self, parent, name, modal, fl) elif type == "QTextEdit": QTextEdit.__init__(self, parent, name) elif type == "QFrame": QFrame.__init__(self, parent, name) else: print "don't know about type == %r" % (type, ) self.image1 = QPixmap() self.image1.loadFromData(image1_data, "PNG") # should be: title_icon #### self.image3 = QPixmap() self.image3.loadFromData(image3_data, "PNG") self.image4 = QPixmap() self.image4.loadFromData(image4_data, "PNG") self.image5 = QPixmap() self.image5.loadFromData(image5_data, "PNG") self.image6 = QPixmap() self.image6.loadFromData(image6_data, "PNG") self.image7 = QPixmap() self.image7.loadFromData(image7_data, "PNG") self.image0 = QPixmap(image0_data) # should be: border_icon #### self.image2 = QPixmap(image2_data) # should be: sponsor_pixmap #### try: ####@@@@ title_icon_name = self.desc.options.get('title_icon') border_icon_name = self.desc.options.get('border_icon') if title_icon_name: self.image1 = imagename_to_pixmap( title_icon_name) ###@@@ pass icon_path ###@@@ import imagename_to_pixmap or use env function # or let that func itself be an arg, or have an env arg for it ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset) ###e use iconset instead? if border_icon_name: self.image0 = imagename_to_pixmap(border_icon_name) except: print_compact_traceback( "bug in icon-setting code, using fallback icons: ") pass if not name: self.setName("parameter_dialog_or_frame") ### ###k guess this will need: if type == 'QDialog' self.setIcon(self.image0) # should be: border_icon #### nanotube_dialogLayout = QVBoxLayout(self, 0, 0, "nanotube_dialogLayout") self.heading_frame = QFrame(self, "heading_frame") self.heading_frame.setPaletteBackgroundColor(QColor(122, 122, 122)) self.heading_frame.setFrameShape(QFrame.NoFrame) self.heading_frame.setFrameShadow(QFrame.Plain) heading_frameLayout = QHBoxLayout(self.heading_frame, 0, 3, "heading_frameLayout") self.heading_pixmap = QLabel(self.heading_frame, "heading_pixmap") self.heading_pixmap.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed, 0, 0, self.heading_pixmap.sizePolicy().hasHeightForWidth())) self.heading_pixmap.setPixmap( self.image1) # should be: title_icon #### self.heading_pixmap.setScaledContents(1) heading_frameLayout.addWidget(self.heading_pixmap) self.heading_label = QLabel(self.heading_frame, "heading_label") self.heading_label.setPaletteForegroundColor(QColor(255, 255, 255)) heading_label_font = QFont(self.heading_label.font()) heading_label_font.setPointSize(12) heading_label_font.setBold(1) self.heading_label.setFont(heading_label_font) heading_frameLayout.addWidget(self.heading_label) nanotube_dialogLayout.addWidget(self.heading_frame) self.body_frame = QFrame(self, "body_frame") self.body_frame.setFrameShape(QFrame.StyledPanel) self.body_frame.setFrameShadow(QFrame.Raised) body_frameLayout = QVBoxLayout(self.body_frame, 3, 3, "body_frameLayout") self.sponsor_frame = QFrame(self.body_frame, "sponsor_frame") self.sponsor_frame.setPaletteBackgroundColor(QColor(255, 255, 255)) self.sponsor_frame.setFrameShape(QFrame.StyledPanel) self.sponsor_frame.setFrameShadow(QFrame.Raised) sponsor_frameLayout = QHBoxLayout(self.sponsor_frame, 0, 0, "sponsor_frameLayout") self.sponsor_btn = QPushButton(self.sponsor_frame, "sponsor_btn") self.sponsor_btn.setAutoDefault(0) #bruce 060703 bugfix self.sponsor_btn.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred, 0, 0, self.sponsor_btn.sizePolicy().hasHeightForWidth())) self.sponsor_btn.setPaletteBackgroundColor(QColor(255, 255, 255)) self.sponsor_btn.setPixmap( self.image2 ) # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor] self.sponsor_btn.setFlat(1) sponsor_frameLayout.addWidget(self.sponsor_btn) body_frameLayout.addWidget(self.sponsor_frame) layout59 = QHBoxLayout(None, 0, 6, "layout59") left_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout59.addItem(left_spacer) self.done_btn = QToolButton(self.body_frame, "done_btn") self.done_btn.setIcon(QIcon(self.image3)) layout59.addWidget(self.done_btn) self.abort_btn = QToolButton(self.body_frame, "abort_btn") self.abort_btn.setIcon(QIcon(self.image4)) layout59.addWidget(self.abort_btn) self.preview_btn = QToolButton(self.body_frame, "preview_btn") self.preview_btn.setIcon(QIcon(self.image5)) layout59.addWidget(self.preview_btn) self.whatsthis_btn = QToolButton(self.body_frame, "whatsthis_btn") self.whatsthis_btn.setIcon(QIcon(self.image6)) layout59.addWidget(self.whatsthis_btn) right_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout59.addItem(right_spacer) body_frameLayout.addLayout(layout59) self.groups = [] self.param_getters = { } # map from param name to get-function (which gets current value out of its widget or controller) for group_desc in self.desc.kids('group'): # == start parameters_grpbox ### this will differ for Windows style header_refs = [ ] # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs) self.parameters_grpbox = QGroupBox(self.body_frame, "parameters_grpbox") self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel) self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken) self.parameters_grpbox.setMargin(0) self.parameters_grpbox.setColumnLayout(0, Qt.Vertical) self.parameters_grpbox.layout().setSpacing(1) self.parameters_grpbox.layout().setMargin(4) parameters_grpboxLayout = QVBoxLayout( self.parameters_grpbox.layout()) parameters_grpboxLayout.setAlignment(Qt.AlignTop) layout20 = QHBoxLayout(None, 0, 6, "layout20") self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox, "nt_parameters_grpbtn") self.nt_parameters_grpbtn.setSizePolicy( QSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed, 0, 0, self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth()) ) self.nt_parameters_grpbtn.setMaximumSize(QSize(16, 16)) self.nt_parameters_grpbtn.setAutoDefault(0) self.nt_parameters_grpbtn.setIcon(QIcon( self.image7)) ### not always right, but doesn't matter self.nt_parameters_grpbtn.setFlat(1) layout20.addWidget(self.nt_parameters_grpbtn) self.parameters_grpbox_label = QLabel(self.parameters_grpbox, "parameters_grpbox_label") self.parameters_grpbox_label.setSizePolicy( QSizePolicy( QSizePolicy.Preferred, QSizePolicy.Minimum, 0, 0, self.parameters_grpbox_label.sizePolicy(). hasHeightForWidth())) self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter) layout20.addWidget(self.parameters_grpbox_label) gbx_spacer1 = QSpacerItem(67, 16, QSizePolicy.Expanding, QSizePolicy.Minimum) layout20.addItem(gbx_spacer1) parameters_grpboxLayout.addLayout(layout20) nt_parameters_body_layout = QGridLayout( None, 1, 1, 0, 6, "nt_parameters_body_layout" ) ### what is 6 -- is it related to number of items??? # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime. # == start its kids # will use from above: self.parameters_grpbox, nt_parameters_body_layout nextrow = 0 # which row of the QGridLayout to start filling next (loop variable) hidethese = [ ] # set of objects to hide or show, when this group is closed or opened for param in group_desc.kids('parameter'): # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that, # so we redundantly test for this here. getter = None paramname = None # set these for use by uniform code at the end (e.g. for tooltips) editfield = None label = None if param.isa('parameter'): label = QLabel(self.parameters_grpbox, "members_label") label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight) nt_parameters_body_layout.addWidget(label, nextrow, 0) hidethese.append(label) thisrow = nextrow nextrow += 1 #e following should be known in a place that knows the input language, not here paramname = param.options.get('name') or ( param.args and param.args[0]) or "?" paramlabel = param.options.get( 'label' ) or paramname ##e wrong, label "" or none ought to be possible # QtGui.QApplication.translate(self.__class__.__name__, "xyz") label.setText( QtGui.QApplication.translate(self.__class__.__name__, paramlabel)) if param.isa('parameter', widget='combobox', type=('str', None)): self.members_combox = QComboBox( 0, self.parameters_grpbox, "members_combox") ###k what's 0? editfield = self.members_combox #### it probably needs a handler class, and then that could do this setup self.members_combox.clear() default = param.options.get( 'default', None) # None is not equal to any string thewidgetkid = param.kids( 'widget' )[-1] # kluge; need to think what the desc method for this should be for item in thewidgetkid.kids('item'): itemval = item.args[0] itemtext = itemval self.members_combox.insertItem( QtGui.QApplication.translate( self.__class__.__name__, itemtext)) #k __tr ok?? if itemval == default: #k or itemtext? pass ##k i find no setItem in our py code, so not sure yet what to do for this. nt_parameters_body_layout.addWidget( self.members_combox, thisrow, 1) hidethese.append(self.members_combox) getter = (lambda combobox=self.members_combox: str( combobox.currentText())) ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table # (though whether __tr is good here might depend on what it's used for) elif param.isa('parameter', widget=('lineedit', None), type=('str', None)): # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither. # (i.e. if you say parameter and nothing else, it's str lineedit by default.) self.length_linedit = QLineEdit(self.parameters_grpbox, "length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget( self.length_linedit, thisrow, 1) hidethese.append(self.length_linedit) default = str(param.options.get('default', "")) self.length_linedit.setText( QtGui.QApplication.translate(self.__class__.__name__, default)) # __tr ok? getter = (lambda lineedit=self.length_linedit: str( lineedit.text())) elif param.isa('parameter', widget=('lineedit', None), type='float'): self.length_linedit = QLineEdit(self.parameters_grpbox, "length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget( self.length_linedit, thisrow, 1) hidethese.append(self.length_linedit) controller = FloatLineeditController_Qt( self, param, self.length_linedit) header_refs.append(controller) getter = controller.get_value elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \ param.isa('parameter', widget = ('spinbox'), type = None): self.chirality_N_spinbox = QSpinBox( self.parameters_grpbox, "chirality_N_spinbox" ) # was chirality_m_spinbox, now chirality_N_spinbox editfield = self.chirality_N_spinbox ### seems like Qt defaults for min and max are 0,100 -- way too small a range! if param.options.has_key('min') or 1: self.chirality_N_spinbox.setMinimum( param.options.get('min', -999999999)) # was 0 if param.options.has_key('max') or 1: self.chirality_N_spinbox.setMaximum( param.options.get( 'max', +999999999)) # wasn't in egcode, but needed self.chirality_N_spinbox.setValue( param.options.get('default', 0)) # was 5 ##e note: i suspect this default 0 should come from something that knows this desc grammar. suffix = param.options.get('suffix', '') if suffix: self.chirality_N_spinbox.setSuffix( QtGui.QApplication.translate( self.__class__.__name__, suffix)) else: self.chirality_N_spinbox.setSuffix( QString.null) # probably not needed nt_parameters_body_layout.addWidget( self.chirality_N_spinbox, thisrow, 1) hidethese.append(self.chirality_N_spinbox) getter = self.chirality_N_spinbox.value # note: it also has .text, which includes suffix else: print "didn't match:", param ###e improve this # things done the same way for all kinds of param-editing widgets if 1: #bruce 060703 moved this down here, as bugfix # set tooltip (same one for editfield and label) tooltip = param.options.get('tooltip', '') ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid? ###k QToolTip appropriateness; tooltip option might be entirely untested if tooltip and label: QToolTip.add( label, QtGui.QApplication.translate( self.__class__.__name__, tooltip)) if tooltip and editfield: QToolTip.add( editfield, QtGui.QApplication.translate( self.__class__.__name__, tooltip) ) ##k ok?? review once not all params have same-row labels. if getter and paramname and paramname != '?': self.param_getters[paramname] = getter ### also bind these params to actions... continue # next param header_refs.extend([ self.parameters_grpbox, self.nt_parameters_grpbtn, self.parameters_grpbox_label ]) # now create the logic/control object for the group group = CollapsibleGroupController_Qt(self, group_desc, header_refs, hidethese, self.nt_parameters_grpbtn) ### maybe ask env for the class to use for this? self.groups.append( group ) ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount. # from languageChange: if 1: # i don't know if these are needed: self.parameters_grpbox.setTitle(QString.null) self.nt_parameters_grpbtn.setText(QString.null) self.parameters_grpbox_label.setText( QtGui.QApplication.translate( self.__class__.__name__, group_desc.args[0])) # was "Nanotube Parameters" ##e note that it's questionable in the syntax design for this property of a group (overall group label) # to be in that position (desc arg 0). # == end its kids parameters_grpboxLayout.addLayout(nt_parameters_body_layout) body_frameLayout.addWidget(self.parameters_grpbox) # == end parameters groupbox continue # next group nanotube_dialogLayout.addWidget(self.body_frame) spacer14 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) nanotube_dialogLayout.addItem(spacer14) layout42 = QHBoxLayout(None, 4, 6, "layout42") btm_spacer = QSpacerItem(59, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout42.addItem(btm_spacer) self.cancel_btn = QPushButton(self, "cancel_btn") self.cancel_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.cancel_btn) self.ok_btn = QPushButton(self, "ok_btn") self.ok_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.ok_btn) nanotube_dialogLayout.addLayout(layout42) self.languageChange() self.resize( QSize(246, 618).expandedTo(self.minimumSizeHint()) ) ### this size will need to be adjusted (guess -- it's only place overall size is set) qt4todo('self.clearWState(Qt.WState_Polished)') ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) #### # new: for button, methodname in ( (self.sponsor_btn, 'do_sponsor_btn'), #e generalize to more than one sponsor button (self.done_btn, 'do_done_btn'), (self.abort_btn, 'do_abort_btn'), (self.preview_btn, 'do_preview_btn'), (self.whatsthis_btn, 'do_whatsthis_btn'), (self.cancel_btn, 'do_cancel_btn'), (self.ok_btn, 'do_ok_btn')): if hasattr(self, methodname): self.connect(button, SIGNAL("clicked()"), getattr(self, methodname)) return
def __init__(self, parent = None, desc = None, name = None, modal = 0, fl = 0, env = None, type = "QDialog"): if env is None: import foundation.env as env # this is a little weird... probably it'll be ok, and logically it seems correct. self.desc = desc self.typ = type if type == "QDialog": QDialog.__init__(self,parent,name,modal,fl) elif type == "QTextEdit": QTextEdit.__init__(self, parent, name) elif type == "QFrame": QFrame.__init__(self,parent,name) else: print "don't know about type == %r" % (type,) self.image1 = QPixmap() self.image1.loadFromData(image1_data,"PNG") # should be: title_icon #### self.image3 = QPixmap() self.image3.loadFromData(image3_data,"PNG") self.image4 = QPixmap() self.image4.loadFromData(image4_data,"PNG") self.image5 = QPixmap() self.image5.loadFromData(image5_data,"PNG") self.image6 = QPixmap() self.image6.loadFromData(image6_data,"PNG") self.image7 = QPixmap() self.image7.loadFromData(image7_data,"PNG") self.image0 = QPixmap(image0_data) # should be: border_icon #### self.image2 = QPixmap(image2_data) # should be: sponsor_pixmap #### try: ####@@@@ title_icon_name = self.desc.options.get('title_icon') border_icon_name = self.desc.options.get('border_icon') if title_icon_name: self.image1 = imagename_to_pixmap(title_icon_name) ###@@@ pass icon_path ###@@@ import imagename_to_pixmap or use env function # or let that func itself be an arg, or have an env arg for it ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset) ###e use iconset instead? if border_icon_name: self.image0 = imagename_to_pixmap(border_icon_name) except: print_compact_traceback("bug in icon-setting code, using fallback icons: ") pass if not name: self.setName("parameter_dialog_or_frame") ### ###k guess this will need: if type == 'QDialog' self.setIcon(self.image0) # should be: border_icon #### nanotube_dialogLayout = QVBoxLayout(self,0,0,"nanotube_dialogLayout") self.heading_frame = QFrame(self,"heading_frame") self.heading_frame.setPaletteBackgroundColor(QColor(122,122,122)) self.heading_frame.setFrameShape(QFrame.NoFrame) self.heading_frame.setFrameShadow(QFrame.Plain) heading_frameLayout = QHBoxLayout(self.heading_frame,0,3,"heading_frameLayout") self.heading_pixmap = QLabel(self.heading_frame,"heading_pixmap") self.heading_pixmap.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.heading_pixmap.sizePolicy().hasHeightForWidth())) self.heading_pixmap.setPixmap(self.image1) # should be: title_icon #### self.heading_pixmap.setScaledContents(1) heading_frameLayout.addWidget(self.heading_pixmap) self.heading_label = QLabel(self.heading_frame,"heading_label") self.heading_label.setPaletteForegroundColor(QColor(255,255,255)) heading_label_font = QFont(self.heading_label.font()) heading_label_font.setPointSize(12) heading_label_font.setBold(1) self.heading_label.setFont(heading_label_font) heading_frameLayout.addWidget(self.heading_label) nanotube_dialogLayout.addWidget(self.heading_frame) self.body_frame = QFrame(self,"body_frame") self.body_frame.setFrameShape(QFrame.StyledPanel) self.body_frame.setFrameShadow(QFrame.Raised) body_frameLayout = QVBoxLayout(self.body_frame,3,3,"body_frameLayout") self.sponsor_frame = QFrame(self.body_frame,"sponsor_frame") self.sponsor_frame.setPaletteBackgroundColor(QColor(255,255,255)) self.sponsor_frame.setFrameShape(QFrame.StyledPanel) self.sponsor_frame.setFrameShadow(QFrame.Raised) sponsor_frameLayout = QHBoxLayout(self.sponsor_frame,0,0,"sponsor_frameLayout") self.sponsor_btn = QPushButton(self.sponsor_frame,"sponsor_btn") self.sponsor_btn.setAutoDefault(0) #bruce 060703 bugfix self.sponsor_btn.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Preferred,0,0,self.sponsor_btn.sizePolicy().hasHeightForWidth())) self.sponsor_btn.setPaletteBackgroundColor(QColor(255,255,255)) self.sponsor_btn.setPixmap(self.image2) # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor] self.sponsor_btn.setFlat(1) sponsor_frameLayout.addWidget(self.sponsor_btn) body_frameLayout.addWidget(self.sponsor_frame) layout59 = QHBoxLayout(None,0,6,"layout59") left_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout59.addItem(left_spacer) self.done_btn = QToolButton(self.body_frame,"done_btn") self.done_btn.setIcon(QIcon(self.image3)) layout59.addWidget(self.done_btn) self.abort_btn = QToolButton(self.body_frame,"abort_btn") self.abort_btn.setIcon(QIcon(self.image4)) layout59.addWidget(self.abort_btn) self.preview_btn = QToolButton(self.body_frame,"preview_btn") self.preview_btn.setIcon(QIcon(self.image5)) layout59.addWidget(self.preview_btn) self.whatsthis_btn = QToolButton(self.body_frame,"whatsthis_btn") self.whatsthis_btn.setIcon(QIcon(self.image6)) layout59.addWidget(self.whatsthis_btn) right_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout59.addItem(right_spacer) body_frameLayout.addLayout(layout59) self.groups = [] self.param_getters = {} # map from param name to get-function (which gets current value out of its widget or controller) for group_desc in self.desc.kids('group'): # == start parameters_grpbox ### this will differ for Windows style header_refs = [] # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs) self.parameters_grpbox = QGroupBox(self.body_frame,"parameters_grpbox") self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel) self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken) self.parameters_grpbox.setMargin(0) self.parameters_grpbox.setColumnLayout(0,Qt.Vertical) self.parameters_grpbox.layout().setSpacing(1) self.parameters_grpbox.layout().setMargin(4) parameters_grpboxLayout = QVBoxLayout(self.parameters_grpbox.layout()) parameters_grpboxLayout.setAlignment(Qt.AlignTop) layout20 = QHBoxLayout(None,0,6,"layout20") self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox,"nt_parameters_grpbtn") self.nt_parameters_grpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Minimum,QSizePolicy.Fixed,0,0,self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth())) self.nt_parameters_grpbtn.setMaximumSize(QSize(16,16)) self.nt_parameters_grpbtn.setAutoDefault(0) self.nt_parameters_grpbtn.setIcon(QIcon(self.image7)) ### not always right, but doesn't matter self.nt_parameters_grpbtn.setFlat(1) layout20.addWidget(self.nt_parameters_grpbtn) self.parameters_grpbox_label = QLabel(self.parameters_grpbox,"parameters_grpbox_label") self.parameters_grpbox_label.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Minimum,0,0,self.parameters_grpbox_label.sizePolicy().hasHeightForWidth())) self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter) layout20.addWidget(self.parameters_grpbox_label) gbx_spacer1 = QSpacerItem(67,16,QSizePolicy.Expanding,QSizePolicy.Minimum) layout20.addItem(gbx_spacer1) parameters_grpboxLayout.addLayout(layout20) nt_parameters_body_layout = QGridLayout(None,1,1,0,6,"nt_parameters_body_layout") ### what is 6 -- is it related to number of items??? # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime. # == start its kids # will use from above: self.parameters_grpbox, nt_parameters_body_layout nextrow = 0 # which row of the QGridLayout to start filling next (loop variable) hidethese = [] # set of objects to hide or show, when this group is closed or opened for param in group_desc.kids('parameter'): # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that, # so we redundantly test for this here. getter = None paramname = None # set these for use by uniform code at the end (e.g. for tooltips) editfield = None label = None if param.isa('parameter'): label = QLabel(self.parameters_grpbox,"members_label") label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight) nt_parameters_body_layout.addWidget(label,nextrow,0) hidethese.append(label) thisrow = nextrow nextrow += 1 #e following should be known in a place that knows the input language, not here paramname = param.options.get('name') or (param.args and param.args[0]) or "?" paramlabel = param.options.get('label') or paramname ##e wrong, label "" or none ought to be possible # QtGui.QApplication.translate(self.__class__.__name__, "xyz") label.setText(QtGui.QApplication.translate(self.__class__.__name__, paramlabel)) if param.isa('parameter', widget = 'combobox', type = ('str',None)): self.members_combox = QComboBox(0,self.parameters_grpbox,"members_combox") ###k what's 0? editfield = self.members_combox #### it probably needs a handler class, and then that could do this setup self.members_combox.clear() default = param.options.get('default', None) # None is not equal to any string thewidgetkid = param.kids('widget')[-1] # kluge; need to think what the desc method for this should be for item in thewidgetkid.kids('item'): itemval = item.args[0] itemtext = itemval self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, itemtext)) #k __tr ok?? if itemval == default: #k or itemtext? pass ##k i find no setItem in our py code, so not sure yet what to do for this. nt_parameters_body_layout.addWidget(self.members_combox,thisrow,1) hidethese.append(self.members_combox) getter = (lambda combobox = self.members_combox: str(combobox.currentText())) ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table # (though whether __tr is good here might depend on what it's used for) elif param.isa('parameter', widget = ('lineedit', None), type = ('str',None)): # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither. # (i.e. if you say parameter and nothing else, it's str lineedit by default.) self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1) hidethese.append(self.length_linedit) default = str(param.options.get('default', "")) self.length_linedit.setText(QtGui.QApplication.translate(self.__class__.__name__, default)) # __tr ok? getter = (lambda lineedit = self.length_linedit: str(lineedit.text())) elif param.isa('parameter', widget = ('lineedit', None), type = 'float'): self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1) hidethese.append(self.length_linedit) controller = FloatLineeditController_Qt(self, param, self.length_linedit) header_refs.append(controller) getter = controller.get_value elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \ param.isa('parameter', widget = ('spinbox'), type = None): self.chirality_N_spinbox = QSpinBox(self.parameters_grpbox,"chirality_N_spinbox") # was chirality_m_spinbox, now chirality_N_spinbox editfield = self.chirality_N_spinbox ### seems like Qt defaults for min and max are 0,100 -- way too small a range! if param.options.has_key('min') or 1: self.chirality_N_spinbox.setMinimum(param.options.get('min', -999999999)) # was 0 if param.options.has_key('max') or 1: self.chirality_N_spinbox.setMaximum(param.options.get('max', +999999999)) # wasn't in egcode, but needed self.chirality_N_spinbox.setValue(param.options.get('default', 0)) # was 5 ##e note: i suspect this default 0 should come from something that knows this desc grammar. suffix = param.options.get('suffix', '') if suffix: self.chirality_N_spinbox.setSuffix(QtGui.QApplication.translate(self.__class__.__name__, suffix)) else: self.chirality_N_spinbox.setSuffix(QString.null) # probably not needed nt_parameters_body_layout.addWidget(self.chirality_N_spinbox,thisrow,1) hidethese.append(self.chirality_N_spinbox) getter = self.chirality_N_spinbox.value # note: it also has .text, which includes suffix else: print "didn't match:",param ###e improve this # things done the same way for all kinds of param-editing widgets if 1: #bruce 060703 moved this down here, as bugfix # set tooltip (same one for editfield and label) tooltip = param.options.get('tooltip', '') ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid? ###k QToolTip appropriateness; tooltip option might be entirely untested if tooltip and label: QToolTip.add(label, QtGui.QApplication.translate(self.__class__.__name__, tooltip)) if tooltip and editfield: QToolTip.add(editfield, QtGui.QApplication.translate(self.__class__.__name__, tooltip)) ##k ok?? review once not all params have same-row labels. if getter and paramname and paramname != '?': self.param_getters[paramname] = getter ### also bind these params to actions... continue # next param header_refs.extend( [self.parameters_grpbox, self.nt_parameters_grpbtn, self.parameters_grpbox_label] ) # now create the logic/control object for the group group = CollapsibleGroupController_Qt(self, group_desc, header_refs, hidethese, self.nt_parameters_grpbtn) ### maybe ask env for the class to use for this? self.groups.append(group) ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount. # from languageChange: if 1: # i don't know if these are needed: self.parameters_grpbox.setTitle(QString.null) self.nt_parameters_grpbtn.setText(QString.null) self.parameters_grpbox_label.setText(QtGui.QApplication.translate(self.__class__.__name__, group_desc.args[0])) # was "Nanotube Parameters" ##e note that it's questionable in the syntax design for this property of a group (overall group label) # to be in that position (desc arg 0). # == end its kids parameters_grpboxLayout.addLayout(nt_parameters_body_layout) body_frameLayout.addWidget(self.parameters_grpbox) # == end parameters groupbox continue # next group nanotube_dialogLayout.addWidget(self.body_frame) spacer14 = QSpacerItem(20,20,QSizePolicy.Minimum,QSizePolicy.Expanding) nanotube_dialogLayout.addItem(spacer14) layout42 = QHBoxLayout(None,4,6,"layout42") btm_spacer = QSpacerItem(59,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout42.addItem(btm_spacer) self.cancel_btn = QPushButton(self,"cancel_btn") self.cancel_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.cancel_btn) self.ok_btn = QPushButton(self,"ok_btn") self.ok_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.ok_btn) nanotube_dialogLayout.addLayout(layout42) self.languageChange() self.resize(QSize(246,618).expandedTo(self.minimumSizeHint())) ### this size will need to be adjusted (guess -- it's only place overall size is set) qt4todo('self.clearWState(Qt.WState_Polished)') ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) #### # new: for button, methodname in ((self.sponsor_btn, 'do_sponsor_btn'), #e generalize to more than one sponsor button (self.done_btn, 'do_done_btn'), (self.abort_btn, 'do_abort_btn'), (self.preview_btn, 'do_preview_btn'), (self.whatsthis_btn, 'do_whatsthis_btn'), (self.cancel_btn, 'do_cancel_btn'), (self.ok_btn, 'do_ok_btn')): if hasattr(self, methodname): self.connect(button, SIGNAL("clicked()"), getattr(self, methodname)) return
def __init__(self, plugin): DefaultConfigWidget.__init__(self, plugin) c = plugin_prefs[STORE_NAME] all_tags = get_current_db().all_tags() self.gb.setMaximumHeight(80) genre_group_box = QGroupBox(_('Aladin tag to Calibre tag mappings'), self) self.l.addWidget(genre_group_box, self.l.rowCount(), 0, 1, 2) genre_group_box_layout = QVBoxLayout() genre_group_box.setLayout(genre_group_box_layout) # Aladin tag convert to calibre tag 20140312 self.get_convert_tag_checkbox = QCheckBox(_('Convert Aladin tag to Calibre tag'), self) self.get_convert_tag_checkbox.setToolTip(_('Convert Aladin tag(korean tag) to Calibre tag.')) self.get_convert_tag_checkbox.setChecked(c.get(KEY_CONVERT_TAG,DEFAULT_STORE_VALUES[KEY_CONVERT_TAG])) genre_group_box_layout.addWidget(self.get_convert_tag_checkbox) tags_layout = QHBoxLayout() genre_group_box_layout.addLayout(tags_layout) self.edit_table = GenreTagMappingsTableWidget(self, all_tags) tags_layout.addWidget(self.edit_table) button_layout = QVBoxLayout() tags_layout.addLayout(button_layout) add_mapping_button = QtGui.QToolButton(self) add_mapping_button.setToolTip(_('Add genre mapping')) add_mapping_button.setIcon(QIcon(I('plus.png'))) add_mapping_button.clicked.connect(self.add_mapping) button_layout.addWidget(add_mapping_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem1) remove_mapping_button = QtGui.QToolButton(self) remove_mapping_button.setToolTip(_('Delete genre mapping')) remove_mapping_button.setIcon(QIcon(I('minus.png'))) remove_mapping_button.clicked.connect(self.delete_mapping) button_layout.addWidget(remove_mapping_button) spacerItem3 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem3) rename_genre_button = QtGui.QToolButton(self) rename_genre_button.setToolTip(_('Rename Aladin genre')) rename_genre_button.setIcon(QIcon(I('edit-undo.png'))) rename_genre_button.clicked.connect(self.rename_genre) button_layout.addWidget(rename_genre_button) spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem2) reset_defaults_button = QtGui.QToolButton(self) reset_defaults_button.setToolTip(_('Reset to plugin default mappings')) reset_defaults_button.setIcon(QIcon(I('clear_left.png'))) reset_defaults_button.clicked.connect(self.reset_to_defaults) button_layout.addWidget(reset_defaults_button) self.l.setRowStretch(self.l.rowCount()-1, 2) other_group_box = QGroupBox(_('Other options'), self) self.l.addWidget(other_group_box, self.l.rowCount(), 0, 1, 2) other_group_box_layout = QVBoxLayout() other_group_box.setLayout(other_group_box_layout) # DID: category | v0.1.0 20140315 self.get_category_checkbox = QCheckBox(_('Add Aladin Categories to Calibre tags'), self) self.get_category_checkbox.setToolTip(_('Add Aladin Categories to Calibre tags.\n' 'This Plugin will change delimiter ">" to delimiter "." for Category Hierarchy.\n' '(ex, "Category Prefix"History.Korea Culture.History Journey)\n ')) self.get_category_checkbox.stateChanged.connect(self.get_category_checkbox_changed) other_group_box_layout.addWidget(self.get_category_checkbox) self.category_group_box = QGroupBox(self) category_group_box_layout = QtGui.QGridLayout() self.category_group_box.setLayout(category_group_box_layout) other_group_box_layout.addWidget(self.category_group_box) # DID: 주제분류 category - 머리글 | v0.2.0 20140330 category_prefix_label = QtGui.QLabel(_('Category Prefix'),self) category_prefix_label.setToolTip(_('Set strings before categories to distinguish other tags.\n' '(예, ☞History.Korea Culture.History Journey)\n ')) category_group_box_layout.addWidget(category_prefix_label, 0, 0, 1, 1) self.category_prefix_edit = QtGui.QLineEdit(self) self.category_prefix_edit.setText(c.get(KEY_CATEGORY_PREFIX,DEFAULT_STORE_VALUES[KEY_CATEGORY_PREFIX])) category_group_box_layout.addWidget(self.category_prefix_edit, 0, 1, 1, 1) self.get_category_checkbox.setChecked(c.get(KEY_GET_CATEGORY,DEFAULT_STORE_VALUES[KEY_GET_CATEGORY])) # DID: 책표지(cover)를 큰것/작은것(big/small) 선택할 수 있도록 하자. | v0.2.0 20140330 self.small_cover_checkbox = QCheckBox(_('Download small cover.'), self) self.small_cover_checkbox.setToolTip(_('Download small cover from aladin.')) self.small_cover_checkbox.setChecked(c.get(KEY_SMALL_COVER, DEFAULT_STORE_VALUES[KEY_SMALL_COVER])) other_group_box_layout.addWidget(self.small_cover_checkbox) self.all_authors_checkbox = QCheckBox(_('Get all contributing authors (e.g. illustrators, series editors etc)'), self) self.all_authors_checkbox.setToolTip(_('Aladin for some books will list all of the contributing authors and\n' 'the type of contribution like (Editor), (Illustrator) etc.\n\n' 'When this option is checked, all contributing authors are retrieved.\n\n' 'When unchecked (default) only the primary author(s) are returned which\n' 'are those that either have no contribution type specified, or have the\n' 'value of (Aladin Author).\n\n' 'If there is no primary author then only those with the same contribution\n' 'type as the first author are returned.\n' 'e.g. "A, B (Illustrator)" will return author A\n' 'e.g. "A (Aladin Author)" will return author A\n' 'e.g. "A (Editor), B (Editor), C (Illustrator)" will return authors A & B\n' 'e.g. "A (Editor), B (Series Editor)" will return author A\n ')) self.all_authors_checkbox.setChecked(c.get(KEY_GET_ALL_AUTHORS, DEFAULT_STORE_VALUES[KEY_GET_ALL_AUTHORS])) other_group_box_layout.addWidget(self.all_authors_checkbox) # Add by sseeookk, 20140315 self.toc_checkbox = QCheckBox(_('Append TOC from Aladin TOC if available to comments'), self) self.toc_checkbox.setToolTip(_('Aladin for textbooks on their website have a Features which\n' 'contains a table of contents for the book. Checking this option will\n' 'append the TOC to the bottom of the Synopsis in the comments field')) self.toc_checkbox.setChecked(c.get(KEY_APPEND_TOC, DEFAULT_STORE_VALUES[KEY_APPEND_TOC])) other_group_box_layout.addWidget(self.toc_checkbox) # DID: 책소개(comment) 끝에 출처를 적으면 어떨까? | v0.2.0 20140330 # 코멘트 뒤에 붙을 내용 (예, aladin.co.kr{날짜}) comments_suffix_label = QLabel(_('Append comments suffix:'), self) comments_suffix_label.setToolTip(_('Append comments source after comments.\n' '(ex, <hr /><div><div style="float:right">[aladin.co.kr]</div></div>)\n ')) other_group_box_layout.addWidget(comments_suffix_label) self.comments_suffix_edit = QtGui.QLineEdit(self) self.comments_suffix_edit.setText(c.get(KEY_COMMENTS_SUFFIX, DEFAULT_STORE_VALUES[KEY_COMMENTS_SUFFIX])) other_group_box_layout.addWidget(self.comments_suffix_edit) max_label = QLabel(_('Maximum title/author search matches to evaluate (1 = fastest):'), self) max_label.setToolTip(_('Increasing this value will take effect when doing\n' 'title/author searches to consider more books.\n ')) other_group_box_layout.addWidget(max_label) self.max_downloads_spin = QtGui.QSpinBox(self) self.max_downloads_spin.setMinimum(1) self.max_downloads_spin.setMaximum(20) self.max_downloads_spin.setProperty('value', c.get(KEY_MAX_DOWNLOADS, DEFAULT_STORE_VALUES[KEY_MAX_DOWNLOADS])) other_group_box_layout.addWidget(self.max_downloads_spin) self.edit_table.populate_table(c[KEY_GENRE_MAPPINGS])
class ConfigWidget(QWidget, Logger): ''' Config dialog for Marvin Manager ''' WIZARD_PROFILES = { 'Annotations': { 'label': 'mm_annotations', 'datatype': 'comments', 'display': {}, 'is_multiple': False }, 'Collections': { 'label': 'mm_collections', 'datatype': 'text', 'display': {u'is_names': False}, 'is_multiple': True }, 'Last read': { 'label': 'mm_date_read', 'datatype': 'datetime', 'display': {}, 'is_multiple': False }, 'Locked': { 'label': 'mm_locked', 'datatype': 'bool', 'display': {}, 'is_multiple': False }, 'Progress': { 'label': 'mm_progress', 'datatype': 'float', 'display': {u'number_format': u'{0:.0f}%'}, 'is_multiple': False }, 'Read': { 'label': 'mm_read', 'datatype': 'bool', 'display': {}, 'is_multiple': False }, 'Reading list': { 'label': 'mm_reading_list', 'datatype': 'bool', 'display': {}, 'is_multiple': False }, 'Word count': { 'label': 'mm_word_count', 'datatype': 'int', 'display': {u'number_format': u'{0:n}'}, 'is_multiple': False } } def __init__(self, plugin_action): QWidget.__init__(self) self.parent = plugin_action self.gui = get_gui() self.icon = plugin_action.icon self.opts = plugin_action.opts self.prefs = plugin_prefs self.resources_path = plugin_action.resources_path self.verbose = plugin_action.verbose self.restart_required = False self._log_location() self.l = QGridLayout() self.setLayout(self.l) self.column1_layout = QVBoxLayout() self.l.addLayout(self.column1_layout, 0, 0) self.column2_layout = QVBoxLayout() self.l.addLayout(self.column2_layout, 0, 1) # ----------------------------- Column 1 ----------------------------- # ~~~~~~~~ Create the Custom fields options group box ~~~~~~~~ self.cfg_custom_fields_gb = QGroupBox(self) self.cfg_custom_fields_gb.setTitle('Custom column assignments') self.column1_layout.addWidget(self.cfg_custom_fields_gb) self.cfg_custom_fields_qgl = QGridLayout(self.cfg_custom_fields_gb) current_row = 0 # ++++++++ Labels + HLine ++++++++ self.marvin_source_label = QLabel("Marvin source") self.cfg_custom_fields_qgl.addWidget(self.marvin_source_label, current_row, 0) self.calibre_destination_label = QLabel("calibre destination") self.cfg_custom_fields_qgl.addWidget(self.calibre_destination_label, current_row, 1) current_row += 1 self.sd_hl = QFrame(self.cfg_custom_fields_gb) self.sd_hl.setFrameShape(QFrame.HLine) self.sd_hl.setFrameShadow(QFrame.Raised) self.cfg_custom_fields_qgl.addWidget(self.sd_hl, current_row, 0, 1, 3) current_row += 1 # ++++++++ Annotations ++++++++ self.cfg_annotations_label = QLabel('Annotations') self.cfg_annotations_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_annotations_label, current_row, 0) self.annotations_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.annotations_field_comboBox.setObjectName('annotations_field_comboBox') self.annotations_field_comboBox.setToolTip('Select a custom column to store Marvin annotations') self.cfg_custom_fields_qgl.addWidget(self.annotations_field_comboBox, current_row, 1) self.cfg_highlights_wizard = QToolButton() self.cfg_highlights_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_highlights_wizard.setToolTip("Create a custom column to store Marvin annotations") self.cfg_highlights_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Annotations')) self.cfg_custom_fields_qgl.addWidget(self.cfg_highlights_wizard, current_row, 2) current_row += 1 # ++++++++ Collections ++++++++ self.cfg_collections_label = QLabel('Collections') self.cfg_collections_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_label, current_row, 0) self.collection_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.collection_field_comboBox.setObjectName('collection_field_comboBox') self.collection_field_comboBox.setToolTip('Select a custom column to store Marvin collection assignments') self.cfg_custom_fields_qgl.addWidget(self.collection_field_comboBox, current_row, 1) self.cfg_collections_wizard = QToolButton() self.cfg_collections_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_collections_wizard.setToolTip("Create a custom column for Marvin collection assignments") self.cfg_collections_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Collections')) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_wizard, current_row, 2) current_row += 1 # ++++++++ Last read ++++++++ self.cfg_date_read_label = QLabel("Last read") self.cfg_date_read_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_date_read_label, current_row, 0) self.date_read_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.date_read_field_comboBox.setObjectName('date_read_field_comboBox') self.date_read_field_comboBox.setToolTip('Select a custom column to store Last read date') self.cfg_custom_fields_qgl.addWidget(self.date_read_field_comboBox, current_row, 1) self.cfg_collections_wizard = QToolButton() self.cfg_collections_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_collections_wizard.setToolTip("Create a custom column to store Last read date") self.cfg_collections_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Last read')) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_wizard, current_row, 2) current_row += 1 # ++++++++ Locked ++++++++ self.cfg_locked_label = QLabel("Locked") self.cfg_locked_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_locked_label, current_row, 0) self.locked_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.locked_field_comboBox.setObjectName('locked_field_comboBox') self.locked_field_comboBox.setToolTip('Select a custom column to store Locked status') self.cfg_custom_fields_qgl.addWidget(self.locked_field_comboBox, current_row, 1) self.cfg_locked_wizard = QToolButton() self.cfg_locked_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_locked_wizard.setToolTip("Create a custom column to store Locked status") self.cfg_locked_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Locked')) self.cfg_custom_fields_qgl.addWidget(self.cfg_locked_wizard, current_row, 2) current_row += 1 # ++++++++ Progress ++++++++ self.cfg_progress_label = QLabel('Progress') self.cfg_progress_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_progress_label, current_row, 0) self.progress_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.progress_field_comboBox.setObjectName('progress_field_comboBox') self.progress_field_comboBox.setToolTip('Select a custom column to store Marvin reading progress') self.cfg_custom_fields_qgl.addWidget(self.progress_field_comboBox, current_row, 1) self.cfg_progress_wizard = QToolButton() self.cfg_progress_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_progress_wizard.setToolTip("Create a custom column to store Marvin reading progress") self.cfg_progress_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Progress')) self.cfg_custom_fields_qgl.addWidget(self.cfg_progress_wizard, current_row, 2) current_row += 1 # ++++++++ Read flag ++++++++ self.cfg_read_label = QLabel('Read') self.cfg_read_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_read_label, current_row, 0) self.read_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.read_field_comboBox.setObjectName('read_field_comboBox') self.read_field_comboBox.setToolTip('Select a custom column to store Marvin Read status') self.cfg_custom_fields_qgl.addWidget(self.read_field_comboBox, current_row, 1) self.cfg_read_wizard = QToolButton() self.cfg_read_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_read_wizard.setToolTip("Create a custom column to store Marvin Read status") self.cfg_read_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Read')) self.cfg_custom_fields_qgl.addWidget(self.cfg_read_wizard, current_row, 2) current_row += 1 # ++++++++ Reading list flag ++++++++ self.cfg_reading_list_label = QLabel('Reading list') self.cfg_reading_list_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_reading_list_label, current_row, 0) self.reading_list_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.reading_list_field_comboBox.setObjectName('reading_list_field_comboBox') self.reading_list_field_comboBox.setToolTip('Select a custom column to store Marvin Reading list status') self.cfg_custom_fields_qgl.addWidget(self.reading_list_field_comboBox, current_row, 1) self.cfg_reading_list_wizard = QToolButton() self.cfg_reading_list_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_reading_list_wizard.setToolTip("Create a custom column to store Marvin Reading list status") self.cfg_reading_list_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Reading list')) self.cfg_custom_fields_qgl.addWidget(self.cfg_reading_list_wizard, current_row, 2) current_row += 1 # ++++++++ Word count ++++++++ self.cfg_word_count_label = QLabel('Word count') self.cfg_word_count_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_word_count_label, current_row, 0) self.word_count_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.word_count_field_comboBox.setObjectName('word_count_field_comboBox') self.word_count_field_comboBox.setToolTip('Select a custom column to store Marvin word counts') self.cfg_custom_fields_qgl.addWidget(self.word_count_field_comboBox, current_row, 1) self.cfg_word_count_wizard = QToolButton() self.cfg_word_count_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_word_count_wizard.setToolTip("Create a custom column to store Marvin word counts") self.cfg_word_count_wizard.clicked.connect(partial(self.launch_cc_wizard, 'Word count')) self.cfg_custom_fields_qgl.addWidget(self.cfg_word_count_wizard, current_row, 2) current_row += 1 self.spacerItem1 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) self.column1_layout.addItem(self.spacerItem1) # ----------------------------- Column 2 ----------------------------- # ~~~~~~~~ Create the CSS group box ~~~~~~~~ self.cfg_css_options_gb = QGroupBox(self) self.cfg_css_options_gb.setTitle('CSS') self.column2_layout.addWidget(self.cfg_css_options_gb) self.cfg_css_options_qgl = QGridLayout(self.cfg_css_options_gb) current_row = 0 # ++++++++ Annotations appearance ++++++++ self.annotations_icon = QIcon(os.path.join(self.resources_path, 'icons', 'annotations_hiliter.png')) self.cfg_annotations_appearance_toolbutton = QToolButton() self.cfg_annotations_appearance_toolbutton.setIcon(self.annotations_icon) self.cfg_annotations_appearance_toolbutton.clicked.connect(self.configure_appearance) self.cfg_css_options_qgl.addWidget(self.cfg_annotations_appearance_toolbutton, current_row, 0) self.cfg_annotations_label = ClickableQLabel("Book notes, Bookmark notes and Annotations") self.connect(self.cfg_annotations_label, SIGNAL('clicked()'), self.configure_appearance) self.cfg_css_options_qgl.addWidget(self.cfg_annotations_label, current_row, 1) current_row += 1 # ++++++++ Injected CSS ++++++++ self.css_editor_icon = QIcon(I('format-text-heading.png')) self.cfg_css_editor_toolbutton = QToolButton() self.cfg_css_editor_toolbutton.setIcon(self.css_editor_icon) self.cfg_css_editor_toolbutton.clicked.connect(self.edit_css) self.cfg_css_options_qgl.addWidget(self.cfg_css_editor_toolbutton, current_row, 0) self.cfg_css_editor_label = ClickableQLabel("Articles, Vocabulary") self.connect(self.cfg_css_editor_label, SIGNAL('clicked()'), self.edit_css) self.cfg_css_options_qgl.addWidget(self.cfg_css_editor_label, current_row, 1) """ # ~~~~~~~~ Create the Dropbox syncing group box ~~~~~~~~ self.cfg_dropbox_syncing_gb = QGroupBox(self) self.cfg_dropbox_syncing_gb.setTitle('Dropbox') self.column2_layout.addWidget(self.cfg_dropbox_syncing_gb) self.cfg_dropbox_syncing_qgl = QGridLayout(self.cfg_dropbox_syncing_gb) current_row = 0 # ++++++++ Syncing enabled checkbox ++++++++ self.dropbox_syncing_checkbox = QCheckBox('Enable Dropbox updates') self.dropbox_syncing_checkbox.setObjectName('dropbox_syncing') self.dropbox_syncing_checkbox.setToolTip('Refresh custom column content from Marvin metadata') self.cfg_dropbox_syncing_qgl.addWidget(self.dropbox_syncing_checkbox, current_row, 0, 1, 3) current_row += 1 # ++++++++ Dropbox folder picker ++++++++ self.dropbox_folder_icon = QIcon(os.path.join(self.resources_path, 'icons', 'dropbox.png')) self.cfg_dropbox_folder_toolbutton = QToolButton() self.cfg_dropbox_folder_toolbutton.setIcon(self.dropbox_folder_icon) self.cfg_dropbox_folder_toolbutton.setToolTip("Specify Dropbox folder location on your computer") self.cfg_dropbox_folder_toolbutton.clicked.connect(self.select_dropbox_folder) self.cfg_dropbox_syncing_qgl.addWidget(self.cfg_dropbox_folder_toolbutton, current_row, 1) # ++++++++ Dropbox location lineedit ++++++++ self.dropbox_location_lineedit = QLineEdit() self.dropbox_location_lineedit.setPlaceholderText("Dropbox folder location") self.cfg_dropbox_syncing_qgl.addWidget(self.dropbox_location_lineedit, current_row, 2) """ # ~~~~~~~~ Create the General options group box ~~~~~~~~ self.cfg_runtime_options_gb = QGroupBox(self) self.cfg_runtime_options_gb.setTitle('General options') self.column2_layout.addWidget(self.cfg_runtime_options_gb) self.cfg_runtime_options_qvl = QVBoxLayout(self.cfg_runtime_options_gb) # ++++++++ Temporary markers: Duplicates ++++++++ self.duplicate_markers_checkbox = QCheckBox('Apply temporary markers to duplicate books') self.duplicate_markers_checkbox.setObjectName('apply_markers_to_duplicates') self.duplicate_markers_checkbox.setToolTip('Books with identical content will be flagged in the Library window') self.cfg_runtime_options_qvl.addWidget(self.duplicate_markers_checkbox) # ++++++++ Temporary markers: Updated ++++++++ self.updated_markers_checkbox = QCheckBox('Apply temporary markers to books with updated content') self.updated_markers_checkbox.setObjectName('apply_markers_to_updated') self.updated_markers_checkbox.setToolTip('Books with updated content will be flagged in the Library window') self.cfg_runtime_options_qvl.addWidget(self.updated_markers_checkbox) # ++++++++ Auto refresh checkbox ++++++++ self.auto_refresh_checkbox = QCheckBox('Automatically refresh custom column content') self.auto_refresh_checkbox.setObjectName('auto_refresh_at_startup') self.auto_refresh_checkbox.setToolTip('Update calibre custom column when Marvin XD is opened') self.cfg_runtime_options_qvl.addWidget(self.auto_refresh_checkbox) # ++++++++ Progress as percentage checkbox ++++++++ self.reading_progress_checkbox = QCheckBox('Show reading progress as percentage') self.reading_progress_checkbox.setObjectName('show_progress_as_percentage') self.reading_progress_checkbox.setToolTip('Display percentage in Progress column') self.cfg_runtime_options_qvl.addWidget(self.reading_progress_checkbox) # ~~~~~~~~ Create the Debug options group box ~~~~~~~~ self.cfg_debug_options_gb = QGroupBox(self) self.cfg_debug_options_gb.setTitle('Debug options') self.column2_layout.addWidget(self.cfg_debug_options_gb) self.cfg_debug_options_qvl = QVBoxLayout(self.cfg_debug_options_gb) # ++++++++ Debug logging checkboxes ++++++++ self.debug_plugin_checkbox = QCheckBox('Enable debug logging for Marvin XD') self.debug_plugin_checkbox.setObjectName('debug_plugin_checkbox') self.debug_plugin_checkbox.setToolTip('Print plugin diagnostic messages to console') self.cfg_debug_options_qvl.addWidget(self.debug_plugin_checkbox) self.debug_libimobiledevice_checkbox = QCheckBox('Enable debug logging for libiMobileDevice') self.debug_libimobiledevice_checkbox.setObjectName('debug_libimobiledevice_checkbox') self.debug_libimobiledevice_checkbox.setToolTip('Print libiMobileDevice diagnostic messages to console') self.cfg_debug_options_qvl.addWidget(self.debug_libimobiledevice_checkbox) self.spacerItem2 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) self.column2_layout.addItem(self.spacerItem2) # ~~~~~~~~ End of construction zone ~~~~~~~~ self.resize(self.sizeHint()) # ~~~~~~~~ Populate/restore config options ~~~~~~~~ # Annotations comboBox self.populate_annotations() self.populate_collections() self.populate_date_read() self.populate_locked() self.populate_progress() self.populate_read() self.populate_reading_list() self.populate_word_count() """ # Restore Dropbox settings, hook changes dropbox_syncing = self.prefs.get('dropbox_syncing', False) self.dropbox_syncing_checkbox.setChecked(dropbox_syncing) self.set_dropbox_syncing(dropbox_syncing) self.dropbox_syncing_checkbox.clicked.connect(partial(self.set_dropbox_syncing)) self.dropbox_location_lineedit.setText(self.prefs.get('dropbox_folder', '')) """ # Restore general settings self.duplicate_markers_checkbox.setChecked(self.prefs.get('apply_markers_to_duplicates', True)) self.updated_markers_checkbox.setChecked(self.prefs.get('apply_markers_to_updated', True)) self.auto_refresh_checkbox.setChecked(self.prefs.get('auto_refresh_at_startup', False)) self.reading_progress_checkbox.setChecked(self.prefs.get('show_progress_as_percentage', False)) # Restore debug settings, hook changes self.debug_plugin_checkbox.setChecked(self.prefs.get('debug_plugin', False)) self.debug_plugin_checkbox.stateChanged.connect(self.set_restart_required) self.debug_libimobiledevice_checkbox.setChecked(self.prefs.get('debug_libimobiledevice', False)) self.debug_libimobiledevice_checkbox.stateChanged.connect(self.set_restart_required) # Hook changes to Annotations comboBox # self.annotations_field_comboBox.currentIndexChanged.connect( # partial(self.save_combobox_setting, 'annotations_field_comboBox')) self.connect(self.annotations_field_comboBox, SIGNAL('currentIndexChanged(const QString &)'), self.annotations_destination_changed) # Launch the annotated_books_scanner field = get_cc_mapping('annotations', 'field', None) self.annotated_books_scanner = InventoryAnnotatedBooks(self.gui, field) self.connect(self.annotated_books_scanner, self.annotated_books_scanner.signal, self.inventory_complete) QTimer.singleShot(1, self.start_inventory) def annotations_destination_changed(self, qs_new_destination_name): ''' If the destination field changes, move all existing annotations from old to new ''' self._log_location(str(qs_new_destination_name)) #self._log("self.eligible_annotations_fields: %s" % self.eligible_annotations_fields) old_destination_field = get_cc_mapping('annotations', 'field', None) old_destination_name = get_cc_mapping('annotations', 'combobox', None) self._log("old_destination_field: %s" % old_destination_field) self._log("old_destination_name: %s" % old_destination_name) new_destination_name = unicode(qs_new_destination_name) self._log("new_destination_name: %s" % repr(new_destination_name)) if old_destination_name == new_destination_name: self._log_location("old_destination_name = new_destination_name, no changes") return if new_destination_name == '': self._log_location("annotations storage disabled") set_cc_mapping('annotations', field=None, combobox=new_destination_name) return new_destination_field = self.eligible_annotations_fields[new_destination_name] if existing_annotations(self.parent, old_destination_field): command = self.launch_new_destination_dialog(old_destination_name, new_destination_name) if command == 'move': set_cc_mapping('annotations', field=new_destination_field, combobox=new_destination_name) if self.annotated_books_scanner.isRunning(): self.annotated_books_scanner.wait() move_annotations(self, self.annotated_books_scanner.annotation_map, old_destination_field, new_destination_field) elif command == 'change': # Keep the updated destination field, but don't move annotations pass elif command == 'cancel': # Restore previous destination self.annotations_field_comboBox.blockSignals(True) old_index = self.annotations_field_comboBox.findText(old_destination_name) self.annotations_field_comboBox.setCurrentIndex(old_index) self.annotations_field_comboBox.blockSignals(False) else: # No existing annotations, just update prefs self._log("no existing annotations, updating destination to '{0}'".format(new_destination_name)) set_cc_mapping('annotations', field=new_destination_field, combobox=new_destination_name) def configure_appearance(self): ''' ''' self._log_location() appearance_settings = { 'appearance_css': default_elements, 'appearance_hr_checkbox': False, 'appearance_timestamp_format': default_timestamp } # Save, hash the original settings original_settings = {} osh = hashlib.md5() for setting in appearance_settings: original_settings[setting] = plugin_prefs.get(setting, appearance_settings[setting]) osh.update(repr(plugin_prefs.get(setting, appearance_settings[setting]))) # Display the Annotations appearance dialog aa = AnnotationsAppearance(self, self.annotations_icon, plugin_prefs) cancelled = False if aa.exec_(): # appearance_hr_checkbox and appearance_timestamp_format changed live to prefs during previews plugin_prefs.set('appearance_css', aa.elements_table.get_data()) # Generate a new hash nsh = hashlib.md5() for setting in appearance_settings: nsh.update(repr(plugin_prefs.get(setting, appearance_settings[setting]))) else: for setting in appearance_settings: plugin_prefs.set(setting, original_settings[setting]) nsh = osh # If there were changes, and there are existing annotations, # and there is an active Annotations field, offer to re-render field = get_cc_mapping('annotations', 'field', None) if osh.digest() != nsh.digest() and existing_annotations(self.parent, field): title = 'Update annotations?' msg = '<p>Update existing annotations to new appearance settings?</p>' d = MessageBox(MessageBox.QUESTION, title, msg, show_copy_button=False) self._log_location("QUESTION: %s" % msg) if d.exec_(): self._log_location("Updating existing annotations to modified appearance") # Wait for indexing to complete while not self.annotated_books_scanner.isFinished(): Application.processEvents() move_annotations(self, self.annotated_books_scanner.annotation_map, field, field, window_title="Updating appearance") def edit_css(self): ''' ''' self._log_location() from calibre_plugins.marvin_manager.book_status import dialog_resources_path klass = os.path.join(dialog_resources_path, 'css_editor.py') if os.path.exists(klass): sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('css_editor') sys.path.remove(dialog_resources_path) dlg = this_dc.CSSEditorDialog(self, 'css_editor') dlg.initialize(self) dlg.exec_() def get_eligible_custom_fields(self, eligible_types=[], is_multiple=None): ''' Discover qualifying custom fields for eligible_types[] ''' #self._log_location(eligible_types) eligible_custom_fields = {} for cf in self.gui.current_db.custom_field_keys(): cft = self.gui.current_db.metadata_for_field(cf)['datatype'] cfn = self.gui.current_db.metadata_for_field(cf)['name'] cfim = self.gui.current_db.metadata_for_field(cf)['is_multiple'] #self._log("cf: %s cft: %s cfn: %s cfim: %s" % (cf, cft, cfn, cfim)) if cft in eligible_types: if is_multiple is not None: if bool(cfim) == is_multiple: eligible_custom_fields[cfn] = cf else: eligible_custom_fields[cfn] = cf return eligible_custom_fields def inventory_complete(self, msg): self._log_location(msg) def launch_cc_wizard(self, column_type): ''' ''' def _update_combo_box(comboBox, destination, previous): ''' ''' cb = getattr(self, comboBox) cb.blockSignals(True) all_items = [str(cb.itemText(i)) for i in range(cb.count())] if previous and previous in all_items: all_items.remove(previous) all_items.append(destination) cb.clear() cb.addItems(sorted(all_items, key=lambda s: s.lower())) # Select the new destination in the comboBox idx = cb.findText(destination) if idx > -1: cb.setCurrentIndex(idx) cb.blockSignals(False) from calibre_plugins.marvin_manager.book_status import dialog_resources_path klass = os.path.join(dialog_resources_path, 'cc_wizard.py') if os.path.exists(klass): #self._log("importing CC Wizard dialog from '%s'" % klass) sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('cc_wizard') sys.path.remove(dialog_resources_path) dlg = this_dc.CustomColumnWizard(self, column_type, self.WIZARD_PROFILES[column_type], verbose=True) dlg.exec_() if dlg.modified_column: self._log("modified_column: %s" % dlg.modified_column) self.restart_required = True destination = dlg.modified_column['destination'] label = dlg.modified_column['label'] previous = dlg.modified_column['previous'] source = dlg.modified_column['source'] if source == "Annotations": _update_combo_box("annotations_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_annotations_fields[destination] = label # Save manually in case user cancels set_cc_mapping('annotations', combobox=destination, field=label) elif source == 'Collections': _update_combo_box("collection_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_collection_fields[destination] = label # Save manually in case user cancels set_cc_mapping('collections', combobox=destination, field=label) elif source == 'Last read': _update_combo_box("date_read_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_date_read_fields[destination] = label # Save manually in case user cancels set_cc_mapping('date_read', combobox=destination, field=label) elif source == 'Locked': _update_combo_box("locked_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_locked_fields[destination] = label # Save manually in case user cancels set_cc_mapping('locked', combobox=destination, field=label) elif source == "Progress": _update_combo_box("progress_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_progress_fields[destination] = label # Save manually in case user cancels set_cc_mapping('progress', combobox=destination, field=label) elif source == "Read": _update_combo_box("read_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_read_fields[destination] = label # Save manually in case user cancels set_cc_mapping('read', combobox=destination, field=label) elif source == "Reading list": _update_combo_box("reading_list_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_reading_list_fields[destination] = label # Save manually in case user cancels set_cc_mapping('reading_list', combobox=destination, field=label) elif source == "Word count": _update_combo_box("word_count_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_word_count_fields[destination] = label # Save manually in case user cancels set_cc_mapping('word_count', combobox=destination, field=label) else: self._log("ERROR: Can't import from '%s'" % klass) def launch_new_destination_dialog(self, old, new): ''' Return 'move', 'change' or 'cancel' ''' from calibre_plugins.marvin_manager.book_status import dialog_resources_path self._log_location() klass = os.path.join(dialog_resources_path, 'new_destination.py') if os.path.exists(klass): self._log("importing new destination dialog from '%s'" % klass) sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('new_destination') sys.path.remove(dialog_resources_path) dlg = this_dc.NewDestinationDialog(self, old, new) dlg.exec_() return dlg.command def populate_annotations(self): datatype = self.WIZARD_PROFILES['Annotations']['datatype'] self.eligible_annotations_fields = self.get_eligible_custom_fields([datatype]) self.annotations_field_comboBox.addItems(['']) ecf = sorted(self.eligible_annotations_fields.keys(), key=lambda s: s.lower()) self.annotations_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('annotations', 'combobox') if existing: ci = self.annotations_field_comboBox.findText(existing) self.annotations_field_comboBox.setCurrentIndex(ci) def populate_collections(self): datatype = self.WIZARD_PROFILES['Collections']['datatype'] self.eligible_collection_fields = self.get_eligible_custom_fields([datatype], is_multiple=True) self.collection_field_comboBox.addItems(['']) ecf = sorted(self.eligible_collection_fields.keys(), key=lambda s: s.lower()) self.collection_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('collections', 'combobox') if existing: ci = self.collection_field_comboBox.findText(existing) self.collection_field_comboBox.setCurrentIndex(ci) def populate_date_read(self): #self.eligible_date_read_fields = self.get_eligible_custom_fields(['datetime']) datatype = self.WIZARD_PROFILES['Last read']['datatype'] self.eligible_date_read_fields = self.get_eligible_custom_fields([datatype]) self.date_read_field_comboBox.addItems(['']) ecf = sorted(self.eligible_date_read_fields.keys(), key=lambda s: s.lower()) self.date_read_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('date_read', 'combobox') if existing: ci = self.date_read_field_comboBox.findText(existing) self.date_read_field_comboBox.setCurrentIndex(ci) def populate_locked(self): datatype = self.WIZARD_PROFILES['Locked']['datatype'] self.eligible_locked_fields = self.get_eligible_custom_fields([datatype]) self.locked_field_comboBox.addItems(['']) ecf = sorted(self.eligible_locked_fields.keys(), key=lambda s: s.lower()) self.locked_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('locked', 'combobox') if existing: ci = self.locked_field_comboBox.findText(existing) self.locked_field_comboBox.setCurrentIndex(ci) def populate_progress(self): #self.eligible_progress_fields = self.get_eligible_custom_fields(['float']) datatype = self.WIZARD_PROFILES['Progress']['datatype'] self.eligible_progress_fields = self.get_eligible_custom_fields([datatype]) self.progress_field_comboBox.addItems(['']) ecf = sorted(self.eligible_progress_fields.keys(), key=lambda s: s.lower()) self.progress_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('progress', 'combobox') if existing: ci = self.progress_field_comboBox.findText(existing) self.progress_field_comboBox.setCurrentIndex(ci) def populate_read(self): datatype = self.WIZARD_PROFILES['Read']['datatype'] self.eligible_read_fields = self.get_eligible_custom_fields([datatype]) self.read_field_comboBox.addItems(['']) ecf = sorted(self.eligible_read_fields.keys(), key=lambda s: s.lower()) self.read_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('read', 'combobox') if existing: ci = self.read_field_comboBox.findText(existing) self.read_field_comboBox.setCurrentIndex(ci) def populate_reading_list(self): datatype = self.WIZARD_PROFILES['Reading list']['datatype'] self.eligible_reading_list_fields = self.get_eligible_custom_fields([datatype]) self.reading_list_field_comboBox.addItems(['']) ecf = sorted(self.eligible_reading_list_fields.keys(), key=lambda s: s.lower()) self.reading_list_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('reading_list', 'combobox') if existing: ci = self.reading_list_field_comboBox.findText(existing) self.reading_list_field_comboBox.setCurrentIndex(ci) def populate_word_count(self): #self.eligible_word_count_fields = self.get_eligible_custom_fields(['int']) datatype = self.WIZARD_PROFILES['Word count']['datatype'] self.eligible_word_count_fields = self.get_eligible_custom_fields([datatype]) self.word_count_field_comboBox.addItems(['']) ecf = sorted(self.eligible_word_count_fields.keys(), key=lambda s: s.lower()) self.word_count_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('word_count', 'combobox') if existing: ci = self.word_count_field_comboBox.findText(existing) self.word_count_field_comboBox.setCurrentIndex(ci) """ def select_dropbox_folder(self): ''' ''' self._log_location() dropbox_location = QFileDialog.getExistingDirectory( self, "Dropbox folder", os.path.expanduser("~"), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) self.dropbox_location_lineedit.setText(unicode(dropbox_location)) def set_dropbox_syncing(self, state): ''' Called when checkbox changes state, or when restoring state Set enabled state of Dropbox folder picker to match ''' self.cfg_dropbox_folder_toolbutton.setEnabled(state) self.dropbox_location_lineedit.setEnabled(state) """ def set_restart_required(self, state): ''' Set restart_required flag to show show dialog when closing dialog ''' self.restart_required = True """ def save_combobox_setting(self, cb, index): ''' Apply changes immediately ''' cf = str(getattr(self, cb).currentText()) self._log_location("%s => %s" % (cb, repr(cf))) if cb == 'annotations_field_comboBox': field = None if cf: field = self.eligible_annotations_fields[cf] set_cc_mapping('annotations', combobox=cf, field=field) """ def save_settings(self): self._log_location() # Annotations field cf = unicode(self.annotations_field_comboBox.currentText()) field = None if cf: field = self.eligible_annotations_fields[cf] set_cc_mapping('annotations', combobox=cf, field=field) # Collections field cf = unicode(self.collection_field_comboBox.currentText()) field = None if cf: field = self.eligible_collection_fields[cf] set_cc_mapping('collections', combobox=cf, field=field) # Date read field cf = unicode(self.date_read_field_comboBox.currentText()) field = None if cf: field = self.eligible_date_read_fields[cf] set_cc_mapping('date_read', combobox=cf, field=field) # Locked field cf = unicode(self.locked_field_comboBox.currentText()) field = None if cf: field = self.eligible_locked_fields[cf] set_cc_mapping('locked', combobox=cf, field=field) # Progress field cf = unicode(self.progress_field_comboBox.currentText()) field = None if cf: field = self.eligible_progress_fields[cf] set_cc_mapping('progress', combobox=cf, field=field) # Read field cf = unicode(self.read_field_comboBox.currentText()) field = None if cf: field = self.eligible_read_fields[cf] set_cc_mapping('read', combobox=cf, field=field) # Reading list field cf = unicode(self.reading_list_field_comboBox.currentText()) field = None if cf: field = self.eligible_reading_list_fields[cf] set_cc_mapping('reading_list', combobox=cf, field=field) # Word count field cf = unicode(self.word_count_field_comboBox.currentText()) field = None if cf: field = self.eligible_word_count_fields[cf] set_cc_mapping('word_count', combobox=cf, field=field) ''' # Save Dropbox settings self.prefs.set('dropbox_syncing', self.dropbox_syncing_checkbox.isChecked()) self.prefs.set('dropbox_folder', unicode(self.dropbox_location_lineedit.text())) ''' # Save general settings self.prefs.set('apply_markers_to_duplicates', self.duplicate_markers_checkbox.isChecked()) self.prefs.set('apply_markers_to_updated', self.updated_markers_checkbox.isChecked()) self.prefs.set('auto_refresh_at_startup', self.auto_refresh_checkbox.isChecked()) self.prefs.set('show_progress_as_percentage', self.reading_progress_checkbox.isChecked()) # Save debug settings self.prefs.set('debug_plugin', self.debug_plugin_checkbox.isChecked()) self.prefs.set('debug_libimobiledevice', self.debug_libimobiledevice_checkbox.isChecked()) # If restart needed, inform user if self.restart_required: do_restart = show_restart_warning('Restart calibre for the changes to be applied.', parent=self.gui) if do_restart: self.gui.quit(restart=True) def start_inventory(self): self._log_location() self.annotated_books_scanner.start()
def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""): QDialog.__init__(self,parent) self.parent = parent self.key_type_name = key_type_name self.plugin_keys = plugin_keys self.create_key = create_key self.keyfile_ext = keyfile_ext self.import_key = (keyfile_ext != u"") self.binary_file = (key_type_name == u"Adobe Digital Editions Key") self.json_file = (key_type_name == u"Kindle for Mac and PC Key") self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) # Start Qt Gui dialog layout layout = QVBoxLayout(self) self.setLayout(layout) help_layout = QHBoxLayout() layout.addLayout(help_layout) # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self) help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_label.setAlignment(Qt.AlignRight) help_label.linkActivated.connect(self.help_link_activated) help_layout.addWidget(help_label) keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) layout.addWidget(keys_group_box) keys_group_box_layout = QHBoxLayout() keys_group_box.setLayout(keys_group_box_layout) self.listy = QListWidget(self) self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name)) self.listy.setSelectionMode(QAbstractItemView.SingleSelection) self.populate_list() keys_group_box_layout.addWidget(self.listy) button_layout = QVBoxLayout() keys_group_box_layout.addLayout(button_layout) self._add_key_button = QtGui.QToolButton(self) self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name)) self._add_key_button.setIcon(QIcon(I('plus.png'))) self._add_key_button.clicked.connect(self.add_key) button_layout.addWidget(self._add_key_button) self._delete_key_button = QtGui.QToolButton(self) self._delete_key_button.setToolTip(_(u"Delete highlighted key")) self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) self._delete_key_button.clicked.connect(self.delete_key) button_layout.addWidget(self._delete_key_button) if type(self.plugin_keys) == dict: self._rename_key_button = QtGui.QToolButton(self) self._rename_key_button.setToolTip(_(u"Rename highlighted key")) self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) self._rename_key_button.clicked.connect(self.rename_key) button_layout.addWidget(self._rename_key_button) self.export_key_button = QtGui.QToolButton(self) self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext)) self.export_key_button.setIcon(QIcon(I('save.png'))) self.export_key_button.clicked.connect(self.export_key) button_layout.addWidget(self.export_key_button) spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) button_layout.addItem(spacerItem) layout.addSpacing(5) migrate_layout = QHBoxLayout() layout.addLayout(migrate_layout) if self.import_key: migrate_layout.setAlignment(Qt.AlignJustify) self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self) self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext)) self.migrate_btn.clicked.connect(self.migrate_wrapper) migrate_layout.addWidget(self.migrate_btn) migrate_layout.addStretch() self.button_box = QDialogButtonBox(QDialogButtonBox.Close) self.button_box.rejected.connect(self.close) migrate_layout.addWidget(self.button_box) self.resize(self.sizeHint())
def do_layout(self): self.central_widget.clear() self.tabs = [] self.labels = [] sto = QWidget.setTabOrder self.on_drag_enter.connect(self.handle_drag_enter) self.tabs.append(DragTrackingWidget(self, self.on_drag_enter)) self.central_widget.addTab(self.tabs[0], _("&Metadata")) self.tabs[0].l = QGridLayout() self.tabs[0].setLayout(self.tabs[0].l) self.tabs.append(QWidget(self)) self.central_widget.addTab(self.tabs[1], _("&Cover and formats")) self.tabs[1].l = QGridLayout() self.tabs[1].setLayout(self.tabs[1].l) # accept drop events so we can automatically switch to the second tab to # drop covers and formats self.tabs[0].setAcceptDrops(True) # Tab 0 tab0 = self.tabs[0] tl = QGridLayout() gb = QGroupBox(_('&Basic metadata'), self.tabs[0]) self.tabs[0].l.addWidget(gb, 0, 0, 1, 1) gb.setLayout(tl) self.button_box_layout.insertWidget(1, self.fetch_metadata_button) self.button_box_layout.insertWidget(2, self.config_metadata_button) sto(self.button_box, self.fetch_metadata_button) sto(self.fetch_metadata_button, self.config_metadata_button) sto(self.config_metadata_button, self.title) def create_row(row, widget, tab_to, button=None, icon=None, span=1): ql = BuddyLabel(widget) tl.addWidget(ql, row, 1, 1, 1) tl.addWidget(widget, row, 2, 1, 1) if button is not None: tl.addWidget(button, row, 3, span, 1) if icon is not None: button.setIcon(QIcon(I(icon))) if tab_to is not None: if button is not None: sto(widget, button) sto(button, tab_to) else: sto(widget, tab_to) tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 1, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, icon='auto_author_sort.png') create_row(1, self.title_sort, self.authors) create_row(2, self.authors, self.author_sort, button=self.deduce_author_sort_button, span=2, icon='auto_author_sort.png') create_row(3, self.author_sort, self.series) create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate, button=self.clear_ratings_button) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') create_row(9, self.publisher, self.languages) create_row(10, self.languages, self.timestamp) create_row(11, self.timestamp, self.identifiers, button=self.timestamp.clear_button, icon='trash.png') create_row(12, self.identifiers, self.comments, button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) sto(self.manage_authors_button, self.tags_editor_button) sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1 ,1) w = getattr(self, 'custom_metadata_widgets_parent', None) if w is not None: gb = QGroupBox(_('C&ustom metadata'), tab0) gbl = QVBoxLayout() gb.setLayout(gbl) sr = QScrollArea(tab0) sr.setWidgetResizable(True) sr.setFrameStyle(QFrame.NoFrame) sr.setWidget(w) gbl.addWidget(sr) self.tabs[0].l.addWidget(gb, 0, 1, 1, 1) sto(self.identifiers, gb) w = QGroupBox(_('&Comments'), tab0) sp = QSizePolicy() sp.setVerticalStretch(10) sp.setHorizontalPolicy(QSizePolicy.Expanding) sp.setVerticalPolicy(QSizePolicy.Expanding) w.setSizePolicy(sp) l = QHBoxLayout() w.setLayout(l) l.addWidget(self.comments) tab0.l.addWidget(w, 1, 0, 1, 2) # Tab 1 tab1 = self.tabs[1] wsp = QWidget(tab1) wgl = QVBoxLayout() wsp.setLayout(wgl) # right-hand side of splitter gb = QGroupBox(_('Change cover'), tab1) l = QGridLayout() gb.setLayout(l) for i, b in enumerate(self.cover.buttons[:3]): l.addWidget(b, 0, i, 1, 1) sto(b, self.cover.buttons[i+1]) hl = QHBoxLayout() for b in self.cover.buttons[3:]: hl.addWidget(b) sto(self.cover.buttons[-2], self.cover.buttons[-1]) l.addLayout(hl, 1, 0, 1, 3) wgl.addWidget(gb) wgl.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addWidget(self.formats_manager) self.splitter = QSplitter(Qt.Horizontal, tab1) tab1.l.addWidget(self.splitter) self.splitter.addWidget(self.cover) self.splitter.addWidget(wsp) self.formats_manager.formats.setMaximumWidth(10000) self.formats_manager.formats.setIconSize(QSize(64, 64))
def do_layout(self): self.central_widget.clear() self.tabs = [] self.labels = [] sto = QWidget.setTabOrder self.on_drag_enter.connect(self.handle_drag_enter) self.tabs.append(DragTrackingWidget(self, self.on_drag_enter)) self.central_widget.addTab(self.tabs[0], _("&Metadata")) self.tabs[0].l = QGridLayout() self.tabs[0].setLayout(self.tabs[0].l) self.tabs.append(QWidget(self)) self.central_widget.addTab(self.tabs[1], _("&Cover and formats")) self.tabs[1].l = QGridLayout() self.tabs[1].setLayout(self.tabs[1].l) # accept drop events so we can automatically switch to the second tab to # drop covers and formats self.tabs[0].setAcceptDrops(True) # Tab 0 tab0 = self.tabs[0] tl = QGridLayout() gb = QGroupBox(_('&Basic metadata'), self.tabs[0]) self.tabs[0].l.addWidget(gb, 0, 0, 1, 1) gb.setLayout(tl) self.button_box_layout.insertWidget(1, self.fetch_metadata_button) self.button_box_layout.insertWidget(2, self.config_metadata_button) sto(self.button_box, self.fetch_metadata_button) sto(self.fetch_metadata_button, self.config_metadata_button) sto(self.config_metadata_button, self.title) def create_row(row, widget, tab_to, button=None, icon=None, span=1): ql = BuddyLabel(widget) tl.addWidget(ql, row, 1, 1, 1) tl.addWidget(widget, row, 2, 1, 1) if button is not None: tl.addWidget(button, row, 3, span, 1) if icon is not None: button.setIcon(QIcon(I(icon))) if tab_to is not None: if button is not None: sto(widget, button) sto(button, tab_to) else: sto(widget, tab_to) tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1) tl.addWidget(self.manage_authors_button, 2, 0, 1, 1) tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1) tl.addWidget(self.tags_editor_button, 6, 0, 1, 1) create_row(0, self.title, self.title_sort, button=self.deduce_title_sort_button, span=2, icon='auto_author_sort.png') create_row(1, self.title_sort, self.authors) create_row(2, self.authors, self.author_sort, button=self.deduce_author_sort_button, span=2, icon='auto_author_sort.png') create_row(3, self.author_sort, self.series) create_row(4, self.series, self.series_index, button=self.clear_series_button, icon='trash.png') create_row(5, self.series_index, self.tags) create_row(6, self.tags, self.rating, button=self.clear_tags_button) create_row(7, self.rating, self.pubdate, button=self.clear_ratings_button) create_row(8, self.pubdate, self.publisher, button=self.pubdate.clear_button, icon='trash.png') create_row(9, self.publisher, self.languages) create_row(10, self.languages, self.timestamp) create_row(11, self.timestamp, self.identifiers, button=self.timestamp.clear_button, icon='trash.png') create_row(12, self.identifiers, self.comments, button=self.clear_identifiers_button, icon='trash.png') sto(self.clear_identifiers_button, self.swap_title_author_button) sto(self.swap_title_author_button, self.manage_authors_button) sto(self.manage_authors_button, self.tags_editor_button) sto(self.tags_editor_button, self.paste_isbn_button) tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding), 13, 1, 1, 1) w = getattr(self, 'custom_metadata_widgets_parent', None) if w is not None: gb = QGroupBox(_('C&ustom metadata'), tab0) gbl = QVBoxLayout() gb.setLayout(gbl) sr = QScrollArea(tab0) sr.setWidgetResizable(True) sr.setFrameStyle(QFrame.NoFrame) sr.setWidget(w) gbl.addWidget(sr) self.tabs[0].l.addWidget(gb, 0, 1, 1, 1) sto(self.identifiers, gb) w = QGroupBox(_('&Comments'), tab0) sp = QSizePolicy() sp.setVerticalStretch(10) sp.setHorizontalPolicy(QSizePolicy.Expanding) sp.setVerticalPolicy(QSizePolicy.Expanding) w.setSizePolicy(sp) l = QHBoxLayout() w.setLayout(l) l.addWidget(self.comments) tab0.l.addWidget(w, 1, 0, 1, 2) # Tab 1 tab1 = self.tabs[1] wsp = QWidget(tab1) wgl = QVBoxLayout() wsp.setLayout(wgl) # right-hand side of splitter gb = QGroupBox(_('Change cover'), tab1) l = QGridLayout() gb.setLayout(l) for i, b in enumerate(self.cover.buttons[:3]): l.addWidget(b, 0, i, 1, 1) sto(b, self.cover.buttons[i + 1]) hl = QHBoxLayout() for b in self.cover.buttons[3:]: hl.addWidget(b) sto(self.cover.buttons[-2], self.cover.buttons[-1]) l.addLayout(hl, 1, 0, 1, 3) wgl.addWidget(gb) wgl.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Expanding)) wgl.addWidget(self.formats_manager) self.splitter = QSplitter(Qt.Horizontal, tab1) tab1.l.addWidget(self.splitter) self.splitter.addWidget(self.cover) self.splitter.addWidget(wsp) self.formats_manager.formats.setMaximumWidth(10000) self.formats_manager.formats.setIconSize(QSize(64, 64))
class AnnotationsAppearance(SizePersistedDialog): ''' Dialog for managing CSS rules, including Preview window ''' if isosx: FONT = QFont('Monaco', 12) elif iswindows: FONT = QFont('Lucida Console', 9) elif islinux: FONT = QFont('Monospace', 9) FONT.setStyleHint(QFont.TypeWriter) def __init__(self, parent, icon, prefs): self.opts = parent.opts self.parent = parent self.prefs = prefs self.icon = icon super(AnnotationsAppearance, self).__init__(parent, 'appearance_dialog') self.setWindowTitle('Annotations appearance') self.setWindowIcon(icon) self.l = QVBoxLayout(self) self.setLayout(self.l) # Add a label for description #self.description_label = QLabel("Descriptive text here") #self.l.addWidget(self.description_label) # Add a group box, vertical layout for preview window self.preview_gb = QGroupBox(self) self.preview_gb.setTitle("Preview") self.preview_vl = QVBoxLayout(self.preview_gb) self.l.addWidget(self.preview_gb) self.wv = QWebView() self.wv.setHtml('<p></p>') self.wv.setMinimumHeight(100) self.wv.setMaximumHeight(16777215) self.wv.setGeometry(0, 0, 200, 100) self.wv.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.preview_vl.addWidget(self.wv) # Create a group box, horizontal layout for the table self.css_table_gb = QGroupBox(self) self.css_table_gb.setTitle("Annotation elements") self.elements_hl = QHBoxLayout(self.css_table_gb) self.l.addWidget(self.css_table_gb) # Add the group box to the main layout self.elements_table = AnnotationElementsTable(self, 'annotation_elements_tw') self.elements_hl.addWidget(self.elements_table) self.elements_table.initialize() # Options self.options_gb = QGroupBox(self) self.options_gb.setTitle("Options") self.options_gl = QGridLayout(self.options_gb) self.l.addWidget(self.options_gb) current_row = 0 # <hr/> separator # addWidget(widget, row, col, rowspan, colspan) self.hr_checkbox = QCheckBox('Add horizontal rule between annotations') self.hr_checkbox.stateChanged.connect(self.hr_checkbox_changed) self.hr_checkbox.setCheckState( prefs.get('appearance_hr_checkbox', False)) self.options_gl.addWidget(self.hr_checkbox, current_row, 0, 1, 4) current_row += 1 # Timestamp self.timestamp_fmt_label = QLabel("Timestamp format:") self.options_gl.addWidget(self.timestamp_fmt_label, current_row, 0) self.timestamp_fmt_le = QLineEdit( prefs.get('appearance_timestamp_format', default_timestamp), parent=self) self.timestamp_fmt_le.textEdited.connect(self.timestamp_fmt_changed) self.timestamp_fmt_le.setFont(self.FONT) self.timestamp_fmt_le.setObjectName('timestamp_fmt_le') self.timestamp_fmt_le.setToolTip('Format string for timestamp') self.timestamp_fmt_le.setMaximumWidth(16777215) self.timestamp_fmt_le.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.options_gl.addWidget(self.timestamp_fmt_le, current_row, 1) self.timestamp_fmt_reset_tb = QToolButton(self) self.timestamp_fmt_reset_tb.setToolTip("Reset to default") self.timestamp_fmt_reset_tb.setIcon(QIcon(I('trash.png'))) self.timestamp_fmt_reset_tb.clicked.connect(self.reset_timestamp_to_default) self.options_gl.addWidget(self.timestamp_fmt_reset_tb, current_row, 2) self.timestamp_fmt_help_tb = QToolButton(self) self.timestamp_fmt_help_tb.setToolTip("Format string reference") self.timestamp_fmt_help_tb.setIcon(QIcon(I('help.png'))) self.timestamp_fmt_help_tb.clicked.connect(self.show_help) self.options_gl.addWidget(self.timestamp_fmt_help_tb, current_row, 3) # Button box bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.l.addWidget(bb) # Spacer self.spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.l.addItem(self.spacerItem) # Sizing sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.resize_dialog() def hr_checkbox_changed(self, state): self.prefs.set('appearance_hr_checkbox', state) self.prefs.commit() self.elements_table.preview_css() def reset_timestamp_to_default(self): from calibre_plugins.marvin_manager.appearance import default_timestamp self.timestamp_fmt_le.setText(default_timestamp) self.timestamp_fmt_changed() def show_help(self): ''' Display strftime help file ''' from calibre.gui2 import open_url path = os.path.join(self.parent.resources_path, 'help/timestamp_formats.html') open_url(QUrl.fromLocalFile(path)) def sizeHint(self): return QtCore.QSize(600, 200) def timestamp_fmt_changed(self): self.prefs.set('appearance_timestamp_format', str(self.timestamp_fmt_le.text())) self.prefs.commit() self.elements_table.preview_css()
class ConfigWidget(QWidget, Logger): ''' Config dialog for Marvin Manager ''' WIZARD_PROFILES = { 'Annotations': { 'label': 'mm_annotations', 'datatype': 'comments', 'display': {}, 'is_multiple': False }, 'Collections': { 'label': 'mm_collections', 'datatype': 'text', 'display': { u'is_names': False }, 'is_multiple': True }, 'Last read': { 'label': 'mm_date_read', 'datatype': 'datetime', 'display': {}, 'is_multiple': False }, 'Progress': { 'label': 'mm_progress', 'datatype': 'float', 'display': { u'number_format': u'{0:.0f}%' }, 'is_multiple': False }, 'Read': { 'label': 'mm_read', 'datatype': 'bool', 'display': {}, 'is_multiple': False }, 'Reading list': { 'label': 'mm_reading_list', 'datatype': 'bool', 'display': {}, 'is_multiple': False }, 'Word count': { 'label': 'mm_word_count', 'datatype': 'int', 'display': { u'number_format': u'{0:n}' }, 'is_multiple': False } } def __init__(self, plugin_action): QWidget.__init__(self) self.parent = plugin_action self.gui = get_gui() self.icon = plugin_action.icon self.opts = plugin_action.opts self.prefs = plugin_prefs self.resources_path = plugin_action.resources_path self.verbose = plugin_action.verbose self.restart_required = False self._log_location() self.l = QGridLayout() self.setLayout(self.l) self.column1_layout = QVBoxLayout() self.l.addLayout(self.column1_layout, 0, 0) self.column2_layout = QVBoxLayout() self.l.addLayout(self.column2_layout, 0, 1) # ----------------------------- Column 1 ----------------------------- # ~~~~~~~~ Create the Custom fields options group box ~~~~~~~~ self.cfg_custom_fields_gb = QGroupBox(self) self.cfg_custom_fields_gb.setTitle('Custom column assignments') self.column1_layout.addWidget(self.cfg_custom_fields_gb) self.cfg_custom_fields_qgl = QGridLayout(self.cfg_custom_fields_gb) current_row = 0 # ++++++++ Labels + HLine ++++++++ self.marvin_source_label = QLabel("Marvin source") self.cfg_custom_fields_qgl.addWidget(self.marvin_source_label, current_row, 0) self.calibre_destination_label = QLabel("calibre destination") self.cfg_custom_fields_qgl.addWidget(self.calibre_destination_label, current_row, 1) current_row += 1 self.sd_hl = QFrame(self.cfg_custom_fields_gb) self.sd_hl.setFrameShape(QFrame.HLine) self.sd_hl.setFrameShadow(QFrame.Raised) self.cfg_custom_fields_qgl.addWidget(self.sd_hl, current_row, 0, 1, 3) current_row += 1 # ++++++++ Annotations ++++++++ self.cfg_annotations_label = QLabel('Annotations') self.cfg_annotations_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_annotations_label, current_row, 0) self.annotations_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.annotations_field_comboBox.setObjectName( 'annotations_field_comboBox') self.annotations_field_comboBox.setToolTip( 'Select a custom column to store Marvin annotations') self.cfg_custom_fields_qgl.addWidget(self.annotations_field_comboBox, current_row, 1) self.cfg_highlights_wizard = QToolButton() self.cfg_highlights_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_highlights_wizard.setToolTip( "Create a custom column to store Marvin annotations") self.cfg_highlights_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Annotations')) self.cfg_custom_fields_qgl.addWidget(self.cfg_highlights_wizard, current_row, 2) current_row += 1 # ++++++++ Collections ++++++++ self.cfg_collections_label = QLabel('Collections') self.cfg_collections_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_label, current_row, 0) self.collection_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.collection_field_comboBox.setObjectName( 'collection_field_comboBox') self.collection_field_comboBox.setToolTip( 'Select a custom column to store Marvin collection assignments') self.cfg_custom_fields_qgl.addWidget(self.collection_field_comboBox, current_row, 1) self.cfg_collections_wizard = QToolButton() self.cfg_collections_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_collections_wizard.setToolTip( "Create a custom column for Marvin collection assignments") self.cfg_collections_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Collections')) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_wizard, current_row, 2) current_row += 1 # ++++++++ Last read ++++++++ self.cfg_date_read_label = QLabel("Last read") self.cfg_date_read_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_date_read_label, current_row, 0) self.date_read_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.date_read_field_comboBox.setObjectName('date_read_field_comboBox') self.date_read_field_comboBox.setToolTip( 'Select a custom column to store Last read date') self.cfg_custom_fields_qgl.addWidget(self.date_read_field_comboBox, current_row, 1) self.cfg_collections_wizard = QToolButton() self.cfg_collections_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_collections_wizard.setToolTip( "Create a custom column to store Last read date") self.cfg_collections_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Last read')) self.cfg_custom_fields_qgl.addWidget(self.cfg_collections_wizard, current_row, 2) current_row += 1 # ++++++++ Progress ++++++++ self.cfg_progress_label = QLabel('Progress') self.cfg_progress_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_progress_label, current_row, 0) self.progress_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.progress_field_comboBox.setObjectName('progress_field_comboBox') self.progress_field_comboBox.setToolTip( 'Select a custom column to store Marvin reading progress') self.cfg_custom_fields_qgl.addWidget(self.progress_field_comboBox, current_row, 1) self.cfg_progress_wizard = QToolButton() self.cfg_progress_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_progress_wizard.setToolTip( "Create a custom column to store Marvin reading progress") self.cfg_progress_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Progress')) self.cfg_custom_fields_qgl.addWidget(self.cfg_progress_wizard, current_row, 2) current_row += 1 # ++++++++ Read flag ++++++++ self.cfg_read_label = QLabel('Read') self.cfg_read_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_read_label, current_row, 0) self.read_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.read_field_comboBox.setObjectName('read_field_comboBox') self.read_field_comboBox.setToolTip( 'Select a custom column to store Marvin Read status') self.cfg_custom_fields_qgl.addWidget(self.read_field_comboBox, current_row, 1) self.cfg_read_wizard = QToolButton() self.cfg_read_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_read_wizard.setToolTip( "Create a custom column to store Marvin Read status") self.cfg_read_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Read')) self.cfg_custom_fields_qgl.addWidget(self.cfg_read_wizard, current_row, 2) current_row += 1 # ++++++++ Reading list flag ++++++++ self.cfg_reading_list_label = QLabel('Reading list') self.cfg_reading_list_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_reading_list_label, current_row, 0) self.reading_list_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.reading_list_field_comboBox.setObjectName( 'reading_list_field_comboBox') self.reading_list_field_comboBox.setToolTip( 'Select a custom column to store Marvin Reading list status') self.cfg_custom_fields_qgl.addWidget(self.reading_list_field_comboBox, current_row, 1) self.cfg_reading_list_wizard = QToolButton() self.cfg_reading_list_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_reading_list_wizard.setToolTip( "Create a custom column to store Marvin Reading list status") self.cfg_reading_list_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Reading list')) self.cfg_custom_fields_qgl.addWidget(self.cfg_reading_list_wizard, current_row, 2) current_row += 1 # ++++++++ Word count ++++++++ self.cfg_word_count_label = QLabel('Word count') self.cfg_word_count_label.setAlignment(Qt.AlignLeft) self.cfg_custom_fields_qgl.addWidget(self.cfg_word_count_label, current_row, 0) self.word_count_field_comboBox = QComboBox(self.cfg_custom_fields_gb) self.word_count_field_comboBox.setObjectName( 'word_count_field_comboBox') self.word_count_field_comboBox.setToolTip( 'Select a custom column to store Marvin word counts') self.cfg_custom_fields_qgl.addWidget(self.word_count_field_comboBox, current_row, 1) self.cfg_word_count_wizard = QToolButton() self.cfg_word_count_wizard.setIcon(QIcon(I('wizard.png'))) self.cfg_word_count_wizard.setToolTip( "Create a custom column to store Marvin word counts") self.cfg_word_count_wizard.clicked.connect( partial(self.launch_cc_wizard, 'Word count')) self.cfg_custom_fields_qgl.addWidget(self.cfg_word_count_wizard, current_row, 2) current_row += 1 self.spacerItem1 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) self.column1_layout.addItem(self.spacerItem1) # ----------------------------- Column 2 ----------------------------- # ~~~~~~~~ Create the CSS group box ~~~~~~~~ self.cfg_css_options_gb = QGroupBox(self) self.cfg_css_options_gb.setTitle('CSS') self.column2_layout.addWidget(self.cfg_css_options_gb) self.cfg_css_options_qgl = QGridLayout(self.cfg_css_options_gb) current_row = 0 # ++++++++ Annotations appearance ++++++++ self.annotations_icon = QIcon( os.path.join(self.resources_path, 'icons', 'annotations_hiliter.png')) self.cfg_annotations_appearance_toolbutton = QToolButton() self.cfg_annotations_appearance_toolbutton.setIcon( self.annotations_icon) self.cfg_annotations_appearance_toolbutton.clicked.connect( self.configure_appearance) self.cfg_css_options_qgl.addWidget( self.cfg_annotations_appearance_toolbutton, current_row, 0) self.cfg_annotations_label = ClickableQLabel("Annotations") self.connect(self.cfg_annotations_label, SIGNAL('clicked()'), self.configure_appearance) self.cfg_css_options_qgl.addWidget(self.cfg_annotations_label, current_row, 1) current_row += 1 # ++++++++ Injected CSS ++++++++ self.css_editor_icon = QIcon(I('format-text-heading.png')) self.cfg_css_editor_toolbutton = QToolButton() self.cfg_css_editor_toolbutton.setIcon(self.css_editor_icon) self.cfg_css_editor_toolbutton.clicked.connect(self.edit_css) self.cfg_css_options_qgl.addWidget(self.cfg_css_editor_toolbutton, current_row, 0) self.cfg_css_editor_label = ClickableQLabel("Articles, Vocabulary") self.connect(self.cfg_css_editor_label, SIGNAL('clicked()'), self.edit_css) self.cfg_css_options_qgl.addWidget(self.cfg_css_editor_label, current_row, 1) """ # ~~~~~~~~ Create the Dropbox syncing group box ~~~~~~~~ self.cfg_dropbox_syncing_gb = QGroupBox(self) self.cfg_dropbox_syncing_gb.setTitle('Dropbox') self.column2_layout.addWidget(self.cfg_dropbox_syncing_gb) self.cfg_dropbox_syncing_qgl = QGridLayout(self.cfg_dropbox_syncing_gb) current_row = 0 # ++++++++ Syncing enabled checkbox ++++++++ self.dropbox_syncing_checkbox = QCheckBox('Enable Dropbox updates') self.dropbox_syncing_checkbox.setObjectName('dropbox_syncing') self.dropbox_syncing_checkbox.setToolTip('Refresh custom column content from Marvin metadata') self.cfg_dropbox_syncing_qgl.addWidget(self.dropbox_syncing_checkbox, current_row, 0, 1, 3) current_row += 1 # ++++++++ Dropbox folder picker ++++++++ self.dropbox_folder_icon = QIcon(os.path.join(self.resources_path, 'icons', 'dropbox.png')) self.cfg_dropbox_folder_toolbutton = QToolButton() self.cfg_dropbox_folder_toolbutton.setIcon(self.dropbox_folder_icon) self.cfg_dropbox_folder_toolbutton.setToolTip("Specify Dropbox folder location on your computer") self.cfg_dropbox_folder_toolbutton.clicked.connect(self.select_dropbox_folder) self.cfg_dropbox_syncing_qgl.addWidget(self.cfg_dropbox_folder_toolbutton, current_row, 1) # ++++++++ Dropbox location lineedit ++++++++ self.dropbox_location_lineedit = QLineEdit() self.dropbox_location_lineedit.setPlaceholderText("Dropbox folder location") self.cfg_dropbox_syncing_qgl.addWidget(self.dropbox_location_lineedit, current_row, 2) """ # ~~~~~~~~ Create the General options group box ~~~~~~~~ self.cfg_runtime_options_gb = QGroupBox(self) self.cfg_runtime_options_gb.setTitle('General options') self.column2_layout.addWidget(self.cfg_runtime_options_gb) self.cfg_runtime_options_qvl = QVBoxLayout(self.cfg_runtime_options_gb) # ++++++++ Auto refresh checkbox ++++++++ self.auto_refresh_checkbox = QCheckBox( 'Automatically refresh custom column content') self.auto_refresh_checkbox.setObjectName('auto_refresh_at_startup') self.auto_refresh_checkbox.setToolTip( 'Update calibre custom column when Marvin XD is opened') self.cfg_runtime_options_qvl.addWidget(self.auto_refresh_checkbox) # ++++++++ Progress as percentage checkbox ++++++++ self.reading_progress_checkbox = QCheckBox( 'Show reading progress as percentage') self.reading_progress_checkbox.setObjectName( 'show_progress_as_percentage') self.reading_progress_checkbox.setToolTip( 'Display percentage in Progress column') self.cfg_runtime_options_qvl.addWidget(self.reading_progress_checkbox) # ~~~~~~~~ Create the Debug options group box ~~~~~~~~ self.cfg_debug_options_gb = QGroupBox(self) self.cfg_debug_options_gb.setTitle('Debug options') self.column2_layout.addWidget(self.cfg_debug_options_gb) self.cfg_debug_options_qvl = QVBoxLayout(self.cfg_debug_options_gb) # ++++++++ Debug logging checkboxes ++++++++ self.debug_plugin_checkbox = QCheckBox( 'Enable debug logging for Marvin XD') self.debug_plugin_checkbox.setObjectName('debug_plugin_checkbox') self.debug_plugin_checkbox.setToolTip( 'Print plugin diagnostic messages to console') self.cfg_debug_options_qvl.addWidget(self.debug_plugin_checkbox) self.debug_libimobiledevice_checkbox = QCheckBox( 'Enable debug logging for libiMobileDevice') self.debug_libimobiledevice_checkbox.setObjectName( 'debug_libimobiledevice_checkbox') self.debug_libimobiledevice_checkbox.setToolTip( 'Print libiMobileDevice diagnostic messages to console') self.cfg_debug_options_qvl.addWidget( self.debug_libimobiledevice_checkbox) self.spacerItem2 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) self.column2_layout.addItem(self.spacerItem2) # ~~~~~~~~ End of construction zone ~~~~~~~~ self.resize(self.sizeHint()) # ~~~~~~~~ Populate/restore config options ~~~~~~~~ # Annotations comboBox self.populate_annotations() self.populate_collections() self.populate_date_read() self.populate_progress() self.populate_read() self.populate_reading_list() self.populate_word_count() """ # Restore Dropbox settings, hook changes dropbox_syncing = self.prefs.get('dropbox_syncing', False) self.dropbox_syncing_checkbox.setChecked(dropbox_syncing) self.set_dropbox_syncing(dropbox_syncing) self.dropbox_syncing_checkbox.clicked.connect(partial(self.set_dropbox_syncing)) self.dropbox_location_lineedit.setText(self.prefs.get('dropbox_folder', '')) """ # Restore general settings self.auto_refresh_checkbox.setChecked( self.prefs.get('auto_refresh_at_startup', False)) self.reading_progress_checkbox.setChecked( self.prefs.get('show_progress_as_percentage', False)) # Restore debug settings, hook changes self.debug_plugin_checkbox.setChecked( self.prefs.get('debug_plugin', False)) self.debug_plugin_checkbox.stateChanged.connect( self.set_restart_required) self.debug_libimobiledevice_checkbox.setChecked( self.prefs.get('debug_libimobiledevice', False)) self.debug_libimobiledevice_checkbox.stateChanged.connect( self.set_restart_required) # Hook changes to Annotations comboBox # self.annotations_field_comboBox.currentIndexChanged.connect( # partial(self.save_combobox_setting, 'annotations_field_comboBox')) self.connect(self.annotations_field_comboBox, SIGNAL('currentIndexChanged(const QString &)'), self.annotations_destination_changed) # Launch the annotated_books_scanner field = get_cc_mapping('annotations', 'field', None) self.annotated_books_scanner = InventoryAnnotatedBooks(self.gui, field) self.connect(self.annotated_books_scanner, self.annotated_books_scanner.signal, self.inventory_complete) QTimer.singleShot(1, self.start_inventory) def annotations_destination_changed(self, qs_new_destination_name): ''' If the destination field changes, move all existing annotations from old to new ''' self._log_location(str(qs_new_destination_name)) #self._log("self.eligible_annotations_fields: %s" % self.eligible_annotations_fields) old_destination_field = get_cc_mapping('annotations', 'field', None) old_destination_name = get_cc_mapping('annotations', 'combobox', None) self._log("old_destination_field: %s" % old_destination_field) self._log("old_destination_name: %s" % old_destination_name) new_destination_name = unicode(qs_new_destination_name) self._log("new_destination_name: %s" % new_destination_name) if old_destination_name == new_destination_name: self._log_location( "old_destination_name = new_destination_name, no changes") return new_destination_field = self.eligible_annotations_fields[ new_destination_name] if existing_annotations(self.parent, old_destination_field): command = self.launch_new_destination_dialog( old_destination_name, new_destination_name) if command == 'move': set_cc_mapping('annotations', field=new_destination_field, combobox=new_destination_name) if self.annotated_books_scanner.isRunning(): self.annotated_books_scanner.wait() move_annotations(self, self.annotated_books_scanner.annotation_map, old_destination_field, new_destination_field) elif command == 'change': # Keep the updated destination field, but don't move annotations pass elif command == 'cancel': # Restore previous destination self.annotations_field_comboBox.blockSignals(True) old_index = self.annotations_field_comboBox.findText( old_destination_name) self.annotations_field_comboBox.setCurrentIndex(old_index) self.annotations_field_comboBox.blockSignals(False) else: # No existing annotations, just update prefs self._log("no existing annotations, updating destination to '{0}'". format(new_destination_name)) set_cc_mapping('annotations', field=new_destination_field, combobox=new_destination_name) def configure_appearance(self): ''' ''' self._log_location() appearance_settings = { 'appearance_css': default_elements, 'appearance_hr_checkbox': False, 'appearance_timestamp_format': default_timestamp } # Save, hash the original settings original_settings = {} osh = hashlib.md5() for setting in appearance_settings: original_settings[setting] = plugin_prefs.get( setting, appearance_settings[setting]) osh.update( repr(plugin_prefs.get(setting, appearance_settings[setting]))) # Display the Annotations appearance dialog aa = AnnotationsAppearance(self, self.annotations_icon, plugin_prefs) cancelled = False if aa.exec_(): # appearance_hr_checkbox and appearance_timestamp_format changed live to prefs during previews plugin_prefs.set('appearance_css', aa.elements_table.get_data()) # Generate a new hash nsh = hashlib.md5() for setting in appearance_settings: nsh.update( repr( plugin_prefs.get(setting, appearance_settings[setting]))) else: for setting in appearance_settings: plugin_prefs.set(setting, original_settings[setting]) nsh = osh # If there were changes, and there are existing annotations, # and there is an active Annotations field, offer to re-render field = get_cc_mapping('annotations', 'field', None) if osh.digest() != nsh.digest() and existing_annotations( self.parent, field): title = 'Update annotations?' msg = '<p>Update existing annotations to new appearance settings?</p>' d = MessageBox(MessageBox.QUESTION, title, msg, show_copy_button=False) self._log_location("QUESTION: %s" % msg) if d.exec_(): self._log_location( "Updating existing annotations to modified appearance") # Wait for indexing to complete while not self.annotated_books_scanner.isFinished(): Application.processEvents() move_annotations(self, self.annotated_books_scanner.annotation_map, field, field, window_title="Updating appearance") def edit_css(self): ''' ''' self._log_location() from calibre_plugins.marvin_manager.book_status import dialog_resources_path klass = os.path.join(dialog_resources_path, 'css_editor.py') if os.path.exists(klass): sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('css_editor') sys.path.remove(dialog_resources_path) dlg = this_dc.CSSEditorDialog(self, 'css_editor') dlg.initialize(self) dlg.exec_() def get_eligible_custom_fields(self, eligible_types=[], is_multiple=None): ''' Discover qualifying custom fields for eligible_types[] ''' #self._log_location(eligible_types) eligible_custom_fields = {} for cf in self.gui.current_db.custom_field_keys(): cft = self.gui.current_db.metadata_for_field(cf)['datatype'] cfn = self.gui.current_db.metadata_for_field(cf)['name'] cfim = self.gui.current_db.metadata_for_field(cf)['is_multiple'] #self._log("cf: %s cft: %s cfn: %s cfim: %s" % (cf, cft, cfn, cfim)) if cft in eligible_types: if is_multiple is not None: if bool(cfim) == is_multiple: eligible_custom_fields[cfn] = cf else: eligible_custom_fields[cfn] = cf return eligible_custom_fields def inventory_complete(self, msg): self._log_location(msg) def launch_cc_wizard(self, column_type): ''' ''' def _update_combo_box(comboBox, destination, previous): ''' ''' cb = getattr(self, comboBox) cb.blockSignals(True) all_items = [str(cb.itemText(i)) for i in range(cb.count())] if previous and previous in all_items: all_items.remove(previous) all_items.append(destination) cb.clear() cb.addItems(sorted(all_items, key=lambda s: s.lower())) # Select the new destination in the comboBox idx = cb.findText(destination) if idx > -1: cb.setCurrentIndex(idx) cb.blockSignals(False) from calibre_plugins.marvin_manager.book_status import dialog_resources_path klass = os.path.join(dialog_resources_path, 'cc_wizard.py') if os.path.exists(klass): #self._log("importing CC Wizard dialog from '%s'" % klass) sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('cc_wizard') sys.path.remove(dialog_resources_path) dlg = this_dc.CustomColumnWizard(self, column_type, self.WIZARD_PROFILES[column_type], verbose=True) dlg.exec_() if dlg.modified_column: self._log("modified_column: %s" % dlg.modified_column) self.restart_required = True destination = dlg.modified_column['destination'] label = dlg.modified_column['label'] previous = dlg.modified_column['previous'] source = dlg.modified_column['source'] if source == "Annotations": _update_combo_box("annotations_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_annotations_fields[destination] = label # Save manually in case user cancels set_cc_mapping('annotations', combobox=destination, field=label) elif source == 'Collections': _update_combo_box("collection_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_collection_fields[destination] = label # Save manually in case user cancels set_cc_mapping('collections', combobox=destination, field=label) elif source == 'Last read': _update_combo_box("date_read_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_date_read_fields[destination] = label # Save manually in case user cancels set_cc_mapping('date_read', combobox=destination, field=label) elif source == "Progress": _update_combo_box("progress_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_progress_fields[destination] = label # Save manually in case user cancels set_cc_mapping('progress', combobox=destination, field=label) elif source == "Read": _update_combo_box("read_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_read_fields[destination] = label # Save manually in case user cancels set_cc_mapping('read', combobox=destination, field=label) elif source == "Reading list": _update_combo_box("reading_list_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_reading_list_fields[destination] = label # Save manually in case user cancels set_cc_mapping('reading_list', combobox=destination, field=label) elif source == "Word count": _update_combo_box("word_count_field_comboBox", destination, previous) # Add/update the new destination so save_settings() can find it self.eligible_word_count_fields[destination] = label # Save manually in case user cancels set_cc_mapping('word_count', combobox=destination, field=label) else: self._log("ERROR: Can't import from '%s'" % klass) def launch_new_destination_dialog(self, old, new): ''' Return 'move', 'change' or 'cancel' ''' from calibre_plugins.marvin_manager.book_status import dialog_resources_path self._log_location() klass = os.path.join(dialog_resources_path, 'new_destination.py') if os.path.exists(klass): self._log("importing new destination dialog from '%s'" % klass) sys.path.insert(0, dialog_resources_path) this_dc = importlib.import_module('new_destination') sys.path.remove(dialog_resources_path) dlg = this_dc.NewDestinationDialog(self, old, new) dlg.exec_() return dlg.command def populate_annotations(self): datatype = self.WIZARD_PROFILES['Annotations']['datatype'] self.eligible_annotations_fields = self.get_eligible_custom_fields( [datatype]) self.annotations_field_comboBox.addItems(['']) ecf = sorted(self.eligible_annotations_fields.keys(), key=lambda s: s.lower()) self.annotations_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('annotations', 'combobox') if existing: ci = self.annotations_field_comboBox.findText(existing) self.annotations_field_comboBox.setCurrentIndex(ci) def populate_collections(self): datatype = self.WIZARD_PROFILES['Collections']['datatype'] self.eligible_collection_fields = self.get_eligible_custom_fields( [datatype], is_multiple=True) self.collection_field_comboBox.addItems(['']) ecf = sorted(self.eligible_collection_fields.keys(), key=lambda s: s.lower()) self.collection_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('collections', 'combobox') if existing: ci = self.collection_field_comboBox.findText(existing) self.collection_field_comboBox.setCurrentIndex(ci) def populate_date_read(self): #self.eligible_date_read_fields = self.get_eligible_custom_fields(['datetime']) datatype = self.WIZARD_PROFILES['Last read']['datatype'] self.eligible_date_read_fields = self.get_eligible_custom_fields( [datatype]) self.date_read_field_comboBox.addItems(['']) ecf = sorted(self.eligible_date_read_fields.keys(), key=lambda s: s.lower()) self.date_read_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('date_read', 'combobox') if existing: ci = self.date_read_field_comboBox.findText(existing) self.date_read_field_comboBox.setCurrentIndex(ci) def populate_progress(self): #self.eligible_progress_fields = self.get_eligible_custom_fields(['float']) datatype = self.WIZARD_PROFILES['Progress']['datatype'] self.eligible_progress_fields = self.get_eligible_custom_fields( [datatype]) self.progress_field_comboBox.addItems(['']) ecf = sorted(self.eligible_progress_fields.keys(), key=lambda s: s.lower()) self.progress_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('progress', 'combobox') if existing: ci = self.progress_field_comboBox.findText(existing) self.progress_field_comboBox.setCurrentIndex(ci) def populate_read(self): datatype = self.WIZARD_PROFILES['Read']['datatype'] self.eligible_read_fields = self.get_eligible_custom_fields([datatype]) self.read_field_comboBox.addItems(['']) ecf = sorted(self.eligible_read_fields.keys(), key=lambda s: s.lower()) self.read_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('read', 'combobox') if existing: ci = self.read_field_comboBox.findText(existing) self.read_field_comboBox.setCurrentIndex(ci) def populate_reading_list(self): datatype = self.WIZARD_PROFILES['Reading list']['datatype'] self.eligible_reading_list_fields = self.get_eligible_custom_fields( [datatype]) self.reading_list_field_comboBox.addItems(['']) ecf = sorted(self.eligible_reading_list_fields.keys(), key=lambda s: s.lower()) self.reading_list_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('reading_list', 'combobox') if existing: ci = self.reading_list_field_comboBox.findText(existing) self.reading_list_field_comboBox.setCurrentIndex(ci) def populate_word_count(self): #self.eligible_word_count_fields = self.get_eligible_custom_fields(['int']) datatype = self.WIZARD_PROFILES['Word count']['datatype'] self.eligible_word_count_fields = self.get_eligible_custom_fields( [datatype]) self.word_count_field_comboBox.addItems(['']) ecf = sorted(self.eligible_word_count_fields.keys(), key=lambda s: s.lower()) self.word_count_field_comboBox.addItems(ecf) # Retrieve stored value existing = get_cc_mapping('word_count', 'combobox') if existing: ci = self.word_count_field_comboBox.findText(existing) self.word_count_field_comboBox.setCurrentIndex(ci) """ def select_dropbox_folder(self): ''' ''' self._log_location() dropbox_location = QFileDialog.getExistingDirectory( self, "Dropbox folder", os.path.expanduser("~"), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) self.dropbox_location_lineedit.setText(unicode(dropbox_location)) def set_dropbox_syncing(self, state): ''' Called when checkbox changes state, or when restoring state Set enabled state of Dropbox folder picker to match ''' self.cfg_dropbox_folder_toolbutton.setEnabled(state) self.dropbox_location_lineedit.setEnabled(state) """ def set_restart_required(self, state): ''' Set restart_required flag to show show dialog when closing dialog ''' self.restart_required = True """ def save_combobox_setting(self, cb, index): ''' Apply changes immediately ''' cf = str(getattr(self, cb).currentText()) self._log_location("%s => %s" % (cb, repr(cf))) if cb == 'annotations_field_comboBox': field = None if cf: field = self.eligible_annotations_fields[cf] set_cc_mapping('annotations', combobox=cf, field=field) """ def save_settings(self): self._log_location() # Annotations cf = unicode(self.annotations_field_comboBox.currentText()) field = None if cf: field = self.eligible_annotations_fields[cf] set_cc_mapping('annotations', combobox=cf, field=field) # Collections cf = unicode(self.collection_field_comboBox.currentText()) field = None if cf: field = self.eligible_collection_fields[cf] set_cc_mapping('collections', combobox=cf, field=field) # Save Date read field cf = unicode(self.date_read_field_comboBox.currentText()) field = None if cf: field = self.eligible_date_read_fields[cf] set_cc_mapping('date_read', combobox=cf, field=field) # Save Progress field cf = unicode(self.progress_field_comboBox.currentText()) field = None if cf: field = self.eligible_progress_fields[cf] set_cc_mapping('progress', combobox=cf, field=field) # Save Read field cf = unicode(self.read_field_comboBox.currentText()) field = None if cf: field = self.eligible_read_fields[cf] set_cc_mapping('read', combobox=cf, field=field) # Save Reading list field cf = unicode(self.reading_list_field_comboBox.currentText()) field = None if cf: field = self.eligible_reading_list_fields[cf] set_cc_mapping('reading_list', combobox=cf, field=field) # Save Word count field cf = unicode(self.word_count_field_comboBox.currentText()) field = None if cf: field = self.eligible_word_count_fields[cf] set_cc_mapping('word_count', combobox=cf, field=field) ''' # Save Dropbox settings self.prefs.set('dropbox_syncing', self.dropbox_syncing_checkbox.isChecked()) self.prefs.set('dropbox_folder', unicode(self.dropbox_location_lineedit.text())) ''' # Save general settings self.prefs.set('auto_refresh_at_startup', self.auto_refresh_checkbox.isChecked()) self.prefs.set('show_progress_as_percentage', self.reading_progress_checkbox.isChecked()) # Save debug settings self.prefs.set('debug_plugin', self.debug_plugin_checkbox.isChecked()) self.prefs.set('debug_libimobiledevice', self.debug_libimobiledevice_checkbox.isChecked()) # If restart needed, inform user if self.restart_required: do_restart = show_restart_warning( 'Restart calibre for the changes to be applied.', parent=self.gui) if do_restart: self.gui.quit(restart=True) def start_inventory(self): self._log_location() self.annotated_books_scanner.start()
def main(args): app = QApplication(args) w = QWidget() mainLayout2 = QVBoxLayout() mainLayout = QHBoxLayout() mainLayout2.addLayout(mainLayout) pbar = QProgressBar() pbar.setOrientation(2) pbar.setValue(0) p = Plot(pbar) mainLayout.addWidget(p) slider = QSlider(w) slider.setMinimum(int(t0*N)) slider.setMaximum(int(T*N)) p.slider = slider mainLayout.addWidget(slider) Layout2 = QVBoxLayout() Label1 = QLabel('T='+str(T), w) Label2 = QLabel('t='+str(t0+slider.value()*tau), w) Label2.setFixedWidth(50) Label3 = QLabel('t0='+str(t0), w) Layout2.addWidget(Label1) Layout2.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) ) Layout2.addWidget(Label2) Layout2.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) ) Layout2.addWidget(Label3) mainLayout.addLayout(Layout2) image = QImage() mainLayout.addWidget(pbar) p.label = Label2 p.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)); w.show() w.resize(600, 400) timer = QTimer() QObject.connect(slider, SIGNAL('valueChanged(int)'), p.Update) QObject.connect(timer, SIGNAL('timeout()'), p.timerEvent) QObject.connect(app, SIGNAL('lastWindowClosed()'), p.onClose) timer.start(100) p.timer = timer blay= QHBoxLayout() b1 = QPushButton("Save") b2 = QPushButton("Open") blay.addWidget(b1) blay.addWidget(b2) mainLayout2.addLayout(blay) w.setLayout(mainLayout2) QObject.connect(b1, SIGNAL('clicked()'), p.Save) QObject.connect(b2, SIGNAL('clicked()'), p.Open) app.exec_()
class Dialog(QDialog): def __init__(self, title, widget=None, closeButton=True, keySequence=None, isDialog=False, icon=None): QDialog.__init__(self, ctx.mainScreen) self.setObjectName("dialog") self.isDialog = isDialog self.layout = QVBoxLayout() self.setLayout(self.layout) self.wlayout = QHBoxLayout() if icon: self.setStyleSheet( """QDialog QLabel{ margin-left:16px;margin-right:10px} QDialog#dialog {background-image:url(':/images/%s.png'); background-repeat:no-repeat; background-position: top left; padding-left:500px;} """ % icon) self.windowTitle = windowTitle(self, closeButton) self.setTitle(title) self.layout.setMargin(0) self.layout.addWidget(self.windowTitle) if widget: self.addWidget(widget) QObject.connect(widget, SIGNAL("finished(int)"), self.reject) QObject.connect(widget, SIGNAL("resizeDialog(int,int)"), self.resize) if closeButton: QObject.connect(self.windowTitle.pushButton, SIGNAL("clicked()"), self.reject) if keySequence: shortCut = QShortcut(keySequence, self) QObject.connect(shortCut, SIGNAL("activated()"), self.reject) QMetaObject.connectSlotsByName(self) self.resize(10, 10) def setTitle(self, title): self.windowTitle.label.setText(title) def addWidget(self, widget): self.content = widget self.wlayout.addWidget(self.content) if self.isDialog: widget.setStyleSheet("QMessageBox { background:none }") self.layout.addItem( QSpacerItem(10, 10, QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)) self.layout.setContentsMargins(0, 0, 0, 8) self.layout.addLayout(self.wlayout) def setCentered(self): self.move(ctx.mainScreen.width() / 2 - self.width() / 2, ctx.mainScreen.height() / 2 - self.height() / 2) def exec_(self): QTimer.singleShot(0, self.setCentered) return QDialog.exec_(self)
class AnnotationsAppearance(SizePersistedDialog): ''' Dialog for managing CSS rules, including Preview window ''' if isosx: FONT = QFont('Monaco', 12) elif iswindows: FONT = QFont('Lucida Console', 9) elif islinux: FONT = QFont('Monospace', 9) FONT.setStyleHint(QFont.TypeWriter) def __init__(self, parent, icon, prefs): self.opts = parent.opts self.parent = parent self.prefs = prefs self.icon = icon super(AnnotationsAppearance, self).__init__(parent, 'appearance_dialog') self.setWindowTitle('Annotations appearance') self.setWindowIcon(icon) self.l = QVBoxLayout(self) self.setLayout(self.l) # Add a label for description #self.description_label = QLabel("Descriptive text here") #self.l.addWidget(self.description_label) # Add a group box, vertical layout for preview window self.preview_gb = QGroupBox(self) self.preview_gb.setTitle("Preview") self.preview_vl = QVBoxLayout(self.preview_gb) self.l.addWidget(self.preview_gb) self.wv = QWebView() self.wv.setHtml('<p></p>') self.wv.setMinimumHeight(100) self.wv.setMaximumHeight(16777215) self.wv.setGeometry(0, 0, 200, 100) self.wv.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.preview_vl.addWidget(self.wv) # Create a group box, horizontal layout for the table self.css_table_gb = QGroupBox(self) self.css_table_gb.setTitle("Annotation elements") self.elements_hl = QHBoxLayout(self.css_table_gb) self.l.addWidget(self.css_table_gb) # Add the group box to the main layout self.elements_table = AnnotationElementsTable( self, 'annotation_elements_tw') self.elements_hl.addWidget(self.elements_table) self.elements_table.initialize() # Options self.options_gb = QGroupBox(self) self.options_gb.setTitle("Options") self.options_gl = QGridLayout(self.options_gb) self.l.addWidget(self.options_gb) current_row = 0 # <hr/> separator # addWidget(widget, row, col, rowspan, colspan) self.hr_checkbox = QCheckBox('Add horizontal rule between annotations') self.hr_checkbox.stateChanged.connect(self.hr_checkbox_changed) self.hr_checkbox.setCheckState( prefs.get('appearance_hr_checkbox', False)) self.options_gl.addWidget(self.hr_checkbox, current_row, 0, 1, 4) current_row += 1 # Timestamp self.timestamp_fmt_label = QLabel("Timestamp format:") self.options_gl.addWidget(self.timestamp_fmt_label, current_row, 0) self.timestamp_fmt_le = QLineEdit(prefs.get( 'appearance_timestamp_format', default_timestamp), parent=self) self.timestamp_fmt_le.textEdited.connect(self.timestamp_fmt_changed) self.timestamp_fmt_le.setFont(self.FONT) self.timestamp_fmt_le.setObjectName('timestamp_fmt_le') self.timestamp_fmt_le.setToolTip('Format string for timestamp') self.timestamp_fmt_le.setMaximumWidth(16777215) self.timestamp_fmt_le.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.options_gl.addWidget(self.timestamp_fmt_le, current_row, 1) self.timestamp_fmt_reset_tb = QToolButton(self) self.timestamp_fmt_reset_tb.setToolTip("Reset to default") self.timestamp_fmt_reset_tb.setIcon(QIcon(I('trash.png'))) self.timestamp_fmt_reset_tb.clicked.connect( self.reset_timestamp_to_default) self.options_gl.addWidget(self.timestamp_fmt_reset_tb, current_row, 2) self.timestamp_fmt_help_tb = QToolButton(self) self.timestamp_fmt_help_tb.setToolTip("Format string reference") self.timestamp_fmt_help_tb.setIcon(QIcon(I('help.png'))) self.timestamp_fmt_help_tb.clicked.connect(self.show_help) self.options_gl.addWidget(self.timestamp_fmt_help_tb, current_row, 3) # Button box bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.l.addWidget(bb) # Spacer self.spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.l.addItem(self.spacerItem) # Sizing sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.resize_dialog() def hr_checkbox_changed(self, state): self.prefs.set('appearance_hr_checkbox', state) self.prefs.commit() self.elements_table.preview_css() def reset_timestamp_to_default(self): from calibre_plugins.marvin_manager.appearance import default_timestamp self.timestamp_fmt_le.setText(default_timestamp) self.timestamp_fmt_changed() def show_help(self): ''' Display strftime help file ''' from calibre.gui2 import open_url path = os.path.join(self.parent.resources_path, 'help/timestamp_formats.html') open_url(QUrl.fromLocalFile(path)) def sizeHint(self): return QtCore.QSize(600, 200) def timestamp_fmt_changed(self): self.prefs.set('appearance_timestamp_format', str(self.timestamp_fmt_le.text())) self.prefs.commit() self.elements_table.preview_css()