Esempio n. 1
0
 def _sortedPages(self, pages):
     try:
         pageRange = Pages.RulesForName[
             self.model.pageRangeRules()].function
         return Pages.sortedPages(pages, pageRange)
     except Pages.Error as err:
         say(err)
Esempio n. 2
0
 def renumber(self, options, reportProgress):
     description = "renumber "
     if options.romanchange:
         description += "{}\u2013{} {:+}".format(
             roman.toRoman(options.romanfrom),
             roman.toRoman(options.romanto), options.romanchange)
         if options.decimalchange:
             description += "; "
     if options.decimalchange:
         description += "{:,}\u2013{:,} {:+}".format(
             options.decimalfrom, options.decimalto, options.decimalchange)
     percents = set()
     total = len(self)
     entries = list(self.allEntriesWithPages())
     if entries:
         macro = Lib.Command.Macro(description)
         for i, entry in enumerate(entries, 1):
             percent = int(min(100, i * 100 // total))
             if percent not in percents:  # report every 1% done
                 reportProgress("Renumbering {}%".format(percent))
                 percents.add(percent)
             pages = Pages.renumbered(entry.pages, options)
             command = Command.EditEntry(entry, entry.saf, entry.sortas,
                                         entry.term, pages, entry.notes)
             macro.append(command)
         self._stack.push(macro)  # Store, then do
         description = self._xix.doCommand(macro)
         self.changed.emit(command.eid, description)
     else:
         say("No pages in range for renumbering")
Esempio n. 3
0
 def openXix(self, filename=None):
     if self.isReadOnly(
             filename if filename is not None else self.filename):
         return
     self.closeXix()
     if filename is not None:
         self.filename = filename
     try:
         self.recent_files.remove(self.filename)
         self.updateRecentFilesMenu()
     except ValueError:
         pass  # No problem if it isn't there to be removed
     self.state.indexPath = os.path.dirname(self.filename)
     QApplication.setOverrideCursor(Qt.WaitCursor)
     try:
         say("Opening {}…".format(os.path.normpath(self.filename)))
         QApplication.processEvents()
         self.state.entryPanel.clearForm()
         self._openModel("Opened")
         self.state.entryPanel.termEdit.setFocus()
         self.state.updateUi()
         self.updateWorkTime()
         self.updateLanguageIndicator()
         self.state.setMode(ModeKind.VIEW)
         self.refreshBookmarks()
     finally:
         QApplication.restoreOverrideCursor()
Esempio n. 4
0
 def combinePages(self):
     widget = QApplication.focusWidget()
     say("Looking for overlapping pages…")
     with Lib.Qt.DisableUI(*self.window.widgets(), forModalDialog=True):
         form = Forms.CombinePages.Form(self.state, self.window)
         form.exec_()
     Lib.restoreFocus(widget)
Esempio n. 5
0
 def initialize(self):
     self.setWindowTitle("{}".format(QApplication.applicationName()))
     self.state.updateDisplayFonts()
     self.filename = None
     if len(sys.argv) > 1:
         filename = sys.argv[1]
         if (filename.lower().endswith(EXTENSION)
                 and os.path.exists(filename)):
             self.filename = filename
     if self.filename is None:
         settings = QSettings()
         filename = settings.value(Gopt.Key.MainForm_Filename,
                                   Gopt.Default.MainForm_Filename)
         if (filename and filename.lower().endswith(EXTENSION)
                 and os.path.exists(filename)):
             self.filename = filename
     if self.filename is None:
         say("Click File→New or File→Open to create or open an index")
         self.updateWorkTime()
         self.state.updateUi()
     else:
         say("Opening {}".format(os.path.normpath(self.filename)))
         QTimer.singleShot(5, self.openXix)
     self.updateRecentFilesMenu()
     self.updateToolTips()
     Lib.maybe_register_filetype(self.debug)
Esempio n. 6
0
 def copy(self):
     self.state.maybeSave()
     eid = self.selectedEntry.eid
     peid = None
     if self.copyToTopRadioButton.isChecked():
         peid = ROOT
         description = "copy “{}” to be main entry"
     elif self.subentryRadioButton.isChecked():
         peid = eid
         description = "copy “{}” to be subentry of itself"
     elif self.siblingRadioButton.isChecked():
         peid = self.selectedEntry.peid
         description = "copy “{}” to be sibling of itself"
     elif self.filteredRadioButton.isChecked():
         peid = self.filteredEntry.eid
         description = "copy “{}” under filtered"
     elif self.circledRadioButton.isChecked():
         peid = self.circledEntry.eid
         description = "copy “{}” under circled"
     elif self.recentRadioButton.isChecked():
         peid = self.recentComboBox.itemData(
             self.recentComboBox.currentIndex())
         description = "copy “{}” under recently visited"
     if peid is not None:  # Should always be True
         description = description.format(
             Lib.elidePatchHtml(self.selectedEntry.term, self.state))
         self.state.model.copyEntry(
             Lib.CopyInfo(eid, peid, self.copyXrefsCheckBox.isChecked(),
                          self.copyGroupsCheckBox.isChecked(),
                          self.copySubentriesCheckBox.isChecked(),
                          self.linkPagesCheckBox.isChecked(),
                          self.withSeeCheckBox.isChecked(), description))
         say(re.sub(r"^copy", "Copied", Lib.htmlToPlainText(description)),
             SAY_TIMEOUT)
     self.accept()
Esempio n. 7
0
 def backup(self):
     model = self.state.model
     if not model:
         return
     widget = QApplication.focusWidget()
     filename = Lib.incrementedFilename(model.filename)
     with Lib.Qt.DisableUI(*self.window.widgets(), forModalDialog=True):
         filename, _ = QFileDialog.getSaveFileName(
             self.window,
             "Backup Index — {}".format(QApplication.applicationName()),
             filename,
             "{} index (*{})".format(QApplication.applicationName(),
                                     EXTENSION))
     if filename:
         with Lib.Qt.DisableUI(*self.window.widgets(), forModalDialog=True):
             self.state.saving = True
             try:
                 self.state.maybeSave()
                 if not filename.endswith(EXTENSION):
                     filename += EXTENSION
                 say("Backing up to “{}”...".format(
                     QDir.toNativeSeparators(filename)))
                 model.optimize()
                 model.backup(filename, "Backing up",
                              self.window.reportProgress)
                 say("Backed up to “{}”".format(
                     QDir.toNativeSeparators(filename)))
             finally:
                 self.state.saving = False
     Lib.restoreFocus(widget)
Esempio n. 8
0
 def removeBookmark(self):
     self.state.maybeSave()
     eid = self.state.viewAllPanel.view.selectedEid
     if eid is not None:
         self.state.model.removeBookmark(eid)
         self.window.refreshBookmarks()
         say("Removed bookmark", SAY_TIMEOUT)
Esempio n. 9
0
 def printIndex(self):
     widget = QApplication.focusWidget()
     if self.state.printer is None:
         self.state.printer = QPrinter(QPrinter.HighResolution)
         self.state.printer.setColorMode(QPrinter.GrayScale)
         settings = QSettings()
         size = PaperSizeKind(
             int(settings.value(Gopt.Key.PaperSize,
                                Gopt.Default.PaperSize)))
         self.state.printer.setPaperSize(
             QPrinter.Letter if size is PaperSizeKind.LETTER else QPrinter.
             A4)
     with Lib.Qt.DisableUI(*self.window.widgets(), forModalDialog=True):
         form = QPrintDialog(self.state.printer, self.state.window)
         form.setWindowTitle("Print Index")
         if form.exec_():
             try:
                 with Lib.DisableUI(*self.window.widgets()):
                     config = self.state.model.configs().copy()
                     config.Filename = "print.$$$"
                     config.Printer = self.state.printer
                     Output.outputEntries(self.state.model, config,
                                          "Printing",
                                          self.window.reportProgress)
                 say("Printed")
             except Output.Error as err:
                 say("Failed to print: {}".format(err))
                 logging.error("printIndex failed: {}".format(err))
     Lib.restoreFocus(widget)
Esempio n. 10
0
 def move(self):
     self.state.maybeSave()
     eid = self.selectedEntry.eid
     if self.moveToTopRadioButton.isChecked():
         self.state.model.moveToTop(eid)
     else:
         peid = None
         if self.grandParentRadioButton.isChecked():
             peid = self.grandParentEntry.eid
             message = "move up"
         elif self.filteredRadioButton.isChecked():
             peid = self.filteredEntry.eid
             message = "move under filtered"
         elif self.circledRadioButton.isChecked():
             peid = self.circledEntry.eid
             message = "move under circled"
         elif self.recentRadioButton.isChecked():
             peid = self.recentComboBox.itemData(
                 self.recentComboBox.currentIndex())
             message = "move under recently visited"
         if peid is not None:  # Should always be True
             self.state.model.moveUnder(eid, peid, message)
             term = Lib.htmlToPlainText(self.state.model.term(eid))
             if peid == ROOT:
                 message = "Moved “{}” to be a main entry".format(term)
             else:
                 message = "Moved “{}” under “{}”".format(
                     term, Lib.htmlToPlainText(self.state.model.term(peid)))
             say(message, SAY_TIMEOUT)
     self.accept()
Esempio n. 11
0
 def addXRef(self):
     from_eid = self.selectedEntry.eid
     assert from_eid is not None
     kind = (XrefKind.SEE
             if self.seeRadioButton.isChecked() else XrefKind.SEE_ALSO)
     if self.groupRadioButton.isChecked():
         gid = int(
             self.groupComboBox.itemData(self.groupComboBox.currentIndex()))
         for to_eid in tuple(self.state.model.eidsForGid(gid)):
             self.state.model.addXRef(from_eid, to_eid, kind)
     elif not self.genericTermRadioButton.isChecked():
         to_eid = None
         if self.filteredRadioButton.isChecked():
             to_eid = self.filteredEntry.eid
         elif self.circledRadioButton.isChecked():
             to_eid = self.circledEntry.eid
         elif self.recentRadioButton.isChecked():
             to_eid = self.recentComboBox.itemData(
                 self.recentComboBox.currentIndex())
         assert to_eid is not None
         self.state.model.addXRef(from_eid, to_eid, kind)
     else:
         term = self.genericTermLineEdit.toHtml()
         kind = (XrefKind.SEE_GENERIC if self.seeRadioButton.isChecked()
                 else XrefKind.SEE_ALSO_GENERIC)
         self.state.model.addGenericXRef(from_eid, term, kind)
     say("Added cross-reference", SAY_TIMEOUT)
     self.accept()
Esempio n. 12
0
 def saveAs(self):  # No need to restore focus widget
     filename = self._getSaveAsFilename()
     if filename:
         # Do a backup to the new filename, then open it
         say("Saving to “{}”...".format(QDir.toNativeSeparators(filename)))
         self.state.model.backup(filename, "Saving",
                                 self.window.reportProgress)
         self.window.openXix(filename)
Esempio n. 13
0
 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()
Esempio n. 14
0
 def recreate(self):  # No need to restore focus widget
     item = self.listWidget.currentItem()
     if item:
         eid = item.data(Qt.UserRole)
         subentries = self.recreateSubentriesCheckBox.isChecked()
         with Lib.DisableUI(self):
             self.state.model.recreateEntry(eid, subentries)
         say("Recreated", SAY_TIMEOUT)
     self.accept()
Esempio n. 15
0
 def redo(self):
     widget = QApplication.focusWidget()
     if self.model.isRedoMacro:
         say("Redoing…")
         eid = self.viewAllPanel.view.selectedEid
         with Lib.DisableUI(*self.window.widgets()):
             self.model.redo()
         say("Redone", SAY_TIMEOUT)
     else:
         eid = self.model.redo()
     self._postUndoOrRedoRefresh(eid, widget)
Esempio n. 16
0
 def updateNavigationStatus(self):
     if (self.viewFilteredPanel.view.selectedEid is None
             or not self.viewFilteredPanel.view.lineCount):
         message = "No entries match the filter"
     elif (self.viewAllPanel.view.selectedEid !=
           self.viewFilteredPanel.view.selectedEid):
         message = ("The filtered entry isn't the current entry: "
                    "press F3 to navigate")
     else:
         message = "The filtered entry is the current entry"
     say(message, SAY_TIMEOUT)
Esempio n. 17
0
 def updateTitle(self):
     if self.filename is None:
         self.setWindowTitle(QApplication.applicationName())
         say("Click File→New or File→Open to create or open an index")
     else:
         filename = os.path.basename(self.filename)
         dirname = os.path.abspath(os.path.dirname(self.filename))
         dirname = (" [{}]".format(os.path.normcase(dirname))
                    if dirname != os.getcwd() else "")
         self.setWindowTitle("{}{} — {}".format(
             filename, dirname, QApplication.applicationName()))
Esempio n. 18
0
 def start(self):
     if self.regexRadioButton.isChecked():
         try:
             re.compile(self.searchLineEdit.text())
         except re.error as err:
             say("Invalid regex pattern: {}".format(err))
             return
     self.stopped = False
     say("Searching…")
     self.searcher.prepare(self.state.model, self.options())
     self.updateUi()
     self._search(started=True)
Esempio n. 19
0
    def _reportOnOutput(self, monitor, goodMessage, badTitle, badMessage):
        if monitor.changed:
            say(goodMessage)
        else:
            QMessageBox.warning(
                self.window, "{} — {}".format(badTitle,
                                              QApplication.applicationName()),
                """\
<p>{}</p><p>{} cannot write a file if the file is open in another
application or if you don't have access permission to write the file (or
to write in the file's folder).</p>
<p><b>Try using a different filename and/or folder.</b></p>""".format(
                    badMessage, QApplication.applicationName()))
Esempio n. 20
0
 def allChecks(self):
     if bool(self.state.model):
         self.doingAllChecks = True
         self.checkCount = 5  # Number of checks using temp file
         filename = self._checkCreateTempFile()
         self.check(FilterKind.SAME_TERM_TEXTS, filename=filename)
         self.check(FilterKind.HAS_OVERLAPPING_PAGES, filename=filename)
         self.check(FilterKind.TOO_HIGH_PAGE, filename=filename)
         self.check(FilterKind.TOO_LARGE_PAGE_RANGE, filename=filename)
         self.check(FilterKind.TOO_MANY_PAGES, filename=filename)
         self.unindexedPages()
         say("Doing All the Checks — will report each one when done",
             SAY_TIMEOUT)
Esempio n. 21
0
 def _importIndex(self, filename, inFilename):
     language, sortAsRules, pageRangeRules = self._getLanguageAndRules()
     with Lib.Timer("Imported in", 0.2):
         if self.state.model.importIndex(inFilename, self.filename,
                                         language, sortAsRules,
                                         pageRangeRules):
             say(
                 "Imported “{}” from “{}”".format(self.filename,
                                                  inFilename),
                 self.state.showMessageTime)
         else:
             say(
                 "Failed to import “{}” from “{}”".format(
                     self.filename, inFilename), self.state.showMessageTime)
     self.updateTitle()
Esempio n. 22
0
 def check(self, filter, match="", filename=None):
     if bool(self.state.model):
         uuid = self.state.model.config(UUID)
         if filename is None:
             filename = self._checkCreateTempFile()
         say("Checking “{}” — will report when done".format(filter.text),
             SAY_TIMEOUT)
         asyncResult = Check.filteredEntries(filename=filename,
                                             filter=filter,
                                             match=match)
         slot = functools.partial(self.checkDone,
                                  asyncResult=asyncResult,
                                  filename=filename,
                                  uuid=uuid,
                                  name=filter.text)
         QTimer.singleShot(CHECK_TIMEOUT, slot)
Esempio n. 23
0
 def _openModel(self, word):
     self.state.viewAllPanel.clear()
     self.state.viewFilteredPanel.clear()
     language, sortAsRules, pageRangeRules = self._getLanguageAndRules()
     with Lib.Timer("Opened in", 0.2):
         self.state.model.open(self.filename, language, sortAsRules,
                               pageRangeRules)
         say("{} “{}”".format(word, os.path.normpath(self.filename)),
             self.state.showMessageTime)
     rules = SortAs.RulesForName[self.state.model.sortAsRules()]
     self.sortAsRuleLabel.setText(LABEL_TEMPLATE.format(rules.abbrev))
     self.sortAsRuleLabel.setToolTip(Lib.rulesTip(rules.tip))
     rules = Pages.RulesForName[self.state.model.pageRangeRules()]
     self.pageRangeRulesLabel.setText(LABEL_TEMPLATE.format(rules.abbrev))
     self.pageRangeRulesLabel.setToolTip(Lib.rulesTip(rules.tip, False))
     self.updateTitle()
     self.state.viewAllPanel.view.goHome()
Esempio n. 24
0
 def newXix(self, filename):
     if self.isReadOnly(filename):
         return
     self.closeXix()
     self.filename = filename
     QApplication.setOverrideCursor(Qt.WaitCursor)
     try:
         say("Creating {}…".format(os.path.normpath(self.filename)),
             SAY_TIMEOUT)
         QApplication.processEvents()
         self._openModel("Created")
         self.state.updateUi()
         self.updateWorkTime()
         self.state.entryPanel.clearForm()
         self.updateLanguageIndicator()
         self.state.setMode(ModeKind.VIEW)
     finally:
         QApplication.restoreOverrideCursor()
Esempio n. 25
0
 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()
Esempio n. 26
0
 def importIndex(self, filename, inFilename):
     if self.isReadOnly(filename):
         return
     self.closeXix()
     Lib.remove_file(filename)  # Don't want to merge!
     self.filename = filename
     QApplication.setOverrideCursor(Qt.WaitCursor)
     try:
         say("Importing {}…".format(os.path.normpath(self.filename)),
             SAY_TIMEOUT)
         QApplication.processEvents()
         self._importIndex(filename, inFilename)
         self.state.entryPanel.termEdit.setFocus()
         self.state.updateUi()
         self.updateWorkTime()
         self.updateLanguageIndicator()
         self.state.setMode(ModeKind.VIEW)
     finally:
         QApplication.restoreOverrideCursor()
Esempio n. 27
0
 def _search(self, *, started=False):
     self.searchMatch = self.searcher.search()
     if self.stopped:
         return  # Already handled
     if self.searchMatch is None:
         self.stop("None found" if started else "No (more) found")
     else:
         if self.filteredEntriesRadioButton.isChecked():
             self.state.viewFilteredPanel.view.gotoEid(self.searchMatch.eid)
         self.state.viewAllPanel.view.gotoEid(self.searchMatch.eid)
         editor = self._searchEditor()
         if editor is not None:
             cursor = editor.textCursor()
             cursor.setPosition(self.searchMatch.start)
             cursor.setPosition(self.searchMatch.end,
                                QTextCursor.KeepAnchor)
             editor.setTextCursor(cursor)
         say("Found: Click Replace or Skip or Stop Search")
     self.updateUi()
Esempio n. 28
0
 def setSortAsRules(self, name, prefix=None, reportProgress=None):
     rules = SortAs.RulesForName[name]
     say("Updating Sort As texts for “{}” rules…".format(rules.name))
     self.setMode(ModeKind.CHANGE)
     QApplication.sendPostedEvents(None, 0)
     QApplication.processEvents()
     try:
         eid = self.viewAllPanel.view.selectedEid
         self.model.setSortAsRules(name, prefix, reportProgress)
         self.window.sortAsRuleLabel.setText(
             LABEL_TEMPLATE.format(rules.abbrev))
         self.window.sortAsRuleLabel.setToolTip(Lib.rulesTip(rules.tip))
         self.viewAllPanel.view.gotoEid(eid)
     finally:
         say("Updated Sort As texts for “{}” rules".format(rules.name),
             SAY_TIMEOUT)
         self.setMode(ModeKind.VIEW)
         QApplication.sendPostedEvents(None, 0)
         QApplication.processEvents()
Esempio n. 29
0
    def _outputIndex(self, filename, widget):
        monitor = Lib.MonitorFile(filename)
        self.state.outputPath = os.path.dirname(filename)
        nativeFilename = QDir.toNativeSeparators(filename)
        try:
            say("Outputting to “{}”…".format(nativeFilename))
            with Lib.DisableUI(*self.state.window.widgets()):
                config = self.state.model.configs().copy()
                config.Filename = filename
                Output.outputEntries(self.state.model, config, "Outputting",
                                     self.window.reportProgress)

            self._reportOnOutput(
                monitor, "Output to “{}”".format(nativeFilename),
                "Output Failed",
                "Failed to output to “{}”".format(nativeFilename))
        except Output.Error as err:
            self._reportOnOutput(
                monitor, "Output to “{}”".format(nativeFilename),
                "Output Failed",
                "Failed to output to “{}”: {}".format(nativeFilename, err))
        Lib.restoreFocus(widget)
Esempio n. 30
0
 def __init__(self, state, parent=None):
     super().__init__(parent)
     Lib.prepareModalDialog(self)
     self.state = state
     self.setWindowTitle("Combine Overlapping Pages — {}".format(
         QApplication.applicationName()))
     self.createWidgets()
     self.layoutWidgets()
     self.createConnections()
     self.entry = None
     QApplication.setOverrideCursor(Qt.WaitCursor)
     try:
         self.eids = list(
             self.state.model.filteredEntries(
                 filter=FilterKind.HAS_OVERLAPPING_PAGES,
                 match=None,
                 offset=0,
                 limit=UNLIMITED,
                 entryData=EntryDataKind.EID))
     finally:
         QApplication.restoreOverrideCursor()
     self.eidIndex = -1 if self.eids else None
     if self.eids:
         self.skip()
         self.combineButton.setFocus()
         say(
             "Found {:,} entries with overlapping pages".format(
                 len(self.eids)), SAY_TIMEOUT)
     else:
         say("No overlapping pages found", SAY_TIMEOUT)
     self.updateUi()
     settings = QSettings()
     self.updateToolTips(
         bool(
             int(
                 settings.value(Gopt.Key.ShowDialogToolTips,
                                Gopt.Default.ShowDialogToolTips))))