From a64d867ed42750948ff58f643be4ca846f13e631 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:30:02 +0200 Subject: [PATCH 1/3] Added a quote symbol selection dialog --- nw/constants/constants.py | 45 +++++++++-------- nw/gui/custom.py | 104 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 25 deletions(-) diff --git a/nw/constants/constants.py b/nw/constants/constants.py index 9bd47110..b05f8e6d 100644 --- a/nw/constants/constants.py +++ b/nw/constants/constants.py @@ -169,27 +169,30 @@ class nwQuotes(): Source: https://en.wikipedia.org/wiki/Quotation_mark """ - SYMBOLS = [ - "\u0022", # Quotation mark - "\u0027", # Apostrophe - "\u00ab", # Left-pointing double angle quotation mark - "\u00bb", # Right-pointing double angle quotation mark - "\u2018", # Left single quotation mark - "\u2019", # Right single quotation mark - "\u201a", # Single low-9 quotation mark - "\u201b", # Single high-reversed-9 quotation mark - "\u201c", # Left double quotation mark - "\u201d", # Right double quotation mark - "\u201e", # Double low-9 quotation mark - "\u201f", # Double high-reversed-9 quotation mark - "\u2039", # Single left-pointing angle quotation mark - "\u203a", # Single right-pointing angle quotation mark - "\u2e42", # Double low-reversed-9 quotation mark - "\u300c", # Left corner bracket - "\u300d", # Right corner bracket - "\u300e", # Left white corner bracket - "\u300f", # Right white corner bracket - ] + SYMBOLS = { + "\u0027" : "Straight single quotation mark", + "\u0022" : "Straight double quotation mark", + + "\u2018" : "Left single quotation mark", + "\u2019" : "Right single quotation mark", + "\u201a" : "Single low-9 quotation mark", + "\u201b" : "Single high-reversed-9 quotation mark", + "\u201c" : "Left double quotation mark", + "\u201d" : "Right double quotation mark", + "\u201e" : "Double low-9 quotation mark", + "\u201f" : "Double high-reversed-9 quotation mark", + "\u2e42" : "Double low-reversed-9 quotation mark", + + "\u2039" : "Single left-pointing angle quotation mark", + "\u203a" : "Single right-pointing angle quotation mark", + "\u00ab" : "Left-pointing double angle quotation mark", + "\u00bb" : "Right-pointing double angle quotation mark", + + "\u300c" : "Left corner bracket", + "\u300d" : "Right corner bracket", + "\u300e" : "Left white corner bracket", + "\u300f" : "Right white corner bracket", + } # END Class nwQuotes diff --git a/nw/gui/custom.py b/nw/gui/custom.py index 5c3dfbd6..051fa1f3 100644 --- a/nw/gui/custom.py +++ b/nw/gui/custom.py @@ -30,17 +30,17 @@ import logging import nw -from PyQt5.QtGui import QColor, QPalette, QPainter +from PyQt5.QtGui import QColor, QPalette, QPainter, QFontMetrics from PyQt5.QtCore import ( Qt, QRect, QPoint, QSize, QRectF, QPropertyAnimation, pyqtProperty ) from PyQt5.QtWidgets import ( QGridLayout, QLabel, QWidget, QVBoxLayout, QHBoxLayout, QSizePolicy, - QAbstractButton, QDialog, QTabWidget, QTabBar, QStyle, - QStylePainter, QStyleOptionTab + QAbstractButton, QDialog, QTabWidget, QTabBar, QStyle, QDialogButtonBox, + QStylePainter, QStyleOptionTab, QListWidget, QListWidgetItem, QFrame ) -from nw.constants import nwUnicode +from nw.constants import nwUnicode, nwQuotes logger = logging.getLogger(__name__) @@ -436,3 +436,99 @@ class VerticalTabBar(QTabBar): return # END Class VerticalTabBar + +# =============================================================================================== # +# Quotes Dialog +# =============================================================================================== # + +class QuotesDialog(QDialog): + + def __init__(self, theParent=None, currentQuote="\""): + QDialog.__init__(self, parent=theParent) + + self.mainConf = nw.CONFIG + + self.outerBox = QVBoxLayout() + self.innerBox = QHBoxLayout() + self.labelBox = QVBoxLayout() + + self.selectedQuote = currentQuote + + qMetrics = QFontMetrics(self.font()) + pxW = 7*qMetrics.boundingRectChar("M").width() + pxH = 7*qMetrics.boundingRectChar("M").height() + pxH = 7*qMetrics.boundingRectChar("M").height() + + lblFont = self.font() + lblFont.setPointSizeF(4*lblFont.pointSizeF()) + + # Preview Label + self.previewLabel = QLabel(currentQuote) + self.previewLabel.setFont(lblFont) + self.previewLabel.setFixedSize(QSize(pxW, pxH)) + self.previewLabel.setAlignment(Qt.AlignCenter) + self.previewLabel.setFrameStyle(QFrame.Box | QFrame.Plain) + + # Quote Symbols + self.listBox = QListWidget() + self.listBox.itemSelectionChanged.connect(self._selectedSymbol) + + minSize = 100 + for sKey, sLabel in nwQuotes.SYMBOLS.items(): + theText = "[ %s ] %s" % (sKey, sLabel) + minSize = max(minSize, qMetrics.boundingRect(theText).width()) + qtItem = QListWidgetItem(theText) + qtItem.setData(Qt.UserRole, sKey) + self.listBox.addItem(qtItem) + if sKey == currentQuote: + self.listBox.setCurrentItem(qtItem) + + self.listBox.setMinimumWidth(minSize + self.mainConf.pxInt(40)) + self.listBox.setMinimumHeight(self.mainConf.pxInt(150)) + + # Buttons + self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox.accepted.connect(self._doAccept) + self.buttonBox.rejected.connect(self._doReject) + + # Assemble + self.labelBox.addWidget(self.previewLabel, 0, Qt.AlignTop) + self.labelBox.addStretch(1) + + self.innerBox.addLayout(self.labelBox) + self.innerBox.addWidget(self.listBox) + + self.outerBox.addLayout(self.innerBox) + self.outerBox.addWidget(self.buttonBox) + + self.setLayout(self.outerBox) + + return + + ## + # Slots + ## + + def _selectedSymbol(self): + """Update the preview label and the selected quote style. + """ + selItems = self.listBox.selectedItems() + if selItems: + theSymbol = selItems[0].data(Qt.UserRole) + self.previewLabel.setText(theSymbol) + self.selectedQuote = theSymbol + return + + def _doAccept(self): + """Ok button clicked. + """ + self.accept() + return + + def _doReject(self): + """Cancel button clicked. + """ + self.reject() + return + +# END Class QuotesDialog From 670f1c0b35bb56a3547bcbec55b792116db4740f Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:30:34 +0200 Subject: [PATCH 2/3] Added the quote selection dialog to Preferences --- nw/gui/preferences.py | 98 ++++++++++++++++++++++++++---------------- nw/gui/projsettings.py | 2 - 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/nw/gui/preferences.py b/nw/gui/preferences.py index 5c0ef235..ff9f0469 100644 --- a/nw/gui/preferences.py +++ b/nw/gui/preferences.py @@ -37,7 +37,7 @@ from PyQt5.QtWidgets import ( QDialogButtonBox, QFileDialog, QFontDialog ) -from nw.gui.custom import QSwitch, QConfigLayout, PagedDialog +from nw.gui.custom import QSwitch, QConfigLayout, PagedDialog, QuotesDialog from nw.core import NWSpellCheck, NWSpellSimple, NWSpellEnchant from nw.constants import nwAlert, nwQuotes @@ -816,51 +816,72 @@ class GuiConfigEditAutoReplaceTab(QWidget): self.mainForm.addGroupLabel("Quotation Style") qWidth = self.mainConf.pxInt(40) + bWidth = int(2.5*self.theTheme.getTextWidth("...")) ## Single Quote Style self.quoteSingleStyleO = QLineEdit() self.quoteSingleStyleO.setMaxLength(1) + self.quoteSingleStyleO.setReadOnly(True) self.quoteSingleStyleO.setFixedWidth(qWidth) self.quoteSingleStyleO.setAlignment(Qt.AlignCenter) self.quoteSingleStyleO.setText(self.mainConf.fmtSingleQuotes[0]) + self.btnSingleStyleO = QPushButton("...") + self.btnSingleStyleO.setMaximumWidth(bWidth) + self.btnSingleStyleO.clicked.connect(self._getSingleOpen) self.mainForm.addRow( "Single quote open style", self.quoteSingleStyleO, - "Auto-replaces apostrophe before words." + "Auto-replaces apostrophe before words.", + theButton=self.btnSingleStyleO ) self.quoteSingleStyleC = QLineEdit() self.quoteSingleStyleC.setMaxLength(1) + self.quoteSingleStyleC.setReadOnly(True) self.quoteSingleStyleC.setFixedWidth(qWidth) self.quoteSingleStyleC.setAlignment(Qt.AlignCenter) self.quoteSingleStyleC.setText(self.mainConf.fmtSingleQuotes[1]) + self.btnSingleStyleC = QPushButton("...") + self.btnSingleStyleC.setMaximumWidth(bWidth) + self.btnSingleStyleC.clicked.connect(self._getSingleClose) self.mainForm.addRow( "Single quote close style", self.quoteSingleStyleC, - "Auto-replaces apostrophe after words." + "Auto-replaces apostrophe after words.", + theButton=self.btnSingleStyleC ) ## Double Quote Style self.quoteDoubleStyleO = QLineEdit() self.quoteDoubleStyleO.setMaxLength(1) + self.quoteDoubleStyleO.setReadOnly(True) self.quoteDoubleStyleO.setFixedWidth(qWidth) self.quoteDoubleStyleO.setAlignment(Qt.AlignCenter) self.quoteDoubleStyleO.setText(self.mainConf.fmtDoubleQuotes[0]) + self.btnDoubleStyleO = QPushButton("...") + self.btnDoubleStyleO.setMaximumWidth(bWidth) + self.btnDoubleStyleO.clicked.connect(self._getDoubleOpen) self.mainForm.addRow( "Double quote open style", self.quoteDoubleStyleO, - "Auto-replaces straight quotes before words." + "Auto-replaces straight quotes before words.", + theButton=self.btnDoubleStyleO ) self.quoteDoubleStyleC = QLineEdit() self.quoteDoubleStyleC.setMaxLength(1) + self.quoteDoubleStyleC.setReadOnly(True) self.quoteDoubleStyleC.setFixedWidth(qWidth) self.quoteDoubleStyleC.setAlignment(Qt.AlignCenter) self.quoteDoubleStyleC.setText(self.mainConf.fmtDoubleQuotes[1]) + self.btnDoubleStyleC = QPushButton("...") + self.btnDoubleStyleC.setMaximumWidth(bWidth) + self.btnDoubleStyleC.clicked.connect(self._getDoubleClose) self.mainForm.addRow( "Double quote close style", self.quoteDoubleStyleC, - "Auto-replaces straight quotes after words." + "Auto-replaces straight quotes after words.", + theButton=self.btnDoubleStyleC ) return @@ -889,37 +910,10 @@ class GuiConfigEditAutoReplaceTab(QWidget): fmtDoubleQuotesO = self.quoteDoubleStyleO.text() fmtDoubleQuotesC = self.quoteDoubleStyleC.text() - if self._checkQuoteSymbol(fmtSingleQuotesO): - self.mainConf.fmtSingleQuotes[0] = fmtSingleQuotesO - else: - self.theParent.makeAlert( - "Invalid quote symbol: %s" % fmtSingleQuotesO, nwAlert.ERROR - ) - validEntries = False - - if self._checkQuoteSymbol(fmtSingleQuotesC): - self.mainConf.fmtSingleQuotes[1] = fmtSingleQuotesC - else: - self.theParent.makeAlert( - "Invalid quote symbol: %s" % fmtSingleQuotesC, nwAlert.ERROR - ) - validEntries = False - - if self._checkQuoteSymbol(fmtDoubleQuotesO): - self.mainConf.fmtDoubleQuotes[0] = fmtDoubleQuotesO - else: - self.theParent.makeAlert( - "Invalid quote symbol: %s" % fmtDoubleQuotesO, nwAlert.ERROR - ) - validEntries = False - - if self._checkQuoteSymbol(fmtDoubleQuotesC): - self.mainConf.fmtDoubleQuotes[1] = fmtDoubleQuotesC - else: - self.theParent.makeAlert( - "Invalid quote symbol: %s" % fmtDoubleQuotesC, nwAlert.ERROR - ) - validEntries = False + self.mainConf.fmtSingleQuotes[0] = fmtSingleQuotesO + self.mainConf.fmtSingleQuotes[1] = fmtSingleQuotesC + self.mainConf.fmtDoubleQuotes[0] = fmtDoubleQuotesO + self.mainConf.fmtDoubleQuotes[1] = fmtDoubleQuotesC self.mainConf.confChanged = True @@ -939,6 +933,38 @@ class GuiConfigEditAutoReplaceTab(QWidget): self.autoReplaceDots.setEnabled(theState) return + def _getSingleOpen(self): + """Dialog for single quote open. + """ + qtBox = QuotesDialog(self, currentQuote=self.quoteSingleStyleO.text()) + if qtBox.exec_() == QDialog.Accepted: + self.quoteSingleStyleO.setText(qtBox.selectedQuote) + return + + def _getSingleClose(self): + """Dialog for single quote close. + """ + qtBox = QuotesDialog(self, currentQuote=self.quoteSingleStyleC.text()) + if qtBox.exec_() == QDialog.Accepted: + self.quoteSingleStyleC.setText(qtBox.selectedQuote) + return + + def _getDoubleOpen(self): + """Dialog for double quote open. + """ + qtBox = QuotesDialog(self, currentQuote=self.quoteDoubleStyleO.text()) + if qtBox.exec_() == QDialog.Accepted: + self.quoteDoubleStyleO.setText(qtBox.selectedQuote) + return + + def _getDoubleClose(self): + """Dialog for double quote close. + """ + qtBox = QuotesDialog(self, currentQuote=self.quoteDoubleStyleC.text()) + if qtBox.exec_() == QDialog.Accepted: + self.quoteDoubleStyleC.setText(qtBox.selectedQuote) + return + ## # Internal Functions ## diff --git a/nw/gui/projsettings.py b/nw/gui/projsettings.py index 0afaefbf..a9c19038 100644 --- a/nw/gui/projsettings.py +++ b/nw/gui/projsettings.py @@ -73,8 +73,6 @@ class GuiProjectSettings(PagedDialog): self.buttonBox.rejected.connect(self._doClose) self.addControls(self.buttonBox) - self.show() - logger.debug("GuiProjectSettings initialisation complete") return From 28641a7b13a796f6012d89e6be17884dec677c44 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 18 Jun 2020 21:20:15 +0200 Subject: [PATCH 3/3] Fixed test and cleaned up imports --- nw/gui/preferences.py | 2 +- nw/gui/projsettings.py | 7 +++---- tests/test_gui.py | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nw/gui/preferences.py b/nw/gui/preferences.py index ff9f0469..56905307 100644 --- a/nw/gui/preferences.py +++ b/nw/gui/preferences.py @@ -39,7 +39,7 @@ from PyQt5.QtWidgets import ( from nw.gui.custom import QSwitch, QConfigLayout, PagedDialog, QuotesDialog from nw.core import NWSpellCheck, NWSpellSimple, NWSpellEnchant -from nw.constants import nwAlert, nwQuotes +from nw.constants import nwQuotes logger = logging.getLogger(__name__) diff --git a/nw/gui/projsettings.py b/nw/gui/projsettings.py index a9c19038..8f5dacb3 100644 --- a/nw/gui/projsettings.py +++ b/nw/gui/projsettings.py @@ -31,10 +31,9 @@ import nw from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush from PyQt5.QtWidgets import ( - QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QLineEdit, QPlainTextEdit, - QLabel, QWidget, QTabWidget, QDialogButtonBox, QListWidget, QPushButton, - QListWidgetItem, QColorDialog, QAbstractItemView, QTreeWidget, QCheckBox, - QTreeWidgetItem + QHBoxLayout, QVBoxLayout, QGridLayout, QLineEdit, QPlainTextEdit, QLabel, + QWidget, QDialogButtonBox, QListWidget, QPushButton, QListWidgetItem, + QColorDialog, QAbstractItemView, QTreeWidget, QTreeWidgetItem ) from nw.constants import nwAlert diff --git a/tests/test_gui.py b/tests/test_gui.py index cd375cd8..1a18ec99 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -273,6 +273,7 @@ def testProjectEditor(qtbot, nwTempGUI, nwRef, nwTemp): nwGUI.mainConf.backupPath = nwTempGUI projEdit = GuiProjectSettings(nwGUI, nwGUI.theProject) + projEdit.show() qtbot.addWidget(projEdit) projEdit.tabMain.editName.setText("")