def __init__(self, parent=None): super(AddAreaDlg, self).__init__(parent) self.setWindowTitle("New Relief Device Area") name_label = QLabel("&Name:") self.name_lineedit = QLineEdit() self.name_lineedit.setMaxLength(200) name_label.setBuddy(self.name_lineedit) location_label = QLabel("&Location:") self.location_combobox = QComboBox() self.location_combobox.setEditable(True) location_label.setBuddy(self.location_combobox) self.browse_button = QPushButton("&Browse...") button_box = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) layout = QGridLayout() layout.addWidget(name_label, 0, 0) layout.addWidget(self.name_lineedit, 0, 1) layout.addWidget(location_label, 1, 0) layout.addWidget(self.location_combobox, 1, 1) layout.addWidget(self.browse_button, 1, 2) #layout.addWidget(QFrame.HLine, 2, 0) layout.addWidget(button_box, 2, 1) self.setLayout(layout) self.browse_button.clicked.connect(self.browseFiles) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject)
def __init__(self, root_node, parent=None): super(AddScenarioDlg, self).__init__(parent) self.setWindowTitle("Add Scenario") type_label = QLabel("&Scenario Type:") self.type_combobox = QComboBox() type_label.setBuddy(self.type_combobox) self.type_combobox.addItems(["External Fire", "Liquid Overfill", "Regulator Failure"]) device_label = QLabel("&Associated Relief Device:") self.device_combobox = QComboBox() device_label.setBuddy(self.device_combobox) for area in root_node.children: for device in area.children: self.device_combobox.addItem(device.name, device) button_box = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) layout = QGridLayout() layout.addWidget(type_label, 0, 0) layout.addWidget(self.type_combobox, 0, 1) layout.addWidget(device_label, 1, 0) layout.addWidget(self.device_combobox, 1, 1) layout.addWidget(button_box, 2, 1) self.setLayout(layout) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject)
def __init__(self, name, tendril, parent=None): super(TendrilWidget, self).__init__(parent) hlayout = QHBoxLayout(self) label = QLabel("&" + name) hlayout.addWidget(label) self.thunker = TendrilThunker(tendril) if tendril.val == True or tendril.val == False: spacer = QSpacerItem(0, 0, hPolicy=QSizePolicy.Expanding, vPolicy=QSizePolicy.Minimum) hlayout.addItem(spacer) checkbox = QCheckBox(self) checkbox.setCheckState( Qt.Checked if tendril.val else Qt.Unchecked) checkbox.stateChanged.connect(self.thunker.update) label.setBuddy(checkbox) hlayout.addWidget(checkbox) else: edit = QLineEdit(str(tendril.val), self) edit.textChanged.connect(self.thunker.update) label.setBuddy(edit) hlayout.addWidget(edit) self.setLayout(hlayout) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
def create_main_area(self, layout): # Master password master_password_label = QLabel("&Master-Passwort:") self.master_password_edit = QLineEdit() self.master_password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.master_password_edit.textChanged.connect(self.masterpassword_changed) self.master_password_edit.returnPressed.connect(self.move_focus) self.master_password_edit.editingFinished.connect(self.masterpassword_entered) self.master_password_edit.setMaximumHeight(28) master_password_label.setBuddy(self.master_password_edit) layout.addWidget(master_password_label) layout.addWidget(self.master_password_edit) # Domain domain_label = QLabel("&Domain:") self.domain_edit = QComboBox() self.domain_edit.setEditable(True) self.domain_edit.textChanged.connect(self.domain_changed) self.domain_edit.currentIndexChanged.connect(self.domain_changed) self.domain_edit.lineEdit().editingFinished.connect(self.domain_entered) self.domain_edit.lineEdit().returnPressed.connect(self.move_focus) self.domain_edit.setMaximumHeight(28) domain_label.setBuddy(self.domain_edit) layout.addWidget(domain_label) layout.addWidget(self.domain_edit) # Username self.username_label = QLabel("&Username:"******"&Passwortstärke:") self.strength_label.setVisible(False) self.strength_selector = PasswordStrengthSelector() self.strength_selector.set_min_length(4) self.strength_selector.set_max_length(36) self.strength_selector.setMinimumHeight(60) self.strength_selector.set_length(12) self.strength_selector.set_complexity(6) self.strength_selector.strength_changed.connect(self.strength_changed) self.strength_selector.setVisible(False) self.strength_label.setBuddy(self.strength_selector) layout.addWidget(self.strength_label) layout.addWidget(self.strength_selector) # Password self.password_label = QLabel("&Passwort:") self.password_label.setVisible(False) self.password = QLabel() self.password.setTextFormat(Qt.PlainText) self.password.setAlignment(Qt.AlignCenter) self.password.setFont(QFont("Helvetica", 18, QFont.Bold)) self.password.setVisible(False) self.password_label.setBuddy(self.password) layout.addWidget(self.password_label) layout.addWidget(self.password)
class CustomPage(QWizardPage): ''' Custom Computer Wizard Page Contains inputs for the Driver and Parser that the user can define a custom mix of driver/parser/options. ''' def __init__(self, parent=None): super(CustomPage, self).__init__(parent) self._createLayout() self.registerField('driver', self._cbxDriver) self.registerField('parser', self._cbxParser) self.registerField('driveropt', self._txtDOpts) self.registerField('parseropt', self._txtPOpts) self.setTitle(self.tr('Setup Driver Options')) self.setSubTitle(self.tr('Select the Driver and Parser to use with your Dive Computer.')) def nextId(self): 'Return the next Page Id' return Pages.Browse def _createLayout(self): 'Create the Wizard Page Layout' self._cbxDriver = QComboBox() self._cbxDriver.setModel(DriverModel()) self._lblDriver = QLabel(self.tr('&Driver:')) self._lblDriver.setBuddy(self._cbxDriver) self._cbxParser = QComboBox() self._cbxParser.setModel(ParserModel()) self._lblParser = QLabel(self.tr('&Parser:')) self._lblParser.setBuddy(self._cbxParser) self._txtDOpts = QLineEdit() self._lblDOpts = QLabel(self.tr('Driver Options:')) self._lblDOpts.setBuddy(self._txtDOpts) self._txtPOpts = QLineEdit() self._lblPOpts = QLabel(self.tr('Parser Options:')) self._lblPOpts.setBuddy(self._txtPOpts) gbox = QGridLayout() gbox.addWidget(self._lblDriver, 0, 0) gbox.addWidget(self._cbxDriver, 0, 1) gbox.addWidget(self._lblParser, 1, 0) gbox.addWidget(self._cbxParser, 1, 1) gbox.addWidget(self._lblDOpts, 2, 0) gbox.addWidget(self._txtDOpts, 2, 1) gbox.addWidget(self._lblPOpts, 3, 0) gbox.addWidget(self._txtPOpts, 3, 1) vbox = QVBoxLayout() vbox.addLayout(gbox) vbox.addStretch() self.setLayout(vbox)
def initUI(self): wordLabel=QLabel("&Wort:") responseLabel=QLabel("Symbol-Wort:") progressLabel=QLabel("Rechen-Fortschritt:") self.lineEdit=QLineEdit() self.updateButton=QPushButton("&Berechnen") self.autoUpdate=QCheckBox("&Auto-Berechnung") self.responseLabel=QLabel() wordLabel.setBuddy(self.lineEdit) self.tableWidget=QTableWidget() self.progressView=ProgressView() self.disableMaxLengthAction=QAction("Zeichenmaximum (Achtung!)",self) self.disableMaxLengthAction.setCheckable(True) self.disableMaxLengthAction.toggled.connect(self.updateMaxLength) self.disableMaxLengthAction.setChecked(True) self.setupTable() self.progressView.setProgress(self.thread.calculator.progress) self.progressView.abortButton.setIcon(QIcon.fromTheme("process-stopp",QIcon("Abort.png"))) self.progressView.abortButton.setToolTip("Stoppe die Berechnung") self.lineEdit.setValidator(QRegExpValidator(QRegExp("[A-Za-z]+"))) self.lineEdit.setToolTip("Nur Zeichen von A-Z") self.lineEdit.setContextMenuPolicy(Qt.ActionsContextMenu) self.lineEdit.addAction(self.disableMaxLengthAction) self.responseLabel.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed) self.responseLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) self.aboutButton=QPushButton(u"Über") f=self.responseLabel.font() f.setPointSize(24) self.responseLabel.setFont(f) self.lineEdit.returnPressed.connect(self.update) self.updateButton.clicked.connect(self.update) self.autoUpdate.stateChanged.connect(self.updateAuto) self.aboutButton.clicked.connect(self.about) layout=QGridLayout() layout.addWidget(wordLabel,0,0) layout.addWidget(self.lineEdit,0,1) layout.addWidget(self.updateButton,0,2) layout.addWidget(self.autoUpdate,1,1,1,2) layout.addWidget(responseLabel,2,0) layout.addWidget(self.responseLabel,2,1,1,2) layout.addWidget(self.tableWidget,3,0,1,3) layout.addWidget(progressLabel,4,0) layout.addWidget(self.progressView,5,0,1,3) layout.addWidget(self.aboutButton,6,2) self.setLayout(layout)
class Panel(QWidget): def __init__(self, state, parent=None): super().__init__(parent) self.state = state self.createWidgets() self.layoutWidgets() self.helpButton.clicked.connect( lambda: self.state.help("xix_ref_panel_index.html")) def clear(self): self.view.clear() def createWidgets(self): self.indexLabel = QLabel("&Index ") self.view = Views.All.View(self.state) self.tooltips.append((self.view, """ <p><b>Index view</b> (Alt+I)</p> <p>This view shows all the index's entries.</p> <p>The entries are always shown in the correct order in accordance with the the chosen <b>Index→Options, Rules, Calculate Sort As Rules</b>, so there's never a need to explicitly sort.</p>""")) self.indexLabel.setBuddy(self.view) self.gotoLabel = QLabel("Goto <font color=darkgreen>(Ctrl+T)</font>") self.gotoLineEdit = SelectAllLineEdit() self.gotoLabel.setBuddy(self.gotoLineEdit) self.tooltips.append((self.gotoLineEdit, """ <p><b>Goto (Ctrl+T)</b></p> <p>Enter a few initial letters to goto the first main entry whose term begins with those letters.</p>""")) self.state.editors.add(self.gotoLineEdit) self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) def layoutWidgets(self): layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.indexLabel) hbox.addSpacing(self.fontMetrics().width("W") * 4) hbox.addStretch() hbox.addWidget(self.gotoLabel) hbox.addWidget(self.gotoLineEdit, 1) hbox.addWidget(self.helpButton) layout.addLayout(hbox) layout.addWidget(self.view, 1) self.setLayout(layout) def updateDisplayFonts(self): self.view.updateDisplayFonts()
class IntroPage(QWizardPage): ''' Introduction Wizard Page Contains the introduction text and a combo box to select either a pre- defined computer model or a custom computer type. ''' def __init__(self, parent=None): super(IntroPage, self).__init__(parent) self._createLayout() self.registerField('type', self._cbxType) self.setTitle(self.tr('Add a Dive Computer')) self.setSubTitle(self.tr('Select the type of Dive Computer to add. Make sure the computer is connected and ready to download before proceeding.')) def nextId(self): 'Return the next Page Id' if self._cbxType.currentIndex() == len(ComputerTypes): return Pages.Custom else: return Pages.Browse def _createLayout(self): 'Create the Wizard Page Layout' self._cbxType = QComboBox() self._lblType = QLabel(self.tr('Dive Computer &Type')) self._lblType.setBuddy(self._cbxType) for t in ComputerTypes: self._cbxType.addItem(t['name']) self._cbxType.addItem('Custom...') gbox = QGridLayout() gbox.addWidget(self._lblType, 0, 0) gbox.addWidget(self._cbxType, 0, 1) vbox = QVBoxLayout() vbox.addLayout(gbox) vbox.addStretch() self.setLayout(vbox)
def __init__(self, root_node, parent=None): super(CopyDeviceDlg, self).__init__(parent) self.setWindowTitle("Duplicate Relief Device") area_label = QLabel("&Copy Relief Device To:") self.area_combobox = QComboBox() for area in root_node.children: self.area_combobox.addItem(area.name, area) area_label.setBuddy(self.area_combobox) button_box = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) layout = QGridLayout() layout.addWidget(area_label, 0, 0) layout.addWidget(self.area_combobox, 0, 1) layout.addWidget(button_box, 1, 1) self.setLayout(layout) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject)
def __init__(self, root_node, parent=None): super(CopyScenarioDlg, self).__init__(parent) self.setWindowTitle("Duplicate Scenario") device_label = QLabel("&Copy Scenario To:") self.device_combobox = QComboBox() device_label.setBuddy(self.device_combobox) for area in root_node.children: for device in area.children: self.device_combobox.addItem(device.name, device) button_box = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) layout = QGridLayout() layout.addWidget(device_label, 0, 0) layout.addWidget(self.device_combobox, 0, 1) layout.addWidget(button_box, 1, 1) self.setLayout(layout) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject)
class managebkm(QDialog): def __init__(self, parent=None): super(managebkm, self).__init__(parent) appicom = QIcon(":/icons/njnlogo.png") self.setWindowIcon(appicom) self.setWindowTitle("Nigandu | Manage Book Marks") self.setFixedSize(463, 242) self.verticalLayoutWidget = QWidget(self) self.verticalLayoutWidget.setGeometry(QRect(350, 30, 101, 201)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.sortbtn = QPushButton(self.verticalLayoutWidget) self.sortbtn.setText("&Sort") self.verticalLayout.addWidget(self.sortbtn) self.deletebtn = QPushButton(self.verticalLayoutWidget) self.deletebtn.setText("&Delete") self.verticalLayout.addWidget(self.deletebtn) self.deleteallbtn = QPushButton(self.verticalLayoutWidget) self.deleteallbtn.setText("Delete &All") self.verticalLayout.addWidget(self.deleteallbtn) self.closebtn = QPushButton(self.verticalLayoutWidget) self.closebtn.setText("&Close") self.verticalLayout.addWidget(self.closebtn) self.listWidget = QListWidget(self) self.listWidget.setGeometry(QRect(10, 30, 331, 201)) self.label = QLabel(self) self.label.setGeometry(QRect(20, 10, 91, 25)) font = QFont() font.setPointSize(10) self.label.setFont(font) self.label.setBuddy(self.listWidget) self.label.setText("Book Mark List:")
def __init__(self, name, tendril, parent=None): super(TendrilWidget,self).__init__(parent) hlayout = QHBoxLayout(self) label = QLabel("&" + name) hlayout.addWidget(label) self.thunker = TendrilThunker(tendril) if tendril.val == True or tendril.val == False: spacer = QSpacerItem(0, 0, hPolicy=QSizePolicy.Expanding, vPolicy=QSizePolicy.Minimum) hlayout.addItem(spacer) checkbox = QCheckBox(self) checkbox.setCheckState(Qt.Checked if tendril.val else Qt.Unchecked) checkbox.stateChanged.connect(self.thunker.update) label.setBuddy(checkbox) hlayout.addWidget(checkbox) else: edit = QLineEdit(str(tendril.val), self) edit.textChanged.connect(self.thunker.update) label.setBuddy(edit) hlayout.addWidget(edit) self.setLayout(hlayout) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
def __init__(self, root_node, parent=None): super(AddDeviceDlg, self).__init__(parent) self.setWindowTitle("Add Relief Device") id_label = QLabel("&Relief Device ID:") self.id_lineedit = QLineEdit() self.id_lineedit.setMaxLength(200) id_label.setBuddy(self.id_lineedit) area_label = QLabel("Associated Relief Device &Area:") self.area_combobox = QComboBox() for area in root_node.children: self.area_combobox.addItem(area.name, area) area_label.setBuddy(self.area_combobox) color_label = QLabel("&Text Color:") self.color_combobox = QComboBox() for key in sorted(COLORS.keys()): pixmap = QPixmap(26, 26) pixmap.fill(COLORS[key]) self.color_combobox.addItem(QIcon(pixmap), key) color_label.setBuddy(self.color_combobox) button_box = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) layout = QGridLayout() layout.addWidget(id_label, 0, 0) layout.addWidget(self.id_lineedit, 0, 1) layout.addWidget(area_label, 1, 0) layout.addWidget(self.area_combobox, 1, 1) layout.addWidget(color_label, 2, 0) layout.addWidget(self.color_combobox, 2, 1) layout.addWidget(button_box, 3, 1) self.setLayout(layout) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject)
def layoutWidgets(self): form = QFormLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.formatPanel) form.addRow(hbox) form.addRow(self.titleLabel, self.titleTextEdit) form.addRow(self.noteLabel, self.noteTextEdit) vbox = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.blankBeforeLabel) hbox.addWidget(self.blankBeforeSpinBox) hbox.addWidget(self.blankAfterLabel) hbox.addWidget(self.blankAfterSpinBox) hbox.addStretch() vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.sectionTitlesCheckBox) hbox.addStretch() hbox.addWidget(self.sectionSpecialTitleLabel) hbox.addWidget(self.sectionSpecialTitleTextEdit) vbox.addLayout(hbox) self.sectionsGroupBox.setLayout(vbox) form.addRow(self.sectionsGroupBox) hbox = QHBoxLayout() hbox.addWidget(self.stdFontComboBox, 1) hbox.addWidget(self.stdFontSizeSpinBox) hbox.addStretch() label = QLabel("&Std. Font") label.setBuddy(self.stdFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.altFontComboBox, 1) hbox.addWidget(self.altFontSizeSpinBox) hbox.addStretch() label = QLabel("&Alt. Font") label.setBuddy(self.altFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.monoFontComboBox, 1) hbox.addWidget(self.monoFontSizeSpinBox) hbox.addStretch() label = QLabel("&Mono. Font") label.setBuddy(self.monoFontComboBox) form.addRow(label, hbox) grid = QGridLayout() grid.addWidget(self.monoFontAsStrikeoutCheckbox, 0, 0, 1, 2) grid.addWidget(self.termPagesSepLabel, 0, 2) grid.addWidget(self.termPagesSepTextEdit, 0, 3) grid.addWidget(self.styleLabel, 1, 0) grid.addWidget(self.styleComboBox, 1, 1) grid.addWidget(self.runInSepLabel, 1, 2) grid.addWidget(self.runInSepTextEdit, 1, 3) form.addRow(grid) self.setLayout(form)
class FinishPage(QWizardPage): ''' Finish Wizard Page Contains a summary of the computer and a space for the user to enter a name for the Computer. ''' def __init__(self, parent=None): super(FinishPage, self).__init__(parent) self._createLayout() self.registerField('name*', self._txtName) self.setTitle(self.tr('Name your Dive Computer')) self.setSubTitle(self.tr('Enter a name for the Dive Computer to finish adding the Dive Computer to the Logbook.')) def nextId(self): 'Return the next Page Id' return -1 def _createLayout(self): 'Create the Wizard Page Layout' self._txtName = QLineEdit() self._lblName = QLabel(self.tr('Computer &Name:')) self._lblName.setBuddy(self._txtName) gbox = QGridLayout() gbox.addWidget(self._lblName, 0, 0) gbox.addWidget(self._txtName, 0, 1) vbox = QVBoxLayout() vbox.addLayout(gbox) vbox.addStretch() self.setLayout(vbox)
def create_main_area(self, layout, url, username, password): url_label = QLabel("&URL des c't SESAM Sync Server:") self.url_edit = QLineEdit() if url: self.url_edit.setText(url) self.url_edit.setMaximumHeight(28) self.url_edit.textChanged.connect(self.url_changed) url_label.setBuddy(self.url_edit) layout.addWidget(url_label) layout.addWidget(self.url_edit) username_label = QLabel("&Benutzername:") self.username_edit = QLineEdit() if username: self.username_edit.setText(username) self.username_edit.setMaximumHeight(28) self.username_edit.textChanged.connect(self.save_settings) username_label.setBuddy(self.username_edit) layout.addWidget(username_label) layout.addWidget(self.username_edit) password_label = QLabel("&Passwort:") self.password_edit = QLineEdit() if password: self.password_edit.setText(password) self.password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.password_edit.setMaximumHeight(28) self.password_edit.textChanged.connect(self.save_settings) password_label.setBuddy(self.password_edit) layout.addWidget(password_label) layout.addWidget(self.password_edit) self.test_button = QPushButton("Verbindung testen") self.test_button.clicked.connect(self.test_connection) layout.addWidget(self.test_button) self.message = QLabel("") if not self.certificate: self.message.setText( '<span style="font-size: 10px; color: #aa0000;">' + 'Kein Zertifikat vorhanden.' + '</span>') layout.addWidget(self.message)
def create_main_area(self, layout, url, username, password): url_label = QLabel("&URL des c't SESAM Sync Server:") self.url_edit = QLineEdit() if url: self.url_edit.setText(url) self.url_edit.setMaximumHeight(28) self.url_edit.textChanged.connect(self.url_changed) url_label.setBuddy(self.url_edit) layout.addWidget(url_label) layout.addWidget(self.url_edit) username_label = QLabel("&Benutzername:") self.username_edit = QLineEdit() if username: self.username_edit.setText(username) self.username_edit.setMaximumHeight(28) self.username_edit.textChanged.connect(self.save_settings) username_label.setBuddy(self.username_edit) layout.addWidget(username_label) layout.addWidget(self.username_edit) password_label = QLabel("&Passwort:") self.password_edit = QLineEdit() if password: self.password_edit.setText(password) self.password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.password_edit.setMaximumHeight(28) self.password_edit.textChanged.connect(self.save_settings) password_label.setBuddy(self.password_edit) layout.addWidget(password_label) layout.addWidget(self.password_edit) self.test_button = QPushButton("Verbindung testen") self.test_button.clicked.connect(self.test_connection) layout.addWidget(self.test_button) self.message = QLabel("") if not self.certificate: self.message.setText('<span style="font-size: 10px; color: #aa0000;">' + 'Kein Zertifikat vorhanden.' + '</span>') layout.addWidget(self.message)
def layoutWidgets(self): form = QFormLayout() grid = QGridLayout() grid.addWidget(self.indexViewOnLeft, 0, 0) grid.addWidget(self.alwaysShowSortAsCheckBox, 1, 0) grid.addWidget(self.showNotesCheckBox, 2, 0) grid.addWidget(self.showMenuToolTipsCheckBox, 0, 1) grid.addWidget(self.showMainWindowToolTipsCheckBox, 1, 1) grid.addWidget(self.showDialogToolTipsCheckBox, 2, 1) grid.addWidget(self.keepHelpOnTopCheckBox, 3, 1) grid.addWidget(self.showSplashCheckBox, 4, 1) hbox = QHBoxLayout() hbox.addLayout(grid) hbox.addStretch() form.addRow(hbox) hbox = QHBoxLayout() hbox.addWidget(self.displaystdFontComboBox, 1) hbox.addWidget(self.displaystdFontSizeSpinBox) hbox.addStretch() label = QLabel("&Std. Font") label.setBuddy(self.displaystdFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.displayaltFontComboBox, 1) hbox.addWidget(self.displayaltFontSizeSpinBox) hbox.addStretch() label = QLabel("&Alt. Font") label.setBuddy(self.displayaltFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.displaymonoFontComboBox, 1) hbox.addWidget(self.displaymonoFontSizeSpinBox) hbox.addStretch() label = QLabel("&Mono. Font") label.setBuddy(self.displaymonoFontComboBox) form.addRow(label, hbox) self.setLayout(form)
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() def createWidgets(self): self.formatPanel = Widgets.FormatPanel.Panel(self.state, self) formatActions = self.formatPanel.formatActions self.seePrefixLabel = QLabel("Pref&ix") self.seePrefixTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seePrefixLabel.setBuddy(self.seePrefixTextEdit) self.seePrefixTextEdit.setHtml(self.config.get( Gconf.Key.SubSeePrefix)) self.form.tooltips.append((self.seePrefixTextEdit, """\ <p><b>See, Prefix</b></p> <p>The text to separate a subentry's <i>see</i> cross-refs from the term or pages that precede them.</p>{}""".format(BLANK_SPACE_HTML))) self.seeLabel = QLabel("T&ext") self.seeTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 10, formatActions=formatActions) self.seeLabel.setBuddy(self.seeTextEdit) self.seeTextEdit.setHtml(self.config.get(Gconf.Key.SubSee)) self.form.tooltips.append((self.seeTextEdit, """\ <p><b>See, Text</b></p> <p>The text to indicate a subentry's <i>see</i> cross-ref(s).</p>{}""".format(BLANK_SPACE_HTML))) self.seeSepLabel = QLabel("Sepa&rator") self.seeSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seeSepLabel.setBuddy(self.seeSepTextEdit) self.seeSepTextEdit.setHtml(self.config.get( Gconf.Key.SubSeeSeparator)) self.form.tooltips.append((self.seeSepTextEdit, """\ <p><b>See, Separator</b></p> <p>The text to separate each of a subentry's <i>see</i> cross-references if there are more than one.</p>{}""".format(BLANK_SPACE_HTML))) self.seeSuffixLabel = QLabel("Su&ffix") self.seeSuffixTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seeSuffixLabel.setBuddy(self.seeSuffixTextEdit) self.seeSuffixTextEdit.setHtml(self.config.get( Gconf.Key.SubSeeSuffix)) self.form.tooltips.append((self.seeSuffixTextEdit, """\ <p><b>See, Suffix</b></p> <p>The text to follow a subentry's <i>see</i> cross-references</p>{}""".format(BLANK_SPACE_HTML))) self.seeAlsoPrefixLabel = QLabel("&Prefix") self.seeAlsoPrefixTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seeAlsoPrefixLabel.setBuddy(self.seeAlsoPrefixTextEdit) self.seeAlsoPrefixTextEdit.setHtml(self.config.get( Gconf.Key.SubSeeAlsoPrefix)) self.form.tooltips.append((self.seeAlsoPrefixTextEdit, """\ <p><b>See Also, Prefix</b></p> <p>The text to separate a subentry's <i>see also</i> cross-refs from the term or pages that precede them.</p>{}""".format(BLANK_SPACE_HTML))) self.seeAlsoLabel = QLabel("Te&xt") self.seeAlsoTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 10, formatActions=formatActions) self.seeAlsoLabel.setBuddy(self.seeAlsoTextEdit) self.seeAlsoTextEdit.setHtml(self.config.get(Gconf.Key.SubSeeAlso)) self.form.tooltips.append((self.seeAlsoTextEdit, """\ <p><b>See Also, Text</b></p> <p>The text to indicate a subentry's <i>see also</i> cross-ref(s).</p>{}""".format(BLANK_SPACE_HTML))) self.seeAlsoSepLabel = QLabel("&Separator") self.seeAlsoSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seeAlsoSepLabel.setBuddy(self.seeAlsoSepTextEdit) self.seeAlsoSepTextEdit.setHtml(self.config.get( Gconf.Key.SubSeeAlsoSeparator)) self.form.tooltips.append((self.seeAlsoSepTextEdit, """\ <p><b>See Also, Separator</b></p> <p>The text to separate each of a subentry's <i>see also</i> cross-references if there are more than one.</p>{}""".format( BLANK_SPACE_HTML))) self.seeAlsoSuffixLabel = QLabel("S&uffix") self.seeAlsoSuffixTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.seeAlsoSuffixLabel.setBuddy(self.seeAlsoSuffixTextEdit) self.seeAlsoSuffixTextEdit.setHtml(self.config.get( Gconf.Key.SubSeeAlsoSuffix)) self.form.tooltips.append((self.seeAlsoSuffixTextEdit, """\ <p><b>See Also, Suffix</b></p> <p>The text to follow a subentry's <i>see also</i> cross-references</p>{}""".format(BLANK_SPACE_HTML))) self.seeAlsoPositionLabel = QLabel("P&osition") self.seeAlsoPositionComboBox = QComboBox() self.seeAlsoPositionLabel.setBuddy(self.seeAlsoPositionComboBox) seeAlsoPos = self.config.get(Gconf.Key.SubSeeAlsoPosition) index = -1 for i, pos in enumerate(SeeAlsoPositionKind): self.seeAlsoPositionComboBox.addItem(pos.text, pos.value) if pos is seeAlsoPos: index = i self.seeAlsoPositionComboBox.setCurrentIndex(index) self.form.tooltips.append((self.seeAlsoPositionComboBox, """\ <p><b>Position</b></p> <p>Where <i>see also</i> cross-references should appear in relation to the subentry they belong to.</p>""")) self.formatPanel.state.editors = [ self.seePrefixTextEdit, self.seeTextEdit, self.seeSepTextEdit, self.seeSuffixTextEdit, self.seeAlsoPrefixTextEdit, self.seeAlsoTextEdit, self.seeAlsoSepTextEdit, self.seeAlsoSuffixTextEdit] def layoutWidgets(self): layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.formatPanel) layout.addLayout(hbox) seeGroup = QGroupBox("See") form = QFormLayout() form.addRow(self.seeLabel, self.seeTextEdit) hbox = QHBoxLayout() hbox.addWidget(self.seePrefixTextEdit) hbox.addWidget(self.seeSepLabel) hbox.addWidget(self.seeSepTextEdit) hbox.addWidget(self.seeSuffixLabel) hbox.addWidget(self.seeSuffixTextEdit) form.addRow(self.seePrefixLabel, hbox) seeGroup.setLayout(form) layout.addWidget(seeGroup) alsoGroup = QGroupBox("See Also") form = QFormLayout() form.addRow(self.seeAlsoLabel, self.seeAlsoTextEdit) hbox = QHBoxLayout() hbox.addWidget(self.seeAlsoPrefixTextEdit) hbox.addWidget(self.seeAlsoSepLabel) hbox.addWidget(self.seeAlsoSepTextEdit) hbox.addWidget(self.seeAlsoSuffixLabel) hbox.addWidget(self.seeAlsoSuffixTextEdit) form.addRow(self.seeAlsoPrefixLabel, hbox) form.addRow(self.seeAlsoPositionLabel, self.seeAlsoPositionComboBox) alsoGroup.setLayout(form) layout.addWidget(alsoGroup) layout.addStretch(2) self.setLayout(layout)
class MainWindow(QWidget): # noinspection PyUnresolvedReferences def __init__(self, clipboard): super().__init__() self.clipboard = clipboard self.setWindowIcon(QIcon('Logo_rendered_edited.png')) self.layout = QBoxLayout(QBoxLayout.TopToBottom, self) self.generator = CtSesam() self.iterations = 4096 # Master password self.master_password_label = QLabel("&Master-Passwort:") self.maser_password_edit = QLineEdit() self.maser_password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.maser_password_edit.textChanged.connect(self.reset_iterations) self.maser_password_edit.returnPressed.connect(self.move_focus) self.maser_password_edit.setMaximumHeight(28) self.master_password_label.setBuddy(self.maser_password_edit) self.layout.addWidget(self.master_password_label) self.layout.addWidget(self.maser_password_edit) # Domain self.domain_label = QLabel("&Domain:") self.domain_edit = QLineEdit() self.domain_edit.textChanged.connect(self.reset_iterations) self.domain_edit.returnPressed.connect(self.move_focus) self.domain_edit.setMaximumHeight(28) self.domain_label.setBuddy(self.domain_edit) self.layout.addWidget(self.domain_label) self.layout.addWidget(self.domain_edit) # Username self.username_label = QLabel("&Username:"******"Sonderzeichen") self.special_characters_checkbox.setChecked(True) self.special_characters_checkbox.stateChanged.connect(self.reset_iterations) self.layout.addWidget(self.special_characters_checkbox) self.letters_checkbox = QCheckBox("Buchstaben") self.letters_checkbox.setChecked(True) self.letters_checkbox.stateChanged.connect(self.reset_iterations) self.layout.addWidget(self.letters_checkbox) self.digits_checkbox = QCheckBox("Zahlen") self.digits_checkbox.setChecked(True) self.digits_checkbox.stateChanged.connect(self.reset_iterations) self.layout.addWidget(self.digits_checkbox) # Length slider self.length_label = QLabel("&Länge:") self.length_display = QLabel() self.length_label_layout = QBoxLayout(QBoxLayout.LeftToRight) self.length_label_layout.addWidget(self.length_label) self.length_label_layout.addWidget(self.length_display) self.length_label_layout.addStretch() self.length_slider = QSlider(Qt.Horizontal) self.length_slider.setMinimum(4) self.length_slider.setMaximum(20) self.length_slider.setPageStep(1) self.length_slider.setValue(10) self.length_display.setText(str(self.length_slider.sliderPosition())) self.length_slider.valueChanged.connect(self.length_slider_changed) self.length_label.setBuddy(self.length_slider) self.layout.addLayout(self.length_label_layout) self.layout.addWidget(self.length_slider) # Button self.generate_button = QPushButton("Erzeugen") self.generate_button.clicked.connect(self.generate_password) self.generate_button.setAutoDefault(True) self.layout.addWidget(self.generate_button) # Password self.password_label = QLabel("&Passwort:") self.password = QLabel() self.password.setTextFormat(Qt.PlainText) self.password.setAlignment(Qt.AlignCenter) self.password.setFont(QFont("Helvetica", 18, QFont.Bold)) self.password_label.setBuddy(self.password) self.layout.addWidget(self.password_label) self.layout.addWidget(self.password) # Iteration display self.message_label = QLabel() self.message_label.setTextFormat(Qt.RichText) self.message_label.setVisible(False) self.layout.addWidget(self.message_label) # Window layout self.layout.addStretch() self.setGeometry(0, 30, 300, 400) self.setWindowTitle("c't SESAM") self.maser_password_edit.setFocus() self.show() def length_slider_changed(self): self.length_display.setText(str(self.length_slider.sliderPosition())) self.reset_iterations() def reset_iterations(self): self.iterations = 4096 self.message_label.setVisible(False) self.password.setText('') self.clipboard.setText('') def move_focus(self): line_edits = [self.maser_password_edit, self.domain_edit, self.username_edit] for i, edit in enumerate(line_edits): if edit.hasFocus() and i + 1 < len(line_edits): line_edits[i + 1].setFocus() return True self.generate_button.setFocus() def generate_password(self): if len(self.domain_edit.text()) <= 0: self.reset_iterations() self.message_label.setText( '<span style="font-size: 10px; color: #aa0000;">Bitte geben Sie eine Domain an.</span>') self.message_label.setVisible(True) return False if self.letters_checkbox.isChecked() or \ self.digits_checkbox.isChecked() or \ self.special_characters_checkbox.isChecked(): self.generator.set_password_characters( use_letters=self.letters_checkbox.isChecked(), use_digits=self.digits_checkbox.isChecked(), use_special_characters=self.special_characters_checkbox.isChecked()) else: self.reset_iterations() self.message_label.setText( '<span style="font-size: 10px; color: #aa0000;">Bei den aktuellen Einstellungen ' + 'kann kein Passwort berechnet werden.</span>') self.message_label.setVisible(True) return False password = self.generator.generate( master_password=self.maser_password_edit.text(), domain=self.domain_edit.text(), username=self.username_edit.text(), length=self.length_slider.sliderPosition(), iterations=self.iterations ) self.password.setText(password) self.password.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard) self.clipboard.setText(password) self.message_label.setText( '<span style="font-size: 10px; color: #888888;">Das Passwort wurde ' + str(self.iterations) + ' mal gehasht <br />und in die Zwischenablage kopiert.</span>') self.message_label.setVisible(True) self.iterations += 1
class Panel(QWidget): def __init__(self, state, parent=None): super().__init__(parent=parent) self.state = state self.createWidgets() self.layoutWidgets() self.createConnections() self.tooltips.append((self, """<p><b>Groups panel</b></p> <p>This panel shows the groups the current entry belongs to.</p>""")) def createWidgets(self): self.label = QLabel("Gro&ups") self.groupsList = QListWidget() self.tooltips.append((self.groupsList, """ <p><b>Groups</b> (Alt+U)</p> <p>A (possibly empty) list of the current entry's groups.</p>""")) self.label.setBuddy(self.groupsList) self.closeButton = QToolButton() self.closeButton.setIcon(QIcon(":/hide.svg")) self.closeButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.closeButton, """<p><b>Hide</b></p> <p>Hide the Groups panel.</p> <p>Use <b>Spelling→Show Suggestions and Groups</b> to show it again.</p>""")) self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.helpButton, "Help on the Groups panel.")) def layoutWidgets(self): layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.label) hbox.addStretch() hbox.addWidget(self.closeButton) hbox.addWidget(self.helpButton) layout.addLayout(hbox) layout.addWidget(self.groupsList) self.setLayout(layout) def createConnections(self): self.closeButton.clicked.connect(self.state.window.closeGroups) self.helpButton.clicked.connect(self.help) self.groupsList.itemDoubleClicked.connect( self.state.viewFilteredPanel.setGroup) def updateUi(self): enable = bool(self.state.model) and self.state.mode not in { ModeKind.NO_INDEX, ModeKind.CHANGE } self.setEnabled(enable) if enable: (self.state.window.entryActions.addToNormalGroupAction.setEnabled( self.state.model.normalGroupCount())) (self.state.window.entryActions.addToLinkedGroupAction.setEnabled( self.state.model.linkedGroupCount())) self.state.window.entryActions.removeFromGroupAction.setEnabled( self.groupsList.currentItem() is not None) def updateGroups(self): self.groupsList.clear() eid = self.state.viewAllPanel.view.selectedEid if eid is not None: for gid, name, linked in self.state.model.groupsForEid( eid, withLinks=True): item = QListWidgetItem(name) item.setData(Qt.UserRole, gid) item.setIcon( QIcon(":/grouplink.svg" if linked else ":/groups.svg")) self.groupsList.addItem(item) if self.groupsList.count(): self.groupsList.setCurrentRow(0) self.updateUi() self.state.viewFilteredPanel.groupChanged() def clear(self): self.groupsList.clear() self.updateUi() def help(self): self.state.help("xix_ref_panel_grp.html") def __getattr__(self, name): return getattr(self.groupsList, name)
class Panel(QWidget): def __init__(self, state, parent=None): super().__init__(parent) self.state = state self.entry = None self.saf = Saf.AUTO self.peid = ROOT self.createWidgets() self.layoutWidgets() self.createConnections() self.showOrHideNotes() self.showOrHideSortAs() self.termEdit.setFocus() def createWidgets(self): self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.helpButton, "Help on the Entry panel.")) self.addingLabel = Widgets.Label.HtmlLabel(CANCEL_ADD) self.addingLabel.hide() self.termLabel = QLabel("&Term") self.termEdit = Widgets.LineEdit.HtmlLineEdit(self.state) self.tooltips.append((self.termEdit, """\ <p><b>Term editor</b> (Alt+T)</p> <p>The entry's term text styled (e.g., <b>bold</b>, <i>italic</i>), as it should appear in the final index.</p>""")) self.spellHighlighter = Widgets.SpellHighlighter.Highlighter( self.state, self.termEdit.document()) self.termLabel.setBuddy(self.termEdit) self.pagesLabel = QLabel("&Pages") self.pagesEdit = Widgets.LineEdit.HtmlPagesLineEdit(self.state, maxLines=3) self.tooltips.append((self.pagesEdit, """\ <p><b>Pages editor</b> (Alt+P)</p> <p>The entry's pages styled (e.g., <b>bold</b>, <i>italic</i>), as they should appear in the final index.</p> <p>The pages are automatically sorted, and exact duplicates are automatically removed.</p> <p>See also <b>Index→Combine Overlapping Pages</b> and <b>Index→Renumber Pages</b>.</p>""")) self.pagesLabel.setBuddy(self.pagesEdit) self.calcSortAsCheckBox = QCheckBox("&Automatically Calculate Sort As") self.tooltips.append((self.calcSortAsCheckBox, """\ <p><b>Automatically Calculate Sort As</b> (Alt+A)</p> <p>This checkbox controls how the Sort As text is created.</p> <p>If checked, {} will either automatically create the sort as text, or will present some choices from which to choose the sort as text, depending on the term text.</p> <p>If unchecked, the sort as text should be entered manually.</p>""".format(QApplication.applicationName()))) self.calcSortAsCheckBox.setChecked(True) self.sortAsHelpButton = QToolButton() self.sortAsHelpButton.setIcon(QIcon(":/help.svg")) self.sortAsHelpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append( (self.sortAsHelpButton, "Help on the Sort As text.")) self.sortAsEdit = Widgets.LineEdit.LineEdit(self.state) self.tooltips.append((self.sortAsEdit, """\ <p><b>Sort As editor</b> (Alt+S)</p> <p>The entry's sort as text.</p> <p>If the <b>Automatically Calculate Sort As</b> checkbox is unchecked, manually enter the sort as text to use for sorting the entry.</p> <p>Main entry's are sorted using the sort as text, so it is easy to force a non-standard ordering by entering a custom sort as text.</p> <p>Subentries are also sorted using the sort as text, but the first word of a subentry will be ignored for sorting purposes if it is in the Ignore Subentry Function words list (see <b>Index→Ignore Subentry Function words</b>) <i>and</i> the <b>Index→Options, Rules, Ignore Subenty Function Words</b> checkbox is checked for this index.</p>""")) self.sortAsEdit.setEnabled(False) self.sortAsLabel = QLabel("&Sort As") self.sortAsLabel.setBuddy(self.sortAsEdit) self.sortAsLabel.setEnabled(False) self.xrefLabel = QLabel("&Cross-references") self.xrefList = Widgets.List.HtmlListWidget(self.state, minLines=4) self.tooltips.append((self.xrefList, """\ <p><b>Cross-references list</b> (Alt+C)</p> <p>The list of the entry's see and see also cross-references, both generic and to other entries.</p> <p>To add a cross-reference to an entry, circle the <i>to</i> entry (<b>Entry→Circle</b>), then go to the <i>from</i> entry and click <img src=":/xref-add.svg" width={0} height={0}> or press <b>Entry→Add Cross-reference</b> (See also the <b>Entry</b> menu.)</p>""".format(TOOLTIP_IMAGE_SIZE))) self.xrefLabel.setBuddy(self.xrefList) self.notesLabel = QLabel("&Notes") self.notesEdit = Widgets.LineEdit.MultilineHtmlEdit(self.state) self.tooltips.append((self.notesEdit, """\ <p><b>Notes editor</b> (Alt+N)</p> <p>The entry's notes.</p> <p>The notes shown here are never output as part of the index so may be freely used for any purpose.</p> <p>If the notes facility isn't wanted, the notes can be hidden by unchecking the <b>Index→Options, General, Show Notes</b> checkbox.</p>""")) self.notesLabel.setBuddy(self.notesEdit) def layoutWidgets(self): form = QFormLayout() form.addRow(self.addingLabel) hbox = QHBoxLayout() hbox.addWidget(self.termEdit, 1) hbox.addWidget(self.helpButton) form.addRow(self.termLabel, hbox) form.addRow(self.pagesLabel, self.pagesEdit) hbox = QHBoxLayout() hbox.addWidget(self.calcSortAsCheckBox, 1) hbox.addWidget(self.sortAsHelpButton) form.addRow(hbox) form.addRow(self.sortAsLabel, self.sortAsEdit) vbox = QVBoxLayout() vbox.addLayout(form) vbox.addWidget(self.xrefLabel) vbox.addWidget(self.xrefList, 1) vbox.addWidget(self.notesLabel) vbox.addWidget(self.notesEdit, 1) self.setLayout(vbox) def createConnections(self): self.helpButton.clicked.connect(self.help) self.sortAsHelpButton.clicked.connect( lambda: self.help("xix_ref_sortas.html")) self.termEdit.textChanged.connect(self.termChanged) self.termEdit.cursorPositionChanged.connect(self.maybeSetSuggestions) self.termEdit.textChanged.connect(self.updateMode) self.termEdit.lostFocus.connect(self.maybeSave) self.termEdit.enterPressed.connect( lambda: self.tabAndMaybeSave(self.pagesEdit)) self.pagesEdit.textChanged.connect(self.updateMode) self.pagesEdit.lostFocus.connect(self.maybeSave) self.pagesEdit.enterPressed.connect( lambda: self.tabAndMaybeSave(self.calcSortAsCheckBox)) self.calcSortAsCheckBox.toggled.connect(self.calcSortAsToggled) self.sortAsEdit.textChanged.connect(self.updateMode) self.sortAsEdit.lostFocus.connect(self.maybeSave) self.sortAsEdit.enterPressed.connect( lambda: self.tabAndMaybeSave(self.xrefList)) self.notesEdit.textChanged.connect(self.updateMode) self.notesEdit.lostFocus.connect(self.maybeSave) def help(self, page="xix_ref_panel_entry.html"): self.state.help(page) def tabAndMaybeSave(self, widget): self.maybeSave() widget.setFocus() def updateUi(self): enable = self.state.mode not in {ModeKind.NO_INDEX, ModeKind.CHANGE} self.setEnabled(enable) if enable: enable = (self.state.mode in {ModeKind.ADD, ModeKind.EDIT} or not self.termEdit.isEmpty()) for widget in (self.termEdit, self.pagesEdit, self.calcSortAsCheckBox, self.xrefList, self.notesEdit): widget.setEnabled(enable) self.sortAsEdit.setEnabled( enable and not self.calcSortAsCheckBox.isChecked()) if self.state.mode is ModeKind.ADD: self.state.window.modeLabel.setText( "<font color=green>Adding</font>") def updateDisplayFonts(self): for widget in (self.termEdit, self.sortAsEdit, self.pagesEdit, self.notesEdit, self.xrefList): widget.updateDisplayFonts() def populateEditors(self, editors): editors |= { self.termEdit, self.sortAsEdit, self.pagesEdit, self.notesEdit } def maybeSave(self): if self.hasChanged(): if not bool(self.sortAsEdit.toPlainText().strip()): sortas = self.state.model.sortBy(self.termEdit.toHtml(), self.saf, self.peid is not ROOT) self.sortAsEdit.setPlainText(sortas) self.state.save() def hasChanged(self): term = self.termEdit.toHtml() sortas = self.sortAsEdit.toPlainText().strip() pages = self.pagesEdit.toHtml() notes = self.notesEdit.toHtml() if self.entry is None: return bool(term or sortas or pages or notes) return (self.entry.term != term or self.entry.sortas != sortas or self.entry.pages != pages or self.entry.notes != notes or self.entry.saf != self.saf) def updateMode(self): if (self.state.mode not in { ModeKind.NO_INDEX, ModeKind.ADD, ModeKind.EDIT, ModeKind.CHANGE } and self.hasChanged()): self.state.setMode(ModeKind.EDIT) def clearForm(self): self.state.spellPanel.clearSuggestions() self.state.groupsPanel.clear() positions = Positions(self.termEdit.textCursor().position(), self.sortAsEdit.textCursor().position(), self.pagesEdit.textCursor().position(), self.notesEdit.textCursor().position()) self.termEdit.clear() self.calcSortAsCheckBox.setChecked(True) self.sortAsEdit.clear() self.pagesEdit.clear() self.xrefList.clear() self.notesEdit.clear() return positions def setEntry(self, entry): positions = self.clearForm() self.entry = entry if entry is not None: self.termEdit.setHtml(entry.term, positions.term) self.saf = entry.saf or Saf.AUTO self.calcSortAsCheckBox.setChecked(self.saf != Saf.CUSTOM) self.sortAsEdit.setPlainText(entry.sortas, positions.sortas) self.pagesEdit.setHtml(entry.pages, positions.pages) self.notesEdit.setHtml(entry.notes, positions.notes) for xref in list(self.state.model.xrefs(entry.eid)): kind = "See" if xref.kind is XrefKind.SEE else "See also" term = Lib.elidePatchHtml(self.state.model.termPath( xref.to_eid), self.state, maxlen=None) item = QListWidgetItem("{} <i>{}</i> {}".format( XREF_INDICATOR, kind, term)) item.setData(Qt.UserRole, xref) self.xrefList.addItem(item) for xref in list(self.state.model.generic_xrefs(entry.eid)): kind = ("See (generic)" if xref.kind is XrefKind.SEE_GENERIC else "See also (generic)") item = QListWidgetItem("{} <i>{}</i> {}".format( XREF_INDICATOR, kind, xref.term)) item.setData(Qt.UserRole, xref) self.xrefList.addItem(item) if self.xrefList.count(): self.xrefList.setCurrentRow(0) self.state.updateGotoEids(entry.eid) self.state.groupsPanel.updateGroups() self.state.updateNavigationStatus() self.state.setMode(ModeKind.VIEW) @property def unknownWords(self): return self.spellHighlighter.unknownWords def termChanged(self): if self.addingLabel.isVisible(): self.addingLabel.setText(CANCEL_ADD) text = self.termEdit.toPlainText() if bool(self.state.model): while text: eid = self.state.model.firstForPrefix(text) if eid is not None: term = Lib.elidePatchHtml(self.state.model.term(eid), self.state) self.addingLabel.setText(CANCEL_ADD + " and goto “{}”".format(term)) break text = text[:-1] self.maybeSetSuggestions() def maybeSetSuggestions(self): word, _ = self.termEdit.wordAndPosition() if word: if self.termEdit.hasFocus(): replacement = self.state.model.autoReplacementFor(word) if replacement is not None: self.termEdit.replaceWord(replacement) return self.state.spellPanel.populateSuggestions(word) else: self.state.spellPanel.clearSuggestions() def rememberWord(self): word = self.findNearestUnknownWord() if word: Spell.add(word, self.state.language.value) self.state.model.addSpellWord(word) self.spellHighlighter.rehighlight() def ignoreWord(self): word = self.findNearestUnknownWord() if word: self.spellHighlighter.wordsToIgnore.add(word) self.spellHighlighter.rehighlight() def findNearestUnknownWord(self): pos = self.termEdit.textCursor().position() where = -1 unknownWord = None unknownWords = sorted(self.unknownWords) for i, word in unknownWords: if i > where and i <= pos: where = i unknownWord = word if i > pos: break if unknownWord is None and unknownWords: unknownWord = unknownWords[-1][1] return unknownWord def completeWithSuggested(self): index = self.state.spellPanel.currentRow() self.complete(index) def complete(self, i): item = self.state.spellPanel.item(i) if item: word = self.state.spellPanel.item(i).text() self.completeWord(word) def completeWord(self, word): word = COMPLETE_WORD_RX.sub("", word) if word: self.termEdit.replaceWord(word) def showOrHideNotes(self): settings = QSettings() visible = bool( int(settings.value(Gopt.Key.ShowNotes, Gopt.Default.ShowNotes))) self.notesLabel.setVisible(visible) self.notesEdit.setVisible(visible) def showOrHideSortAs(self): settings = QSettings() alwaysShowSortAs = bool( int( settings.value(Gopt.Key.AlwaysShowSortAs, Gopt.Default.AlwaysShowSortAs))) editable = not self.calcSortAsCheckBox.isChecked() visible = alwaysShowSortAs or editable for widget in (self.sortAsLabel, self.sortAsEdit): widget.setVisible(visible) widget.setEnabled(editable) def calcSortAsToggled(self): self.showOrHideSortAs() self.updateMode() if self.calcSortAsCheckBox.isChecked(): saf = self.saf if self.saf != Saf.CUSTOM else Saf.AUTO self.state.calculateSortAs(saf, force=True) else: self.saf = Saf.CUSTOM
class Mixin: def createWidgets(self): settings = QSettings() self.searchLabel = QLabel("Search For") self.searchLineEdit = QLineEdit() self.tooltips.append((self.searchLineEdit, """\ <p><b>Search For editor</b></p> <p>The text or regular expression to search for.</p>""")) self.searchLabel.setBuddy(self.searchLineEdit) self.replaceLabel = QLabel("Replace With") self.replaceLineEdit = QLineEdit() self.tooltips.append((self.replaceLineEdit, """\ <p><b>Replace With editor</b></p> <p>The replacement text (which may include backreferences, \\1, \\2, etc., if a regular expression search is being made).</p>""")) self.replaceLabel.setBuddy(self.replaceLineEdit) self.allEntriesRadioButton = QRadioButton("All Entries") self.allEntriesRadioButton.setChecked( bool(int(settings.value("RP/All", 1)))) self.tooltips.append((self.allEntriesRadioButton, """\ <p><b>All Entries</b></p> <p>If checked, the search will consider every entry in the index.</p>""")) self.filteredEntriesRadioButton = QRadioButton("Filtered Entries") self.filteredEntriesRadioButton.setChecked( bool(int(settings.value("RP/Filtered", 0)))) self.tooltips.append((self.filteredEntriesRadioButton, """\ <p><b>Filtered Entries</b></p> <p>If checked, the search will consider only those entries that are in the current filtered view.</p>""")) self.considerLabel = QLabel("Consider") self.scopeGroup = QButtonGroup() self.scopeGroup.addButton(self.allEntriesRadioButton) self.scopeGroup.addButton(self.filteredEntriesRadioButton) self.literalRadioButton = QRadioButton("Literal") self.literalRadioButton.setChecked( bool(int(settings.value("RP/Literal", 1)))) self.tooltips.append((self.literalRadioButton, """<p><b>Literal</b></p> <p>If checked, the <b>Search For</b> text will be searched for literally.</p>""")) self.regexRadioButton = QRadioButton("Regex") self.regexRadioButton.setChecked( bool(int(settings.value("RP/Regex", 0)))) self.tooltips.append((self.regexRadioButton, """<p><b>Regex</b></p> <p>If checked, the <b>Search For</b> text will be searched for as a regular expression pattern.</p>""")) self.matchAsGroup = QButtonGroup() self.matchAsGroup.addButton(self.literalRadioButton) self.matchAsGroup.addButton(self.regexRadioButton) self.ignoreCaseCheckBox = QCheckBox("Ignore Case") self.ignoreCaseCheckBox.setChecked( bool(int(settings.value("RP/ICase", 0)))) self.tooltips.append((self.ignoreCaseCheckBox, """\ <p><b>Ignore Case</b></p> <p>If checked, the <b>Search For</b> text will be searched for case-insensitively.</p>""")) self.wholeWordsCheckBox = QCheckBox("Whole Words") self.wholeWordsCheckBox.setChecked( bool(int(settings.value("RP/WW", 0)))) self.tooltips.append((self.wholeWordsCheckBox, """\ <p><b>Whole Words</b></p> <p>If checked—and when <b>Literal</b> is checked—the <b>Search For</b> text will be matched as whole words.</p> <p>For example, “habit” will not match “habitat” when whole words is checked.</p> <p>(For regular expressions use \\b before and after each word to get whole word matches.)</p>""")) self.replaceInLabel = QLabel("Look In") self.replaceInTermsCheckBox = QCheckBox("Terms") self.replaceInTermsCheckBox.setChecked( bool(int(settings.value("RP/Terms", 1)))) self.tooltips.append((self.replaceInTermsCheckBox, """\ <p><b>Terms</b></p> <p>If checked, the search will look in term texts.</p>""")) self.replaceInPagesCheckBox = QCheckBox("Pages") self.replaceInPagesCheckBox.setChecked( bool(int(settings.value("RP/Pages", 0)))) self.tooltips.append((self.replaceInPagesCheckBox, """\ <p><b>Pages</b></p> <p>If checked, the search will look in pages texts.</p>""")) self.replaceInNotesCheckBox = QCheckBox("Notes") self.replaceInNotesCheckBox.setChecked( bool(int(settings.value("RP/Notes", 0)))) self.tooltips.append((self.replaceInNotesCheckBox, """\ <p><b>Notes</b></p> <p>If checked, the search will look in notes texts.</p>""")) self.startButton = QPushButton(QIcon(":/edit-find.svg"), "Start Search") self.tooltips.append((self.startButton, """<p><b>Start Search</b></p> <p>Start the search from the first entry in the index or the first entry in the filtered view's entries.</p>""")) self.replaceButton = QPushButton(QIcon(":/edit-find-replace.svg"), "Replace") self.tooltips.append((self.replaceButton, """<p><b>Replace</b></p> <p>Replace the highlighted text with the <b>Replace With</b> text (using backreferences if they are in the replacement text and a <b>Regex</b> search is underway), and then try to find the next matching text.</p>""")) self.skipButton = QPushButton(QIcon(":/skip.svg"), "S&kip") self.tooltips.append((self.skipButton, """<p><b>Skip</b></p> <p>Skip the highlighted text and try to find the next matching text.</p>""")) self.stopButton = QPushButton(QIcon(":/process-stop.svg"), "Stop Search") self.tooltips.append((self.stopButton, """<p><b>Stop Search</b></p> <p>Stop the current search. This allows the search options to be changed.</p>""")) self.closeButton = QToolButton() self.closeButton.setIcon(QIcon(":/hide.svg")) self.closeButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.closeButton, """<p><b>Hide</b></p> <p>Hide the Search and Replace panel.</p> <p>Press <b>Ctrl+H</b> or click <img src=":/edit-find-replace.svg" width={0} height={0}> or click <b>Edit→Search and Replace</b> to show it again.</p>""".format(TOOLTIP_IMAGE_SIZE))) self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append( (self.helpButton, "Help on the Search and Replace panel.")) def layoutWidgets(self): form = QFormLayout() hbox = QHBoxLayout() hbox.addWidget(self.searchLineEdit) hbox.addWidget(self.closeButton) form.addRow(self.searchLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.replaceLineEdit) hbox.addWidget(self.helpButton) form.addRow(self.replaceLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.allEntriesRadioButton) hbox.addWidget(self.filteredEntriesRadioButton) hbox.addStretch() form.addRow(self.considerLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.literalRadioButton) hbox.addWidget(self.regexRadioButton) hbox.addStretch(1) hbox.addWidget(self.ignoreCaseCheckBox) hbox.addWidget(self.wholeWordsCheckBox) hbox.addStretch(5) form.addRow(QLabel("Match"), hbox) hbox = QHBoxLayout() hbox.addWidget(self.replaceInTermsCheckBox) hbox.addWidget(self.replaceInPagesCheckBox) hbox.addWidget(self.replaceInNotesCheckBox) hbox.addStretch() form.addRow(self.replaceInLabel, hbox) hbox = QHBoxLayout() hbox.addWidget(self.startButton) hbox.addWidget(self.replaceButton) hbox.addWidget(self.skipButton) hbox.addWidget(self.stopButton) hbox.addStretch() form.addRow(hbox) self.setLayout(form) def createConnections(self): self.helpButton.clicked.connect(self.help) self.stopButton.clicked.connect(self.stop) self.startButton.clicked.connect(self.start) self.replaceButton.clicked.connect(self.replace) self.skipButton.clicked.connect(self.skip) self.searchLineEdit.textChanged.connect(self.updateUi) self.searchLineEdit.returnPressed.connect(self.doAction) self.replaceLineEdit.textChanged.connect(self.updateUi) self.replaceLineEdit.returnPressed.connect(self.doAction) for button in (self.literalRadioButton, self.regexRadioButton, self.ignoreCaseCheckBox, self.wholeWordsCheckBox, self.replaceInTermsCheckBox, self.replaceInPagesCheckBox, self.replaceInNotesCheckBox): button.clicked.connect(self.updateUi) def doAction(self): button = None if self.skipButton.isEnabled(): button = self.skipButton elif self.startButton.isEnabled(): button = self.startButton if button is not None: button.setFocus() button.click() if self.skipButton.isEnabled(): self.skipButton.setFocus() def help(self): self.state.help("xix_ref_panel_replace.html")
class TransferPanel(QWidget): ''' Transfer Panel This Panel is the main dialog box for the Dive Computer Transfer GUI ''' def __init__(self, parent=None): super(TransferPanel, self).__init__(parent) self._logbook = None self._logbookName = 'None' self._logbookPath = None self._createLayout() self._readSettings() self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName) def _createLayout(self): 'Create the Widget Layout' self._txtLogbook = QLineEdit() self._txtLogbook.setReadOnly(True) self._lblLogbook = QLabel(self.tr('&Logbook File:')) self._lblLogbook.setBuddy(self._txtLogbook) self._btnBrowse = QPushButton('...') self._btnBrowse.clicked.connect(self._btnBrowseClicked) self._btnBrowse.setStyleSheet('QPushButton { min-width: 24px; max-width: 24px; }') self._btnBrowse.setToolTip(self.tr('Browse for a Logbook')) self._cbxComputer = QComboBox() self._lblComputer = QLabel(self.tr('Dive &Computer:')) self._lblComputer.setBuddy(self._cbxComputer) self._btnAddComputer = QPushButton(QPixmap(':/icons/list-add.png'), self.tr('')) self._btnAddComputer.setStyleSheet('QPushButton { min-width: 24px; min-height: 24; max-width: 24px; max-height: 24; }') self._btnAddComputer.clicked.connect(self._btnAddComputerClicked) self._btnRemoveComputer = QPushButton(QPixmap(':/icons/list-remove.png'), self.tr('')) self._btnRemoveComputer.setStyleSheet('QPushButton { min-width: 24px; min-height: 24; max-width: 24px; max-height: 24; }') self._btnRemoveComputer.clicked.connect(self._btnRemoveComputerClicked) hbox = QHBoxLayout() hbox.addWidget(self._btnAddComputer) hbox.addWidget(self._btnRemoveComputer) gbox = QGridLayout() gbox.addWidget(self._lblLogbook, 0, 0) gbox.addWidget(self._txtLogbook, 0, 1) gbox.addWidget(self._btnBrowse, 0, 2) gbox.addWidget(self._lblComputer, 1, 0) gbox.addWidget(self._cbxComputer, 1, 1) gbox.addLayout(hbox, 1, 2) gbox.setColumnStretch(1, 1) self._pbTransfer = QProgressBar() self._pbTransfer.reset() self._txtStatus = QTextEdit() self._txtStatus.setReadOnly(True) self._btnTransfer = QPushButton(self.tr('&Transfer Dives')) self._btnTransfer.clicked.connect(self._btnTransferClicked) self._btnExit = QPushButton(self.tr('E&xit')) self._btnExit.clicked.connect(self.close) hbox = QHBoxLayout() hbox.addWidget(self._btnTransfer) hbox.addStretch() hbox.addWidget(self._btnExit) vbox = QVBoxLayout() vbox.addLayout(gbox) vbox.addWidget(self._pbTransfer) vbox.addWidget(self._txtStatus) vbox.addLayout(hbox) self.setLayout(vbox) def _closeLogbook(self): 'Close the current Logbook' if self._logbook is None: return self._logbook = None self._logbookName = 'None' self._logbookPath = None self._txtLogbook.clear() self._cbxComputer.setModel(None) self._writeSettings() self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName) def _openLogbook(self, path): 'Open an existing Logbook' if self._logbook is not None: self._closeLogbook() if not os.path.exists(path): QMessageBox.critical(self, self.tr('Missing Logbook'), self.tr('Logbook File "%s" does not exist.') % path) return #TODO: Handle a Schema Upgrade in a user-friendly manner self._logbook = Logbook(path, auto_update=False) self._logbookName = os.path.basename(path) self._logbookPath = path self._txtLogbook.setText(self._logbookPath) self._cbxComputer.setModel(DiveComputersModel(self._logbook)) self._writeSettings() self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName) def _readSettings(self): 'Read main window settings from the configuration' settings = QSettings() settings.beginGroup('MainWindow') max = settings.value('max') size = settings.value('size') pos = settings.value('pos') file = settings.value('file') settings.endGroup() # Size and Position the Main Window if size is not None: self.resize(size) if pos is not None: self.move(pos) # HAX because QVariant is not exposed in PySide and the default # coercion to string is just stupid if max is not None and (max == 'true'): self.showMaximized() # Open the Logbook if file is not None: self._openLogbook(file) def _writeSettings(self): 'Write settings to the configuration' settings = QSettings() settings.beginGroup('MainWindow') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) settings.setValue('max', self.isMaximized()) settings.setValue('file', self._logbookPath) settings.endGroup() def closeEvent(self, e): 'Intercept an OnClose event' self._writeSettings() e.accept() #-------------------------------------------------------------------------- # Slots @QtCore.Slot() def _btnAddComputerClicked(self): 'Add a Dive Computer' dc = AddDiveComputerWizard.RunWizard(self) if dc is not None: self._logbook.session.add(dc) self._logbook.session.commit() self._cbxComputer.model().reload() self._cbxComputer.setCurrentIndex(self._cbxComputer.findText(dc.name)) @QtCore.Slot() def _btnRemoveComputerClicked(self): 'Remove a Dive Computer' idx = self._cbxComputer.currentIndex() dc = self._cbxComputer.itemData(idx, Qt.UserRole+0) if QMessageBox.question(self, self.tr('Delete Dive Computer?'), self.tr('Are you sure you want to delete "%s"?') % dc.name, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) == QMessageBox.Yes: self._logbook.session.delete(dc) self._logbook.session.commit() self._cbxComputer.model().reload() @QtCore.Slot() def _btnBrowseClicked(self): 'Browse for a Logbook File' if self._logbook is not None: dir = os.path.dirname(self._logbookPath) else: dir = os.path.expanduser('~') fn = QFileDialog.getOpenFileName(self, caption=self.tr('Select a Logbook file'), dir=dir, filter='Logbook Files (*.lbk);;All Files(*.*)')[0] if fn == '': return if not os.path.exists(fn): if QMessageBox.question(self, self.tr('Create new Logbook?'), self.tr('Logbook "%s" does not exist. Would you like to create it?') % os.path.basename(fn), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) != QMessageBox.Yes: return Logbook.Create(fn) self._openLogbook(fn) @QtCore.Slot() def _btnTransferClicked(self): 'Transfer Dives' idx = self._cbxComputer.currentIndex() dc = self._cbxComputer.itemData(idx, Qt.UserRole+0) if self._logbook.session.dirty: print "Flushing dirty session" self._logbook.rollback() self._txtLogbook.setEnabled(False) self._btnBrowse.setEnabled(False) self._cbxComputer.setEnabled(False) self._btnAddComputer.setEnabled(False) self._btnRemoveComputer.setEnabled(False) self._btnTransfer.setEnabled(False) self._btnExit.setEnabled(False) self._txtStatus.clear() thread = QThread(self) #FIXME: ZOMG HAX: Garbage Collector will eat TransferWorker when moveToThread is called #NOTE: Qt.QueuedConnection is important... self.worker = None self.worker = TransferWorker(dc) thread.started.connect(self.worker.start, Qt.QueuedConnection) self.worker.moveToThread(thread) self.worker.finished.connect(self._transferFinished, Qt.QueuedConnection) self.worker.finished.connect(self.worker.deleteLater, Qt.QueuedConnection) self.worker.finished.connect(thread.deleteLater, Qt.QueuedConnection) self.worker.progress.connect(self._transferProgress, Qt.QueuedConnection) self.worker.started.connect(self._transferStart, Qt.QueuedConnection) self.worker.status.connect(self._transferStatus, Qt.QueuedConnection) thread.start() @QtCore.Slot(str) def _transferStatus(self, msg): 'Transfer Status Message' self._txtStatus.append(msg) @QtCore.Slot(int) def _transferStart(self, nBytes): 'Transfer Thread Stated' if nBytes > 0: self._pbTransfer.setMaximum(nBytes) else: self._pbTransfer.setMaximum(100) self._pbTransfer.reset() @QtCore.Slot(int) def _transferProgress(self, nTransferred): 'Transfer Thread Progress Event' self._pbTransfer.setValue(nTransferred) @QtCore.Slot(models.Dive) def _transferParsed(self, dive): 'Transfer Thread Parsed Dive' self._logbook.session.add(dive) @QtCore.Slot() def _transferFinished(self): 'Transfer Thread Finished' self._logbook.session.commit() self._txtLogbook.setEnabled(True) self._btnBrowse.setEnabled(True) self._cbxComputer.setEnabled(True) self._btnAddComputer.setEnabled(True) self._btnRemoveComputer.setEnabled(True) self._btnTransfer.setEnabled(True) self._btnExit.setEnabled(True)
class Form(QDialog): def __init__(self, state, parent=None): super().__init__(parent) Lib.prepareModalDialog(self) self.state = state self.setWindowTitle("Renumber Pages — {}".format( QApplication.applicationName())) self.createWidgets() self.layoutWidgets() self.createConnections() self.romanStartSpinBox.setFocus() self.updateUi() settings = QSettings() self.updateToolTips( bool( int( settings.value(Gopt.Key.ShowDialogToolTips, Gopt.Default.ShowDialogToolTips)))) def createWidgets(self): self.romanStartLabel = QLabel("&Roman from") self.romanStartSpinBox = Widgets.RomanSpinBox.SpinBox() self.tooltips.append((self.romanStartSpinBox, """\ <p><b>Roman from</b></p> <p>The first roman page number to change.</p>""")) self.romanStartLabel.setBuddy(self.romanStartSpinBox) self.romanEndLabel = QLabel("to") self.romanEndSpinBox = Widgets.RomanSpinBox.SpinBox() self.romanEndSpinBox.setValue(200) self.tooltips.append((self.romanEndSpinBox, """\ <p><b>Roman, to</b></p> <p>The last roman page number to change.</p>""")) self.romanChangeLabel = QLabel("change") self.romanChangeSpinBox = Widgets.ChangeSpinBox.SpinBox() self.romanChangeSpinBox.setRange(-100, 100) self.romanChangeSpinBox.setValue(0) self.romanChangeSpinBox.setMinimumWidth( self.romanChangeSpinBox.fontMetrics().width("W(no change)W")) self.tooltips.append((self.romanChangeSpinBox, """\ <p><b>Roman, change</b></p> <p>The amount to change the roman page numbers in the Roman from–to range.</p>""")) self.decimalStartLabel = QLabel("&Decimal from") self.decimalStartSpinBox = QSpinBox() self.decimalStartSpinBox.setAlignment(Qt.AlignRight) self.decimalStartLabel.setBuddy(self.decimalStartSpinBox) self.decimalStartSpinBox.setRange(1, 10000) self.tooltips.append((self.decimalStartSpinBox, """\ <p><b>Decimal from</b></p> <p>The first decimal page number to change.</p>""")) self.decimalEndLabel = QLabel("to") self.decimalEndSpinBox = QSpinBox() self.decimalEndSpinBox.setAlignment(Qt.AlignRight) self.decimalEndSpinBox.setRange(1, 10000) self.decimalEndSpinBox.setValue(2000) self.tooltips.append((self.decimalEndSpinBox, """\ <p><b>Decimal, to</b></p> <p>The last decimal page number to change.</p>""")) self.decimalChangeLabel = QLabel("change") self.decimalChangeSpinBox = Widgets.ChangeSpinBox.SpinBox() self.decimalChangeSpinBox.setRange(-100, 100) self.decimalChangeSpinBox.setValue(0) self.tooltips.append((self.decimalChangeSpinBox, """\ <p><b>Decimal, change</b></p> <p>The amount to change the decimal page numbers in the Decimal from–to range.</p>""")) self.buttonBox = QDialogButtonBox() self.renumberButton = QPushButton(QIcon(":/renumberpages.svg"), "Re&number") self.tooltips.append((self.renumberButton, """\ <p><b>Renumber</b></p> <p>Renumber roman and decimal page numbers within the given ranges by the specified amounts of change throughout the entire index.</p>""")) self.buttonBox.addButton(self.renumberButton, QDialogButtonBox.ActionRole) self.closeButton = QPushButton(QIcon(":/dialog-close.svg"), "&Cancel") self.tooltips.append((self.closeButton, """<p><b>Cancel</b></p> <p>Close the dialog without making any changes to the index.</p>""")) self.buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole) self.helpButton = QPushButton(QIcon(":/help.svg"), "Help") self.tooltips.append( (self.helpButton, "Help on the Renumber Pages dialog")) self.buttonBox.addButton(self.helpButton, QDialogButtonBox.HelpRole) def layoutWidgets(self): grid = QGridLayout() grid.addWidget(self.romanStartLabel, 0, 0) grid.addWidget(self.romanStartSpinBox, 0, 1) grid.addWidget(self.romanEndLabel, 0, 2) grid.addWidget(self.romanEndSpinBox, 0, 3) grid.addWidget(self.romanChangeLabel, 0, 4) grid.addWidget(self.romanChangeSpinBox, 0, 5) grid.addWidget(self.decimalStartLabel, 1, 0) grid.addWidget(self.decimalStartSpinBox, 1, 1) grid.addWidget(self.decimalEndLabel, 1, 2) grid.addWidget(self.decimalEndSpinBox, 1, 3) grid.addWidget(self.decimalChangeLabel, 1, 4) grid.addWidget(self.decimalChangeSpinBox, 1, 5) hbox = QHBoxLayout() hbox.addLayout(grid) hbox.addStretch() layout = QVBoxLayout() layout.addLayout(hbox) layout.addStretch() layout.addWidget(self.buttonBox) self.setLayout(layout) def createConnections(self): self.buttonBox.rejected.connect(self.reject) self.renumberButton.clicked.connect(self.renumber) for spinbox in (self.romanStartSpinBox, self.romanEndSpinBox, self.romanChangeSpinBox, self.decimalStartSpinBox, self.decimalEndSpinBox, self.decimalChangeSpinBox): spinbox.valueChanged.connect(self.updateUi) self.helpButton.clicked.connect(self.help) def updateUi(self): self._synchronize(self.romanStartSpinBox, self.romanEndSpinBox) self._synchronize(self.decimalStartSpinBox, self.decimalEndSpinBox) changeRoman = ( (self.romanStartSpinBox.value() != self.romanEndSpinBox.value()) and self.romanChangeSpinBox.value() != 0) changeDecimal = ((self.decimalStartSpinBox.value() != self.decimalEndSpinBox.value()) and self.decimalChangeSpinBox.value() != 0) self.renumberButton.setEnabled(changeRoman or changeDecimal) self._setPrefix(self.romanChangeSpinBox) self._setPrefix(self.decimalChangeSpinBox) def _synchronize(self, startSpinBox, endSpinBox): value = startSpinBox.value() if endSpinBox.value() < value: endSpinBox.setValue(value) def _setPrefix(self, spinbox): spinbox.setPrefix("+" if spinbox.value() > 0 else "") def help(self): self.state.help("xix_ref_dlg_renumpages.html") def renumber(self): # No need to restore focus widget options = RenumberOptions(self.romanStartSpinBox.value(), self.romanEndSpinBox.value(), self.romanChangeSpinBox.value(), self.decimalStartSpinBox.value(), self.decimalEndSpinBox.value(), self.decimalChangeSpinBox.value()) with Lib.DisableUI(self): self.state.model.renumber(options, self.state.window.reportProgress) message = "Renumber pages" if self.state.model.canUndo: self.state.model.can_undo.emit(True, message) if self.state.model.canRedo: self.state.model.can_redo.emit(True, message) self.state.updateUi() say("Renumbered pages", SAY_TIMEOUT) self.accept()
class Panel(QWidget): def __init__(self, state, parent=None): super().__init__(parent=parent) self.state = state self.createWidgets() self.layoutWidgets() self.createConnections() self.initialize() def createWidgets(self): self.label = QLabel("Suggestions") self.spellList = Widgets.List.HtmlListWidget(self.state) self.tooltips.append((self.spellList, """ <p><b>Suggestions</b> (Alt+N,Tab)</p> <p>A (possibly empty) list of completions or replacements for the word being typed in the <b>Term</b> editor.</p>""")) self.label.setBuddy(self.spellList) self.closeButton = QToolButton() self.closeButton.setIcon(QIcon(":/hide.svg")) self.closeButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append((self.closeButton, """<p><b>Hide</b></p> <p>Hide the Suggestions panel.</p> <p>Use <b>Spelling→Show Suggestions and Groups</b> to show it again.</p>""")) self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.tooltips.append( (self.helpButton, "Help on the Suggestions panel.")) def layoutWidgets(self): layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.label) hbox.addStretch() hbox.addWidget(self.closeButton) hbox.addWidget(self.helpButton) layout.addLayout(hbox) layout.addWidget(self.spellList) self.setLayout(layout) def createConnections(self): self.closeButton.clicked.connect(self.state.window.closeSuggestions) self.helpButton.clicked.connect(self.help) def initialize(self): self.spellList.itemDoubleClicked.connect(self.complete) self.tooltips.append((self, """<p><b>Suggestions panel</b></p> <p>When the text cursor is at the end of a word in the term line edit, any suggestions for completing the word are listed here. To accept a suggestion press <b>Ctrl+<i>number</i></b> or click one of the <b>Spelling→Replace</b> menu options.</p>""")) def complete(self, item): self.state.entryPanel.completeWord(item.text()) def updateUi(self): enable = self.state.mode not in {ModeKind.NO_INDEX, ModeKind.CHANGE} self.setEnabled(enable) def populateSuggestions(self, word): self.clearSuggestions() self.spellList.clear() actions = self.state.window.spellingActions.completionActions suggestions = Spell.suggest(word, self.state.language.value) try: suggestions.remove(word) except ValueError: pass # OK if word isn't in suggestions for i, suggestion in enumerate(suggestions): if i < 9: text = "[Ctrl+{}] {}".format(i + 1, suggestion) actions[i].setText("&{} Replace with “{}”".format( i + 1, suggestion)) actions[i].setVisible(True) else: text = suggestion self.spellList.addItem(text) self.spellList.setCurrentRow(0 if self.spellList.count() else -1) self.state.window.spellingActions.updateUi() def clearSuggestions(self): self.spellList.clear() for action in self.state.window.spellingActions.completionActions: action.setVisible(False) self.state.window.spellingActions.updateUi() def help(self): self.state.help("xix_ref_panel_sug.html") def __getattr__(self, name): return getattr(self.spellList, name)
class Form(QDialog): # Only use if there's a model present def __init__(self, state, parent=None): super().__init__(parent) Lib.prepareModalDialog(self) self.state = state self.formatActions = None self.extension = None self.markup = None self.dirty = False self.setWindowTitle("Custom Markup — {}".format( QApplication.applicationName())) self.createWidgets() self.layoutWidgets() self.createConnections() self.refresh() settings = QSettings() self.updateToolTips( bool( int( settings.value(Gopt.Key.ShowDialogToolTips, Gopt.Default.ShowDialogToolTips)))) def createWidgets(self): self.extensionLabel = QLabel("&Extension") self.extensionComboBox = QComboBox() for markup in self.state.model.markups(): self.extensionComboBox.addItem(markup) self.tooltips.append((self.extensionComboBox, """\ <p><b>Extension</b></p> <p>Choose the file extension to view and edit its custom markup.</p>""")) self.extensionLabel.setBuddy(self.extensionComboBox) self.helpButton = QPushButton(QIcon(":/help.svg"), "Help") self.tooltips.append( (self.helpButton, "Help on the Custom Markup dialog")) self.addButton = QPushButton(QIcon(":/add.svg"), "&Add...") self.tooltips.append((self.addButton, """\ <p><b>Add</b></p> <p>Add a new custom markup to the index.</p>""")) self.deleteButton = QPushButton(QIcon(":/delete.svg"), "&Delete...") self.tooltips.append((self.deleteButton, """\ <p><b>Delete</b></p> <p>Permanently delete the custom markup from the index's <tt>.xix</tt> file. (Note that <tt>.ucp</tt> custom markup cannot be deleted.)</p>""")) self.closeButton = QPushButton(QIcon(":/dialog-close.svg"), "&Close") self.tooltips.append((self.closeButton, """<p><b>Close</b></p> <p>Close the dialog.</p>""")) self.tabWidget = QTabWidget() self.documentPanel = CustomMarkupPanels.Document.Panel( self.state, self) self.characterPanel = CustomMarkupPanels.Character.Panel( self.state, self) self.tabWidget.addTab(self.documentPanel, "D&ocument") self.tabWidget.addTab(self.characterPanel, "C&haracter") def layoutWidgets(self): buttonBox = QDialogButtonBox() buttonBox.addButton(self.helpButton, QDialogButtonBox.HelpRole) buttonBox.addButton(self.addButton, QDialogButtonBox.ActionRole) buttonBox.addButton(self.deleteButton, QDialogButtonBox.ActionRole) buttonBox.addButton(self.closeButton, QDialogButtonBox.AcceptRole) hbox = QHBoxLayout() hbox.addWidget(self.extensionLabel) hbox.addWidget(self.extensionComboBox) hbox.addStretch() hbox.addWidget(buttonBox) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.tabWidget, 1) self.setLayout(vbox) def createConnections(self): self.helpButton.clicked.connect(self.help) self.extensionComboBox.currentIndexChanged.connect(self.refresh) self.addButton.clicked.connect(self.add) self.deleteButton.clicked.connect(self.delete) self.closeButton.clicked.connect(self.accept) self.documentPanel.changed.connect(self.setDirty) self.characterPanel.changed.connect(self.setDirty) def help(self): self.state.help("xix_ref_dlg_markup.html") def setDirty(self): self.dirty = True def refresh(self): self.save() self.extension = self.extensionComboBox.currentText() if self.extension not in self.state.model.markups(): self.markup = Output.Markup.user_markup() else: self.markup = self.state.model.markup(self.extension) self.documentPanel.populateFromMarkup(self.markup) self.characterPanel.populateFromMarkup(self.markup) self.deleteButton.setEnabled(self.extension != ".ucp") def save(self): if self.dirty and self.extension is not None: self.documentPanel.updateMarkup(self.markup) self.characterPanel.updateMarkup(self.markup) self.state.model.updateMarkup(self.extension, self.markup) self.dirty = False def add(self): # No need to restore focus widget self.save() with Lib.DisableUI(self, forModalDialog=True): extension, ok = QInputDialog.getText( self, "Add Custom Markup -— {}".format( QApplication.applicationName()), "Extension") if ok and extension and extension.strip(): extension = extension.strip() if not extension.startswith("."): extension = "." + extension index = self.extensionComboBox.findText(extension, Qt.MatchExactly) if index != -1: self.extensionComboBox.setCurrentIndex(index) else: self.extension = extension self.markup = Output.Markup.user_markup() self.state.model.updateMarkup(self.extension, self.markup) self.extensionComboBox.addItem(extension) self.extensionComboBox.setCurrentIndex( self.extensionComboBox.count() - 1) def delete(self): # No need to restore focus widget index = self.extensionComboBox.currentIndex() if index == -1: return with Lib.Qt.DisableUI(self, forModalDialog=True): extension = self.extensionComboBox.currentText() reply = QMessageBox.question( self, "Delete Custom Markup — {}".format( QApplication.applicationName()), """<p>Delete “{}”?<p> <font color=red>Warning: deleting custom markup cannot be undone.</font>""". format(extension), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.extensionComboBox.removeItem(index) if index < self.extensionComboBox.count(): self.extensionComboBox.setCurrentIndex(index) else: self.extensionComboBox.setCurrentIndex(max(0, index - 1)) self.state.model.deleteMarkup(extension) def reject(self): self.accept() def accept(self): self.save() super().accept()
class Panel(QWidget): def __init__(self, state, parent=None): super().__init__(parent) self.state = state self.createWidgets() self.layoutWidgets() self.clear() def clear(self): self.matchTexts = [] self.prevFilter = None self.view.clear() self.filterComboBox.setCurrentIndex(0) self.filterTextComboBox.clear() self.filterTextIndex = -1 def createWidgets(self): self.helpButton = QToolButton() self.helpButton.setIcon(QIcon(":/help.svg")) self.helpButton.setFocusPolicy(Qt.NoFocus) self.helpButton.clicked.connect(self.help) self.tooltips.append( (self.helpButton, """Help on the Suggestions or Filtered panel.""")) self.view = Views.Filtered.View(self.state) self.tooltips.append((self.view, """<p><b>Filtered view</b></p> <p>This view shows any entries that match the current <b>Filter</b>.</p> <p>Press <b>F3</b> or click <img src=":/goto-found.svg" width={0} height={0}> or click <b>Goto→Filtered</b> to go to the current filtered entry.</p>""".format(TOOLTIP_IMAGE_SIZE))) self.view.match = "" self.filterLabel = QLabel( "Filter <font color=darkgreen>(Ctrl+F)</font>") self.filterComboBox = QComboBox() self.filterComboBox.setMaxVisibleItems(24) self.tooltips.append((self.filterComboBox, """\ <p><b>Filter combobox</b></p> <p>Use this combobox to choose the filter to use.</p> <p>The <b>Terms Matching</b>, <b>Pages Matching</b>, and <b>Notes Matching</b> filters need a match text.</p>""")) self.filterLabel.setBuddy(self.filterComboBox) for filter in FilterKind: if not filter.isCheck: self.filterComboBox.addItem(filter.text, filter) self.filterComboBox.currentIndexChanged[int].connect(self.query) self.filterTextComboBox = ComboBox() self.filterTextComboBox.setEditable(True) self.filterTextComboBox.setDuplicatesEnabled(False) self.filterTextComboBox.currentIndexChanged[str].connect(self.setMatch) self.tooltips.append((self.filterTextComboBox, """\ <p><b>Filter Match editor</b></p> <p>The text to match when using a <b>Terms Matching</b>, <b>Pages Matching</b>, or <b>Notes Matching</b> filter.</p> <p>For terms and notes, the filtered entries are chosen by case-insensitively comparing with the match word or words.</p> <p>Add a <tt>*</tt> after a word to match any words that begin with the text preceding the <tt>*</tt>.</p> <p>For example, “comp*” will match “compress”, “compulsory”, “computer”, “computed”, etc.</p> <p>For pages, enter them as you would for an entry's pages, e.g., <tt>199,202-5</tt> to match entries whose pages equal or include <tt>199,202,203,204,205</tt>, whether explicitly, or within page ranges.</p>""")) self.view.pane.clickLine.connect(self.state.updateNavigationStatus) def layoutWidgets(self): layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.filterLabel) hbox.addWidget(self.filterComboBox, 1) hbox.addWidget(self.filterTextComboBox, 2) hbox.addWidget(self.helpButton) layout.addLayout(hbox) layout.addWidget(self.view, 1) self.setLayout(layout) def setMatch(self, match=None): filter = FilterKind( self.filterComboBox.itemData(self.filterComboBox.currentIndex())) if match is None: match = self.filterTextComboBox.currentText() arg = match if filter in { FilterKind.IN_NORMAL_GROUP, FilterKind.IN_LINKED_GROUP, FilterKind.PAGES_ORDER }: arg = self.filterTextComboBox.itemData( self.filterTextComboBox.currentIndex()) elif filter is FilterKind.ENTRIES_WITH_PAGES: arg = Pages.searchablePages(match) self.view.query(filter, arg) if match: with Lib.BlockSignals(self.filterTextComboBox): index = self.filterTextComboBox.findText(match) if index == -1: self.filterTextComboBox.addItem(match) self.filterTextIndex = (self.filterTextComboBox.count() - 1) else: self.filterTextIndex = index def requery(self): filterIndex = self.filterComboBox.currentIndex() if -1 < self.filterTextIndex < self.filterTextComboBox.count(): textIndex = self.filterTextIndex else: textIndex = self.filterTextComboBox.currentIndex() eid = self.view.selectedEid self.filterComboBox.setCurrentIndex(0) self.filterTextComboBox.setCurrentIndex(0) QTimer.singleShot(0, lambda index=filterIndex: self.filterComboBox. setCurrentIndex(index)) QTimer.singleShot(10, lambda index=textIndex: self.filterTextComboBox. setCurrentIndex(index)) if eid is not None: QTimer.singleShot(20, lambda eid=eid: self.view.gotoEid(eid)) def query(self): filter = FilterKind( self.filterComboBox.itemData(self.filterComboBox.currentIndex())) if filter in { FilterKind.IN_NORMAL_GROUP, FilterKind.IN_LINKED_GROUP, FilterKind.PAGES_ORDER }: self._setGroupOrPagesOrder() elif filter in { FilterKind.ENTRIES_WITH_PAGES, FilterKind.TERMS_MATCHING, FilterKind.NOTES_MATCHING }: self.filterTextComboBox.setEditable(True) self.filterTextComboBox.setEnabled(True) if self.matchTexts: with Lib.BlockSignals(self.filterTextComboBox): self.filterTextComboBox.clear() self.filterTextComboBox.addItems(self.matchTexts) self.matchTexts = [] self.setMatch() else: self.filterTextComboBox.setEnabled(False) self.view.query(filter) self.prevFilter = filter def _setGroupOrPagesOrder(self, gid=None): self.filterTextComboBox.setEditable(False) self.filterTextComboBox.setEnabled(True) items = [] filter = FilterKind( self.filterComboBox.itemData(self.filterComboBox.currentIndex())) if filter is FilterKind.IN_NORMAL_GROUP: items = list(self.state.model.normalGroups()) elif filter is FilterKind.IN_LINKED_GROUP: items = list(self.state.model.linkedGroups()) elif filter is FilterKind.PAGES_ORDER: items = [(int(x), x.text) for x in PagesOrderKind] if self.prevFilter not in { FilterKind.IN_NORMAL_GROUP, FilterKind.IN_LINKED_GROUP, FilterKind.PAGES_ORDER }: self.matchTexts = [] for i in range(self.filterTextComboBox.count()): self.matchTexts.append(self.filterTextComboBox.itemText(i)) with Lib.BlockSignals(self.filterTextComboBox): index = None self.filterTextComboBox.clear() for i, (itemId, name) in enumerate(items): self.filterTextComboBox.addItem(name, itemId) if gid is not None and gid == itemId: index = i if index is not None: self.filterTextComboBox.setCurrentIndex(index) self.setMatch() def updateDisplayFonts(self): self.view.updateDisplayFonts() def help(self): self.state.help("xix_ref_panel_filter.html") def setGroup(self, groupItem=None): if groupItem is None: groupItem = self.state.groupsPanel.groupsList.currentItem() if groupItem is not None: gid = groupItem.data(Qt.UserRole) kind = (FilterKind.IN_LINKED_GROUP if self.state.model.isLinkedGroup(gid) else FilterKind.IN_NORMAL_GROUP) for i in range(self.filterComboBox.count()): if FilterKind(self.filterComboBox.itemData(i)) is kind: self.filterComboBox.setCurrentIndex(i) break self._setGroupOrPagesOrder(gid) def groupChanged(self): filter = FilterKind( self.filterComboBox.itemData(self.filterComboBox.currentIndex())) if filter in {FilterKind.IN_NORMAL_GROUP, FilterKind.IN_LINKED_GROUP}: self.view.refresh()
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() self.createConnections() def createWidgets(self): self.formatPanel = Widgets.FormatPanel.Panel(self.state, self, editableFontSize=True) formatActions = self.formatPanel.formatActions self.titleLabel = QLabel("&Index Title") self.titleTextEdit = Widgets.LineEdit.HtmlLineEdit( self.state, formatActions=formatActions) self.titleLabel.setBuddy(self.titleTextEdit) self.titleTextEdit.setHtml(self.config.get(Gconf.Key.Title)) self.form.tooltips.append((self.titleTextEdit, """\ <p><b>Index Title</b></p> <p>The index's title. Leave blank if the title is to be added directly in the output file.</p>""")) self.noteLabel = QLabel("Index &Note") self.noteTextEdit = Widgets.LineEdit.MultilineHtmlEdit( self.state, maxLines=8, formatActions=formatActions) self.noteLabel.setBuddy(self.noteTextEdit) self.noteTextEdit.setLineWrapMode(QTextEdit.FixedColumnWidth) self.noteTextEdit.setLineWrapColumnOrWidth(60) self.noteTextEdit.setWordWrapMode(QTextOption.WordWrap) self.noteTextEdit.setHtml(self.config.get(Gconf.Key.Note)) self.form.tooltips.append((self.noteTextEdit, """\ <p><b>Index Note</b></p> <p>The index's note. Leave blank if no note is required or if the note is to be added directly in the output file.</p>""")) self.sectionsGroupBox = QGroupBox("Sections") self.blankBeforeLabel = QLabel("&Blank Lines Before") self.blankBeforeSpinBox = QSpinBox() self.blankBeforeSpinBox.setAlignment(Qt.AlignRight) self.blankBeforeLabel.setBuddy(self.blankBeforeSpinBox) self.blankBeforeSpinBox.setRange(0, 3) self.blankBeforeSpinBox.setValue( self.config.get(Gconf.Key.SectionPreLines)) self.form.tooltips.append((self.blankBeforeSpinBox, """\ <p><b>Blank Lines Before</b></p> <p>How many blank lines to output before a section. (A section is a distinct part of the index, e.g., the ‘A’s.)</p>""")) self.blankAfterLabel = QLabel("Blank &Lines After") self.blankAfterSpinBox = QSpinBox() self.blankAfterSpinBox.setAlignment(Qt.AlignRight) self.blankAfterLabel.setBuddy(self.blankAfterSpinBox) self.blankAfterSpinBox.setRange(0, 3) self.blankAfterSpinBox.setValue( self.config.get(Gconf.Key.SectionPostLines)) self.form.tooltips.append((self.blankAfterSpinBox, """\ <p><b>Blank Lines After</b></p> <p>How many blank lines to output before after section's title. (A section is a distinct part of the index, e.g., the ‘A’s.)</p>""")) self.sectionTitlesCheckBox = QCheckBox("&Output Titles") self.sectionTitlesCheckBox.setChecked( self.config.get(Gconf.Key.SectionTitles)) self.form.tooltips.append((self.sectionTitlesCheckBox, """\ <p><b>Output Titles</b></p> <p>If checked, section titles are output before each section, e.g., ‘A’, before the As, ‘B’, before the Bs, and so on.</p>""")) self.sectionSpecialTitleLabel = QLabel("Special Section &Title") self.sectionSpecialTitleTextEdit = Widgets.LineEdit.HtmlLineEdit( self.state, formatActions=formatActions) self.sectionSpecialTitleLabel.setBuddy( self.sectionSpecialTitleTextEdit) self.sectionSpecialTitleTextEdit.setHtml( self.config.get(Gconf.Key.SectionSpecialTitle)) self.form.tooltips.append((self.sectionSpecialTitleTextEdit, """\ <p><b>Special Section Title</b></p> <p>If there are entries which precede the ‘A’ section, then this section title will be used for them.</p> <p>Note that even if this title isn't used, its font name and size will be used for all the other section titles.</p>""")) size = self.font().pointSize() + (1 if WIN else 2) family = self.config.get(Gconf.Key.StdFont) size = self.config.get(Gconf.Key.StdFontSize, size) Lib.createFontBoxesFor(self, "Std", family, size, tooltips=self.form.tooltips, which="Std.") self.onStdFontChange(False) family = self.config.get(Gconf.Key.AltFont) size = self.config.get(Gconf.Key.AltFontSize, size) Lib.createFontBoxesFor(self, "Alt", family, size, tooltips=self.form.tooltips, which="Alt.") self.onAltFontChange(False) family = self.config.get(Gconf.Key.MonoFont) size = self.config.get(Gconf.Key.MonoFontSize, size) Lib.createFontBoxesFor(self, "Mono", family, size, mono=True, tooltips=self.form.tooltips, which="Mono.") self.onMonoFontChange(False) self.monoFontAsStrikeoutCheckbox = QCheckBox( "Output Mono. &Font as Strikeout") self.form.tooltips.append((self.monoFontAsStrikeoutCheckbox, """\ <p><b>Output Mono. Font as Strikeout</b></p> <p>If checked, any text in the index that is styled as mono. font family will be output using the std. font family—but with <s>strikeout</s>.</p>""")) self.monoFontAsStrikeoutCheckbox.setChecked( self.config.get(Gconf.Key.MonoFontAsStrikeout)) self.styleLabel = QLabel("St&yle") self.styleComboBox = QComboBox() self.styleLabel.setBuddy(self.styleComboBox) oldStyle = self.config.get(Gconf.Key.Style) index = -1 for i, style in enumerate(StyleKind): self.styleComboBox.addItem(style.text, style.value) if style is oldStyle: index = i self.styleComboBox.setCurrentIndex(index) self.form.tooltips.append((self.styleComboBox, """\ <p><b>Style</b></p> <p>The style of index to output.</p>""")) self.termPagesSepLabel = QLabel("T&erm-Pages Separator") self.termPagesSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.termPagesSepLabel.setBuddy(self.termPagesSepTextEdit) self.termPagesSepTextEdit.setHtml( self.config.get(Gconf.Key.TermPagesSeparator)) self.form.tooltips.append((self.termPagesSepTextEdit, """\ <p><b>Term-Pages Separator</b></p> <p>The separator text to use between the end of an entry's term and its pages.</p>{}""".format(BLANK_SPACE_HTML))) self.runInSepLabel = QLabel("&Run-in Separator") self.runInSepTextEdit = Widgets.LineEdit.SpacesHtmlLineEdit( self.state, 3, formatActions=formatActions) self.runInSepLabel.setBuddy(self.runInSepTextEdit) self.runInSepTextEdit.setHtml(self.config.get( Gconf.Key.RunInSeparator)) self.form.tooltips.append((self.runInSepTextEdit, """\ <p><b>Run-in Separator</b></p> <p>The separator text to use between run-in entries (for run-in style index output).</p>{}""".format(BLANK_SPACE_HTML))) self.formatPanel.state.editors = [ self.titleTextEdit, self.noteTextEdit, self.sectionSpecialTitleTextEdit, self.termPagesSepTextEdit, self.runInSepTextEdit ] def layoutWidgets(self): form = QFormLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.formatPanel) form.addRow(hbox) form.addRow(self.titleLabel, self.titleTextEdit) form.addRow(self.noteLabel, self.noteTextEdit) vbox = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(self.blankBeforeLabel) hbox.addWidget(self.blankBeforeSpinBox) hbox.addWidget(self.blankAfterLabel) hbox.addWidget(self.blankAfterSpinBox) hbox.addStretch() vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.sectionTitlesCheckBox) hbox.addStretch() hbox.addWidget(self.sectionSpecialTitleLabel) hbox.addWidget(self.sectionSpecialTitleTextEdit) vbox.addLayout(hbox) self.sectionsGroupBox.setLayout(vbox) form.addRow(self.sectionsGroupBox) hbox = QHBoxLayout() hbox.addWidget(self.stdFontComboBox, 1) hbox.addWidget(self.stdFontSizeSpinBox) hbox.addStretch() label = QLabel("&Std. Font") label.setBuddy(self.stdFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.altFontComboBox, 1) hbox.addWidget(self.altFontSizeSpinBox) hbox.addStretch() label = QLabel("&Alt. Font") label.setBuddy(self.altFontComboBox) form.addRow(label, hbox) hbox = QHBoxLayout() hbox.addWidget(self.monoFontComboBox, 1) hbox.addWidget(self.monoFontSizeSpinBox) hbox.addStretch() label = QLabel("&Mono. Font") label.setBuddy(self.monoFontComboBox) form.addRow(label, hbox) grid = QGridLayout() grid.addWidget(self.monoFontAsStrikeoutCheckbox, 0, 0, 1, 2) grid.addWidget(self.termPagesSepLabel, 0, 2) grid.addWidget(self.termPagesSepTextEdit, 0, 3) grid.addWidget(self.styleLabel, 1, 0) grid.addWidget(self.styleComboBox, 1, 1) grid.addWidget(self.runInSepLabel, 1, 2) grid.addWidget(self.runInSepTextEdit, 1, 3) form.addRow(grid) self.setLayout(form) def createConnections(self): self.stdFontComboBox.currentFontChanged.connect(self.onStdFontChange) self.stdFontSizeSpinBox.valueChanged[int].connect(self.onStdFontChange) self.altFontComboBox.currentFontChanged.connect(self.onAltFontChange) self.altFontSizeSpinBox.valueChanged[int].connect(self.onAltFontChange) self.monoFontComboBox.currentFontChanged.connect(self.onMonoFontChange) self.monoFontSizeSpinBox.valueChanged[int].connect( self.onMonoFontChange) def onStdFontChange(self, propagate=True): font = QFont(self.stdFontComboBox.currentFont()) font.setPointSize(self.stdFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.StdFont, font.family()) self.state.model.setConfig(Gconf.Key.StdFontSize, font.pointSize()) def onAltFontChange(self, propagate=True): font = QFont(self.altFontComboBox.currentFont()) font.setPointSize(self.altFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.AltFont, font.family()) self.state.model.setConfig(Gconf.Key.AltFontSize, font.pointSize()) def onMonoFontChange(self, propagate=True): font = QFont(self.monoFontComboBox.currentFont()) font.setPointSize(self.monoFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.MonoFont, font.family()) self.state.model.setConfig(Gconf.Key.MonoFontSize, font.pointSize())
class Form(QDialog): def __init__(self, state, parent=None): super().__init__(parent) Lib.prepareModalDialog(self) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) self.setWindowTitle("Copy Character — {}".format( QApplication.applicationName())) QShortcut(QKeySequence(QKeySequence.FindNext), self, self.findNext) self.state = state self.createWidgets() self.layoutWidgets() self.createConnections() self.findSizes(self.fontComboBox.currentFont()) self.setToFamily(self.state.stdFontFamily) self.setToNearestSize(self.state.stdFontSize) settings = QSettings() self.updateToolTips( bool( int( settings.value(Gopt.Key.ShowDialogToolTips, Gopt.Default.ShowDialogToolTips)))) def createWidgets(self): self.fontLabel = QLabel("Fon&t:") self.fontComboBox = QFontComboBox() self.tooltips.append((self.fontComboBox, """\ <p><b>Font</b></p> <p>The font for displaying the characters.</p>""")) self.fontLabel.setBuddy(self.fontComboBox) self.sizeLabel = QLabel("&Size:") self.sizeComboBox = QComboBox() self.tooltips.append((self.sizeComboBox, """\ <p><b>Size</b></p> <p>The size of font for displaying the characters.</p>""")) self.sizeLabel.setBuddy(self.sizeComboBox) self.scrollArea = QScrollArea() self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.panel = Panel() self.scrollArea.setWidget(self.panel) self.copyTextLabel = QLabel("Copy T&ext") self.copyTextLineEdit = QLineEdit() self.tooltips.append((self.copyTextLineEdit, """\ <p><b>Copy Text editor</b></p> <p>The text for copying to the clipboard when <b>Copy</b> is pressed.</p>""")) self.copyTextLabel.setBuddy(self.copyTextLineEdit) self.findTextLabel = QLabel("&Find Text") self.findTextLineEdit = QLineEdit() self.tooltips.append((self.findTextLineEdit, """\ <p><b>Find Text editor</b></p> <p>The name or partial name of Unicode characters to be found, e.g., “star” will match many characters, including U+22C6 “Star operator”.</p>""")) self.findTextLabel.setBuddy(self.findTextLineEdit) self.buttonBox = QDialogButtonBox() self.addSelectedButton = QPushButton(QIcon(":/add.svg"), "&Add Selected") self.tooltips.append((self.addSelectedButton, """\ <p><b>Add Selected</b></p> <p>Append the selected character to the <b>Copy Text</b> editor.</p>""")) self.buttonBox.addButton(self.addSelectedButton, QDialogButtonBox.ActionRole) self.findNextButton = QPushButton(QIcon(":/edit-find.svg"), "Find &Next") self.tooltips.append((self.findNextButton, """\ <p><b>Find Next</b></p> <p>Find the next character whose Unicode name contains or equals the <b>Find Text</b>.</p>""")) self.buttonBox.addButton(self.findNextButton, QDialogButtonBox.ActionRole) self.helpButton = QPushButton(QIcon(":/help.svg"), "Help") self.tooltips.append( (self.helpButton, "Help on the Copy Character dialog")) self.buttonBox.addButton(self.helpButton, QDialogButtonBox.HelpRole) self.closeButton = QPushButton(QIcon(":/dialog-close.svg"), "&Close") self.tooltips.append((self.closeButton, """<p><b>Cancel</b></p> <p>Close the dialog.</p>""")) self.buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole) def layoutWidgets(self): topLayout = QHBoxLayout() topLayout.addWidget(self.fontLabel) topLayout.addWidget(self.fontComboBox, 1) topLayout.addWidget(self.sizeLabel) topLayout.addWidget(self.sizeComboBox) bottomLayout = QHBoxLayout() bottomLayout.addWidget(self.copyTextLabel) bottomLayout.addWidget(self.copyTextLineEdit) bottomLayout.addWidget(self.findTextLabel) bottomLayout.addWidget(self.findTextLineEdit) layout = QVBoxLayout() layout.addLayout(topLayout) layout.addWidget(self.scrollArea, 1) layout.addLayout(bottomLayout) layout.addWidget(self.buttonBox) self.setLayout(layout) def createConnections(self): self.fontComboBox.activated[str].connect(self.panel.updateFont) self.sizeComboBox.currentIndexChanged[str].connect( self.panel.updateSize) self.panel.characterSelected.connect(self.copyTextLineEdit.insert) self.panel.fontResized.connect(self.updateSize) self.addSelectedButton.clicked.connect(self.addSelected) self.helpButton.clicked.connect(self.help) self.buttonBox.rejected.connect(self.accept) self.findNextButton.clicked.connect(self.findNext) self.findTextLineEdit.returnPressed.connect(self.findNext) def help(self): self.state.help("xix_ref_dlg_copychr.html") def findSizes(self, font): fontDatabase = QFontDatabase() currentSize = self.sizeComboBox.currentText() with Lib.BlockSignals(self.sizeComboBox): self.sizeComboBox.clear() if fontDatabase.isSmoothlyScalable(font.family(), fontDatabase.styleString(font)): for size in QFontDatabase.standardSizes(): self.sizeComboBox.addItem(str(size)) else: for size in fontDatabase.smoothSizes( font.family(), fontDatabase.styleString(font)): self.sizeComboBox.addItem(str(size)) self.sizeComboBox.setEditable(False) sizeIndex = self.sizeComboBox.findText(currentSize) if sizeIndex == -1: self.sizeComboBox.setCurrentIndex( max(0, self.sizeComboBox.count() / 3)) else: self.sizeComboBox.setCurrentIndex(sizeIndex) def accept(self): clipboard = QApplication.clipboard() text = self.copyTextLineEdit.text() or self.panel.currentChar clipboard.setText(text, QClipboard.Clipboard) clipboard.setText(text, QClipboard.Selection) if text: say("Copied “{}” to the clipboard".format(text), SAY_TIMEOUT) super().accept() def addSelected(self): char = self.panel.currentChar if char: self.copyTextLineEdit.setText(self.copyTextLineEdit.text() + char) self.findNextButton.setFocus() def setToFamily(self, family): family = family.casefold() for i in range(self.fontComboBox.count()): if self.fontComboBox.itemText(i).casefold() == family: self.fontComboBox.setCurrentIndex(i) break def setToNearestSize(self, size): below = 0 belowIndex = -1 above = 999 aboveIndex = -1 for i in range(self.sizeComboBox.count()): sz = int(self.sizeComboBox.itemText(i)) if sz == size: self.sizeComboBox.setCurrentIndex(i) break if sz < size and sz > below: below = sz belowIndex = i if sz > size and sz < above: above = sz aboveIndex = i else: if abs(size - below) < abs(size - above): self.sizeComboBox.setCurrentIndex(belowIndex) else: self.sizeComboBox.setCurrentIndex(aboveIndex) def findNext(self): text = self.findTextLineEdit.text().strip().casefold() if text: start = self.panel.currentChar start = ord(start) if start else ord(" ") for i in range(start + 1, MAX_CHAR): try: char = chr(i) name = unicodedata.name(char).casefold() if text in name: self.panel.currentChar = char self.panel.update() y = (self.panel.squareSize * i) // COLUMNS self.scrollArea.ensureVisible(0, y) break except ValueError: pass else: self.panel.currentChar = " " self.findNext() def keyPressEvent(self, event): key = event.key() if key in {Qt.Key_Enter, Qt.Key_Return}: if self.findTextLineEdit.text().strip(): self.findNext() else: self.addSelectedButton.setFocus() def updateSize(self, squareSize): self.setMinimumWidth((COLUMNS + (1.5 if WIN else 1)) * squareSize)
class MainWindow(QWidget, object): master_password_label = None master_password_edit = None domain_label = None domain_edit = None username_label = None username_edit = None strength_label = None strength_selector = None password_label = None password = None sync_button = None clipboard_button = None setting = None decrypt_kgk_task = None settings_window = None def __init__(self): super(MainWindow, self).__init__() self.nam = QNetworkAccessManager() self.setWindowIcon(QIcon(os.path.join('icons', 'Logo_rendered_edited.png'))) layout = QBoxLayout(QBoxLayout.TopToBottom) layout.setContentsMargins(0, 0, 0, 0) self.preference_manager = PreferenceManager() self.kgk_manager = KgkManager() self.kgk_manager.set_preference_manager(self.preference_manager) self.settings_manager = PasswordSettingsManager(self.preference_manager) self.setting_dirty = True # Header bar header_bar = QFrame() header_bar.setStyleSheet( "QWidget { background: rgb(40, 40, 40); } " + "QToolButton { background: rgb(40, 40, 40); }" + "QToolTip { color: rgb(255, 255, 255); background-color: rgb(20, 20, 20); " + "border: 1px solid white; }") header_bar.setAutoFillBackground(True) header_bar.setFixedHeight(45) header_bar_layout = QBoxLayout(QBoxLayout.LeftToRight) header_bar_layout.addStretch() header_bar.setLayout(header_bar_layout) layout.addWidget(header_bar) self.create_header_bar(header_bar_layout) # Widget area main_area = QFrame() main_layout = QBoxLayout(QBoxLayout.TopToBottom) main_area.setLayout(main_layout) layout.addWidget(main_area) self.create_main_area(main_layout) # Window layout layout.addStretch() main_layout.addStretch() self.setLayout(layout) settings = QSettings() size = settings.value("MainWindow/size") if not size: size = QSize(350, 450) self.resize(size) position = settings.value("MainWindow/pos") if not position: position = QPoint(0, 24) self.move(position) self.setWindowTitle("c't SESAM") self.master_password_edit.setFocus() self.show() # noinspection PyUnresolvedReferences def create_header_bar(self, layout): self.sync_button = QToolButton() self.sync_button.setIconSize(QSize(30, 30)) self.sync_button.setIcon(QIcon(os.path.join("icons", "ic_action_sync.png"))) self.sync_button.setStyleSheet("border: 0px;") self.sync_button.setToolTip("Sync") self.sync_button.clicked.connect(self.sync_clicked) self.sync_button.setVisible(False) layout.addWidget(self.sync_button) self.clipboard_button = QToolButton() self.clipboard_button.setIconSize(QSize(30, 30)) self.clipboard_button.setIcon(QIcon(os.path.join("icons", "ic_action_copy.png"))) self.clipboard_button.setStyleSheet("border: 0px;") self.clipboard_button.setToolTip("in die Zwischenablage") self.clipboard_button.clicked.connect(self.copy_to_clipboard) self.clipboard_button.setVisible(False) layout.addWidget(self.clipboard_button) # noinspection PyUnresolvedReferences def create_main_area(self, layout): # Master password master_password_label = QLabel("&Master-Passwort:") self.master_password_edit = QLineEdit() self.master_password_edit.setEchoMode(QLineEdit.EchoMode.Password) self.master_password_edit.textChanged.connect(self.masterpassword_changed) self.master_password_edit.returnPressed.connect(self.move_focus) self.master_password_edit.editingFinished.connect(self.masterpassword_entered) self.master_password_edit.setMaximumHeight(28) master_password_label.setBuddy(self.master_password_edit) layout.addWidget(master_password_label) layout.addWidget(self.master_password_edit) # Domain domain_label = QLabel("&Domain:") self.domain_edit = QComboBox() self.domain_edit.setEditable(True) self.domain_edit.textChanged.connect(self.domain_changed) self.domain_edit.currentIndexChanged.connect(self.domain_changed) self.domain_edit.lineEdit().editingFinished.connect(self.domain_entered) self.domain_edit.lineEdit().returnPressed.connect(self.move_focus) self.domain_edit.setMaximumHeight(28) domain_label.setBuddy(self.domain_edit) layout.addWidget(domain_label) layout.addWidget(self.domain_edit) # Username self.username_label = QLabel("&Username:"******"&Passwortstärke:") self.strength_label.setVisible(False) self.strength_selector = PasswordStrengthSelector() self.strength_selector.set_min_length(4) self.strength_selector.set_max_length(36) self.strength_selector.setMinimumHeight(60) self.strength_selector.set_length(12) self.strength_selector.set_complexity(6) self.strength_selector.strength_changed.connect(self.strength_changed) self.strength_selector.setVisible(False) self.strength_label.setBuddy(self.strength_selector) layout.addWidget(self.strength_label) layout.addWidget(self.strength_selector) # Password self.password_label = QLabel("&Passwort:") self.password_label.setVisible(False) self.password = QLabel() self.password.setTextFormat(Qt.PlainText) self.password.setAlignment(Qt.AlignCenter) self.password.setFont(QFont("Helvetica", 18, QFont.Bold)) self.password.setVisible(False) self.password_label.setBuddy(self.password) layout.addWidget(self.password_label) layout.addWidget(self.password) def set_masterpassword(self, masterpassword): self.master_password_edit.setText(masterpassword) def set_domain(self, domain): self.domain_edit.lineEdit().setText(domain) def closeEvent(self, *args, **kwargs): settings = QSettings() settings.setValue("MainWindow/size", self.size()) settings.setValue("MainWindow/pos", self.pos()) settings.sync() def masterpassword_changed(self): self.kgk_manager.reset() self.decrypt_kgk_task = None self.clipboard_button.setVisible(False) if len(self.master_password_edit.text()) > 0: self.sync_button.setVisible(True) else: self.sync_button.setVisible(False) def masterpassword_entered(self): if len(self.master_password_edit.text()) > 0 and not self.decrypt_kgk_task: self.kgk_manager.get_kgk_crypter_salt() self.decrypt_kgk_task = DecryptKgkTask( self.master_password_edit.text(), self.preference_manager, self.kgk_manager, self.settings_manager, self.domain_edit) def set_visibilities(self): if len(self.domain_edit.lineEdit().text()) > 0: self.username_label.setVisible(True) self.username_edit.setVisible(True) self.strength_label.setVisible(True) self.strength_selector.setVisible(True) self.password_label.setVisible(True) self.password.setVisible(True) else: self.username_label.setVisible(False) self.username_edit.setVisible(False) self.strength_label.setVisible(False) self.strength_selector.setVisible(False) self.password_label.setVisible(False) self.password.setVisible(False) self.clipboard_button.setVisible(False) def domain_changed(self): self.setting_dirty = True self.password.setText("") self.clipboard_button.setVisible(False) self.set_visibilities() if self.kgk_manager.has_kgk() and (not self.decrypt_kgk_task or not self.decrypt_kgk_task.is_running()) and \ len(self.domain_edit.lineEdit().text()) > 0 and \ self.domain_edit.lineEdit().text() in self.settings_manager.get_domain_list(): self.domain_entered() def domain_entered(self): self.setting_dirty = self.domain_edit.lineEdit().text() not in self.settings_manager.get_domain_list() self.setting = self.settings_manager.get_setting(self.domain_edit.lineEdit().text()) self.username_edit.blockSignals(True) self.username_edit.setText(self.setting.get_username()) self.username_edit.blockSignals(False) self.strength_selector.blockSignals(True) self.strength_selector.set_length(self.setting.get_length()) self.strength_selector.set_complexity(self.setting.get_complexity()) self.strength_selector.set_extra_count(len(self.setting.get_extra_character_set())) self.strength_selector.blockSignals(False) self.generate_password() def move_focus(self): line_edits = [self.master_password_edit, self.domain_edit, self.username_edit] for i, edit in enumerate(line_edits): if edit.hasFocus() and i + 1 < len(line_edits): line_edits[i + 1].setFocus() return True self.generate_button.setFocus() def generate_password(self): if not self.kgk_manager.has_kgk(): self.kgk_manager.create_new_kgk() self.kgk_manager.create_and_save_new_kgk_block() if not self.kgk_manager.kgk_crypter or not self.kgk_manager.salt: self.kgk_manager.get_kgk_crypter(self.master_password_edit.text().encode('utf-8'), self.kgk_manager.get_kgk_crypter_salt()) if self.setting_dirty: self.setting.new_salt() self.setting.calculate_template() self.settings_manager.set_setting(self.setting) if not self.setting.get_legacy_password(): generator = CtSesam(self.setting.get_domain(), self.setting.get_username(), self.kgk_manager.get_kgk(), self.setting.get_salt(), self.setting.get_iterations()) password = generator.generate(self.setting) else: password = self.setting.get_legacy_password() self.password.setText(password) self.password.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard) self.clipboard_button.setVisible(True) self.settings_manager.store_local_settings(self.kgk_manager) self.setting_dirty = False def copy_to_clipboard(self): QApplication.clipboard().setText(self.password.text()) def username_changed(self): if self.setting: if self.setting.get_username() != self.username_edit.text(): self.setting.set_username(self.username_edit.text()) self.setting_dirty = True self.generate_password() def strength_changed(self, complexity, length): if self.setting: if self.setting.get_length() != length: self.setting.set_length(length) self.setting_dirty = True if self.setting.get_complexity() != complexity: self.setting.set_complexity(complexity) self.setting_dirty = True self.generate_password() def migrate_local_domains(self, new_kgk_manager): for domain in self.settings_manager.get_domain_list(): setting = self.settings_manager.get_setting(domain) generator = CtSesam(setting.get_domain(), setting.get_username(), self.kgk_manager.get_kgk(), setting.get_salt(), setting.get_iterations()) setting.set_legacy_password(generator.generate(setting)) self.settings_manager.set_setting(setting) self.kgk_manager = new_kgk_manager self.settings_manager.store_local_settings(self.kgk_manager) # noinspection PyUnresolvedReferences def sync_clicked(self): self.masterpassword_entered() if not self.settings_manager.sync_manager.has_settings(): self.show_sync_settings() else: pull_successful, data = self.settings_manager.sync_manager.pull() if pull_successful and len(data) > 0: remote_kgk_manager = KgkManager() remote_kgk_manager.update_from_blob(self.master_password_edit.text().encode('utf-8'), b64decode(data)) if len(self.preference_manager.get_kgk_block()) == 112 and \ remote_kgk_manager.has_kgk() and self.kgk_manager.has_kgk() and \ self.kgk_manager.get_kgk() != remote_kgk_manager.get_kgk(): if len(self.settings_manager.get_domain_list()) > 0: print("Lokal und auf dem Server gibt es unterschiedliche KGKs. Das ist ein Problem!") self.migrate_local_domains(remote_kgk_manager) else: if len(self.preference_manager.get_kgk_block()) != 112: self.kgk_manager = remote_kgk_manager self.kgk_manager.set_preference_manager(self.preference_manager) self.kgk_manager.store_local_kgk_block() self.settings_manager.update_from_export_data(remote_kgk_manager, b64decode(data)) self.domain_edit.blockSignals(True) current_domain = self.domain_edit.lineEdit().text() for i in reversed(range(self.domain_edit.count())): self.domain_edit.removeItem(i) self.domain_edit.insertItems(0, self.settings_manager.get_domain_list()) self.domain_edit.blockSignals(False) self.domain_edit.setEditText(current_domain) self.settings_manager.store_settings(self.kgk_manager) # noinspection PyUnresolvedReferences def show_sync_settings(self, url=None, username=None, password=None): self.settings_window = SettingsWindow( self.settings_manager.sync_manager, self.nam, url=self.settings_manager.sync_manager.server_address, username=self.settings_manager.sync_manager.username, password=self.settings_manager.sync_manager.password, certificate=self.settings_manager.sync_manager.certificate) self.settings_window.finished.connect(self.sync_clicked)
class Panel(QWidget): def __init__(self, state, config, parent): super().__init__(parent) self.state = state self.config = config self.form = parent self.createWidgets() self.layoutWidgets() self.createConnections() def createWidgets(self): settings = QSettings() self.txtGroupBox = QGroupBox("Plain Text Format (.txt)") self.indentLabel = QLabel("&Indent") self.indentComboBox = QComboBox() self.indentLabel.setBuddy(self.indentComboBox) oldIndent = IndentKind.TAB oldIndent = self.config.get(Gconf.Key.Indent, oldIndent) index = -1 for i, indent in enumerate(IndentKind): text = indent.name.replace("_", " ").title() self.indentComboBox.addItem(text, indent.value) if indent is oldIndent: index = i self.indentComboBox.setCurrentIndex(index) self.form.tooltips.append((self.indentComboBox, """\ <p><b>Indent</b></p> <p>The indentation to use when outputting an indented-style index in plain text format for each level of indentation.</p>""")) self.rtfGroupBox = QGroupBox("Rich Text Format (.rtf)") self.rtfIndentLabel = QLabel("I&ndent") self.rtfIndentComboBox = QComboBox() self.rtfIndentLabel.setBuddy(self.rtfIndentComboBox) oldIndent = IndentKind(int(settings.value(Gopt.Key.IndentRTF, Gopt.Default.IndentRTF))) index = -1 for i, indent in enumerate(IndentKind): text = ("Indent" if i == 0 else indent.name.replace("_", " ").title()) self.rtfIndentComboBox.addItem(text, indent.value) if indent is oldIndent: index = i self.rtfIndentComboBox.setCurrentIndex(index) self.form.tooltips.append((self.rtfIndentComboBox, """\ <p><b>Indent</b></p> <p>The indentation to use when outputting an indented-style index in rich text format for each level of indentation.</p>""")) self.pdfGroupBox = QGroupBox("Portable Document Format (.pdf)") self.paperSizeLabel = QLabel("Paper Size") self.letterRadioButton = QRadioButton("&Letter") self.a4RadioButton = QRadioButton("&A4") size = PaperSizeKind(int(settings.value(Gopt.Key.PaperSize, Gopt.Default.PaperSize))) if size is PaperSizeKind.LETTER: self.letterRadioButton.setChecked(True) else: self.a4RadioButton.setChecked(True) self.form.tooltips.append((self.letterRadioButton, """\ <p><b>Paper Size, Letter</b></p> <p>If checked, when outputting a PDF of the index, US Letter 8.5"x11"-sized pages will be used.</p>""")) self.form.tooltips.append((self.a4RadioButton, """\ <p><b>Paper Size, A4</b></p> <p>If checked, when outputting a PDF of the index, European A4-sized pages will be used.</p>""")) def layoutWidgets(self): hbox = QHBoxLayout() hbox.addWidget(self.indentLabel) hbox.addWidget(self.indentComboBox) hbox.addStretch() self.txtGroupBox.setLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.rtfIndentLabel) hbox.addWidget(self.rtfIndentComboBox) hbox.addStretch() self.rtfGroupBox.setLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.paperSizeLabel) hbox.addWidget(self.letterRadioButton) hbox.addWidget(self.a4RadioButton) hbox.addStretch() self.pdfGroupBox.setLayout(hbox) vbox = QVBoxLayout() vbox.addWidget(self.rtfGroupBox) vbox.addWidget(self.txtGroupBox) vbox.addWidget(self.pdfGroupBox) vbox.addStretch() self.setLayout(vbox) def createConnections(self): self.indentComboBox.currentIndexChanged.connect(self.setIndent) self.rtfIndentComboBox.currentIndexChanged.connect( self.setIndentRTF) def setIndent(self, index): index = self.indentComboBox.currentIndex() indent = int(self.indentComboBox.itemData(index)) if bool(self.state.model): self.state.model.setConfig(Gconf.Key.Indent, indent) def setIndentRTF(self, index): index = self.rtfIndentComboBox.currentIndex() indent = int(self.rtfIndentComboBox.itemData(index)) settings = QSettings() settings.setValue(Gopt.Key.IndentRTF, indent)
class WidgetBridge(object): __metaclass__ = WidgetBridgeFactory def __init__(self, parent, kind, path, **kwargs): self.parent = parent self.name = path propname = path.split(".")[-1] self.property = getattr(kind, propname) self.config = dict(self.property.config) self.config.update(kwargs) self.converter = self.config.get("displayconverter") if not self.converter: self.converter = DisplayConverter( suffix = self.config.get("suffix"), label = self.config.get("verbose_name", propname) ) if hasattr(self, "getDisplayConverter"): self.converter = self.getDisplayConverter(self.converter) self.converter.setProperty(self.property) self.choices = self.config.get("choices") self.hasLabel = self.config.get("has_label", True) self.assigned = None self.container = None self.suffix = None self.label = None self.widget = self.create() if not self.container: self.container = self.widget def getWidgetType(self): return self._qttype if hasattr(self, "_qttype") else None def create(self): self.widget = self._createWidget() if hasattr(self, "customize") and callable(self.customize): self.customize(self.widget) if self.converter.suffix(None): self.container = QWidget(self.parent) self.suffix = QLabel("", self.parent) hbox = QHBoxLayout(self.container) hbox.addWidget(self.widget) hbox.addWidget(self.suffix) hbox.addStretch(1) hbox.setContentsMargins(QMargins(0, 0, 0, 0)) if self.converter.label(None) and self.hasLabel: self.label = QLabel(self.parent) self.label.setBuddy(self.widget) return self.widget def _createWidget(self): return self.getWidgetType()(parent = self.parent) def setValue(self, instance): if self.label: self.label.setText(str(self.converter.label(instance)) + ":") if self.suffix: self.suffix.setText(str(self.converter.suffix(instance))) value = getattr(instance, self.property.name) displayvalue = self.converter.to_display(value, instance) self.assigned = displayvalue self.apply(displayvalue) def apply(self, value): self.widget.setText(str(value)) def getValue(self, instance): displayvalue = self.retrieve() value = self.converter.from_display(displayvalue, instance) return value def retrieve(self): return self._pytype(self.widget.text()) def isModified(self): return self.assigned != self.retrieve()