From b1192101ce6c1a30a7f06e1f9331f1dbc202061f Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Thu, 30 Nov 2017 11:11:01 +0100 Subject: [PATCH 1/3] Adds Format menu to mainWindow ui --- .../actions/format-text-strikethrough.svg | 6 + .../actions/format-text-strikethrough.svg | 6 + .../actions/format-text-strikethrough.svg | 7 + .../actions/format-text-strikethrough.svg | 7 + .../actions/format-text-strikethrough.svg | 6 + .../actions/format-text-strikethrough.svg | 6 + .../actions/format-text-strikethrough.svg | 7 + .../actions/format-text-strikethrough.svg | 6 + manuskript/ui/mainWindow.py | 123 +++++++- manuskript/ui/mainWindow.ui | 290 +++++++++++++++--- 10 files changed, 416 insertions(+), 48 deletions(-) create mode 100644 icons/NumixMsk/128x128/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/16x16/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/22x22/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/24x24/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/256x256/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/32x32/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/48x48/actions/format-text-strikethrough.svg create mode 100644 icons/NumixMsk/64x64/actions/format-text-strikethrough.svg diff --git a/icons/NumixMsk/128x128/actions/format-text-strikethrough.svg b/icons/NumixMsk/128x128/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..39d148f1 --- /dev/null +++ b/icons/NumixMsk/128x128/actions/format-text-strikethrough.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/icons/NumixMsk/16x16/actions/format-text-strikethrough.svg b/icons/NumixMsk/16x16/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..759dcafd --- /dev/null +++ b/icons/NumixMsk/16x16/actions/format-text-strikethrough.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/icons/NumixMsk/22x22/actions/format-text-strikethrough.svg b/icons/NumixMsk/22x22/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..43c55933 --- /dev/null +++ b/icons/NumixMsk/22x22/actions/format-text-strikethrough.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/icons/NumixMsk/24x24/actions/format-text-strikethrough.svg b/icons/NumixMsk/24x24/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..e2e919fa --- /dev/null +++ b/icons/NumixMsk/24x24/actions/format-text-strikethrough.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/icons/NumixMsk/256x256/actions/format-text-strikethrough.svg b/icons/NumixMsk/256x256/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..ed9f5160 --- /dev/null +++ b/icons/NumixMsk/256x256/actions/format-text-strikethrough.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/icons/NumixMsk/32x32/actions/format-text-strikethrough.svg b/icons/NumixMsk/32x32/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..55b1221a --- /dev/null +++ b/icons/NumixMsk/32x32/actions/format-text-strikethrough.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/icons/NumixMsk/48x48/actions/format-text-strikethrough.svg b/icons/NumixMsk/48x48/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..292bdb53 --- /dev/null +++ b/icons/NumixMsk/48x48/actions/format-text-strikethrough.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/icons/NumixMsk/64x64/actions/format-text-strikethrough.svg b/icons/NumixMsk/64x64/actions/format-text-strikethrough.svg new file mode 100644 index 00000000..84364b67 --- /dev/null +++ b/icons/NumixMsk/64x64/actions/format-text-strikethrough.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 484df035..30df4f4c 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -378,7 +378,7 @@ class Ui_MainWindow(object): self.scrollAreaPersoInfos.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.scrollAreaPersoInfos.setObjectName("scrollAreaPersoInfos") self.scrollAreaPersoInfosWidget = QtWidgets.QWidget() - self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 426, 688)) + self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 204, 606)) self.scrollAreaPersoInfosWidget.setObjectName("scrollAreaPersoInfosWidget") self.formLayout_8 = QtWidgets.QFormLayout(self.scrollAreaPersoInfosWidget) self.formLayout_8.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) @@ -1040,6 +1040,12 @@ class Ui_MainWindow(object): self.menuTools.setObjectName("menuTools") self.menuEdit = QtWidgets.QMenu(self.menubar) self.menuEdit.setObjectName("menuEdit") + self.mnuFormat = QtWidgets.QMenu(self.menuEdit) + icon = QtGui.QIcon.fromTheme("format-text-bold") + self.mnuFormat.setIcon(icon) + self.mnuFormat.setObjectName("mnuFormat") + self.mnuHeader = QtWidgets.QMenu(self.mnuFormat) + self.mnuHeader.setObjectName("mnuHeader") self.menuView = QtWidgets.QMenu(self.menubar) self.menuView.setObjectName("menuView") self.menuMode = QtWidgets.QMenu(self.menuView) @@ -1214,6 +1220,56 @@ class Ui_MainWindow(object): icon = QtGui.QIcon.fromTheme("edit-rename") self.actRename.setIcon(icon) self.actRename.setObjectName("actRename") + self.actHeaderSetextL1 = QtWidgets.QAction(MainWindow) + self.actHeaderSetextL1.setObjectName("actHeaderSetextL1") + self.actHeaderSetextL2 = QtWidgets.QAction(MainWindow) + self.actHeaderSetextL2.setObjectName("actHeaderSetextL2") + self.actHeaderAtxL1 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL1.setObjectName("actHeaderAtxL1") + self.actHeaderAtxL2 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL2.setObjectName("actHeaderAtxL2") + self.actHeaderAtxL3 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL3.setObjectName("actHeaderAtxL3") + self.actHeaderAtxL4 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL4.setObjectName("actHeaderAtxL4") + self.actHeaderAtxL5 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL5.setObjectName("actHeaderAtxL5") + self.actHeaderAtxL6 = QtWidgets.QAction(MainWindow) + self.actHeaderAtxL6.setObjectName("actHeaderAtxL6") + self.actFormatBold = QtWidgets.QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("format-text-bold") + self.actFormatBold.setIcon(icon) + self.actFormatBold.setObjectName("actFormatBold") + self.actFormatItalic = QtWidgets.QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("format-text-italic") + self.actFormatItalic.setIcon(icon) + self.actFormatItalic.setObjectName("actFormatItalic") + self.actFormatStrike = QtWidgets.QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("format-text-strikethrough") + self.actFormatStrike.setIcon(icon) + self.actFormatStrike.setObjectName("actFormatStrike") + self.actFormatVerbatim = QtWidgets.QAction(MainWindow) + self.actFormatVerbatim.setObjectName("actFormatVerbatim") + self.actFormatSuperscript = QtWidgets.QAction(MainWindow) + self.actFormatSuperscript.setObjectName("actFormatSuperscript") + self.actFormatSubscript = QtWidgets.QAction(MainWindow) + self.actFormatSubscript.setObjectName("actFormatSubscript") + self.actFormatCommentBlock = QtWidgets.QAction(MainWindow) + self.actFormatCommentBlock.setObjectName("actFormatCommentBlock") + self.actFormatClear = QtWidgets.QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("format-text-none") + self.actFormatClear.setIcon(icon) + self.actFormatClear.setObjectName("actFormatClear") + self.actFormatCommentLines = QtWidgets.QAction(MainWindow) + self.actFormatCommentLines.setObjectName("actFormatCommentLines") + self.actFormatUnorderedList = QtWidgets.QAction(MainWindow) + self.actFormatUnorderedList.setObjectName("actFormatUnorderedList") + self.actFormatList = QtWidgets.QAction(MainWindow) + icon = QtGui.QIcon.fromTheme("view-list") + self.actFormatList.setIcon(icon) + self.actFormatList.setObjectName("actFormatList") + self.actFormatBlockquote = QtWidgets.QAction(MainWindow) + self.actFormatBlockquote.setObjectName("actFormatBlockquote") self.menuFile.addAction(self.actOpen) self.menuFile.addAction(self.menuRecents.menuAction()) self.menuFile.addAction(self.actSave) @@ -1228,12 +1284,39 @@ class Ui_MainWindow(object): self.menuHelp.addAction(self.actAbout) self.menuTools.addAction(self.actSpellcheck) self.menuTools.addAction(self.actToolFrequency) + self.mnuHeader.addAction(self.actHeaderSetextL1) + self.mnuHeader.addAction(self.actHeaderSetextL2) + self.mnuHeader.addSeparator() + self.mnuHeader.addAction(self.actHeaderAtxL1) + self.mnuHeader.addAction(self.actHeaderAtxL2) + self.mnuHeader.addAction(self.actHeaderAtxL3) + self.mnuHeader.addAction(self.actHeaderAtxL4) + self.mnuHeader.addAction(self.actHeaderAtxL5) + self.mnuHeader.addAction(self.actHeaderAtxL6) + self.mnuFormat.addAction(self.mnuHeader.menuAction()) + self.mnuFormat.addSeparator() + self.mnuFormat.addAction(self.actFormatBold) + self.mnuFormat.addAction(self.actFormatItalic) + self.mnuFormat.addAction(self.actFormatStrike) + self.mnuFormat.addAction(self.actFormatVerbatim) + self.mnuFormat.addAction(self.actFormatSuperscript) + self.mnuFormat.addAction(self.actFormatSubscript) + self.mnuFormat.addAction(self.actFormatCommentLines) + self.mnuFormat.addSeparator() + self.mnuFormat.addAction(self.actFormatList) + self.mnuFormat.addAction(self.actFormatUnorderedList) + self.mnuFormat.addAction(self.actFormatBlockquote) + self.mnuFormat.addAction(self.actFormatCommentBlock) + self.mnuFormat.addSeparator() + self.mnuFormat.addAction(self.actFormatClear) self.menuEdit.addAction(self.actCut) self.menuEdit.addAction(self.actCopy) self.menuEdit.addAction(self.actPaste) self.menuEdit.addAction(self.actDelete) self.menuEdit.addAction(self.actRename) self.menuEdit.addSeparator() + self.menuEdit.addAction(self.mnuFormat.menuAction()) + self.menuEdit.addSeparator() self.menuEdit.addAction(self.actLabels) self.menuEdit.addAction(self.actStatus) self.menuEdit.addAction(self.actSettings) @@ -1366,6 +1449,8 @@ class Ui_MainWindow(object): self.menuHelp.setTitle(_translate("MainWindow", "&Help")) self.menuTools.setTitle(_translate("MainWindow", "&Tools")) self.menuEdit.setTitle(_translate("MainWindow", "&Edit")) + self.mnuFormat.setTitle(_translate("MainWindow", "&Format")) + self.mnuHeader.setTitle(_translate("MainWindow", "&Header")) self.menuView.setTitle(_translate("MainWindow", "&View")) self.menuMode.setTitle(_translate("MainWindow", "&Mode")) self.menuOrganize.setTitle(_translate("MainWindow", "Organi&ze")) @@ -1415,7 +1500,6 @@ class Ui_MainWindow(object): self.actMerge.setText(_translate("MainWindow", "M&erge")) self.actMerge.setShortcut(_translate("MainWindow", "Ctrl+M")) self.actDuplicate.setText(_translate("MainWindow", "Dupl&icate")) - self.actDuplicate.setShortcut(_translate("MainWindow", "Ctrl+D")) self.actDelete.setText(_translate("MainWindow", "&Delete")) self.actDelete.setShortcut(_translate("MainWindow", "Del")) self.actMoveUp.setText(_translate("MainWindow", "&Move Up")) @@ -1424,6 +1508,41 @@ class Ui_MainWindow(object): self.actMoveDown.setShortcut(_translate("MainWindow", "Ctrl+Shift+Down")) self.actRename.setText(_translate("MainWindow", "&Rename")) self.actRename.setShortcut(_translate("MainWindow", "F2")) + self.actHeaderSetextL1.setText(_translate("MainWindow", "&Level 1 (setext)")) + self.actHeaderSetextL1.setShortcut(_translate("MainWindow", "Ctrl+Alt+1")) + self.actHeaderSetextL2.setText(_translate("MainWindow", "Level &2")) + self.actHeaderSetextL2.setShortcut(_translate("MainWindow", "Ctrl+Alt+2")) + self.actHeaderAtxL1.setText(_translate("MainWindow", "Level &1 (atx)")) + self.actHeaderAtxL1.setShortcut(_translate("MainWindow", "Ctrl+1")) + self.actHeaderAtxL2.setText(_translate("MainWindow", "L&evel 2")) + self.actHeaderAtxL2.setShortcut(_translate("MainWindow", "Ctrl+2")) + self.actHeaderAtxL3.setText(_translate("MainWindow", "Level &3")) + self.actHeaderAtxL3.setShortcut(_translate("MainWindow", "Ctrl+3")) + self.actHeaderAtxL4.setText(_translate("MainWindow", "Level &4")) + self.actHeaderAtxL4.setShortcut(_translate("MainWindow", "Ctrl+4")) + self.actHeaderAtxL5.setText(_translate("MainWindow", "Level &5")) + self.actHeaderAtxL5.setShortcut(_translate("MainWindow", "Ctrl+5")) + self.actHeaderAtxL6.setText(_translate("MainWindow", "Level &6")) + self.actHeaderAtxL6.setShortcut(_translate("MainWindow", "Ctrl+6")) + self.actFormatBold.setText(_translate("MainWindow", "&Bold")) + self.actFormatBold.setShortcut(_translate("MainWindow", "Ctrl+B")) + self.actFormatItalic.setText(_translate("MainWindow", "&Italic")) + self.actFormatItalic.setShortcut(_translate("MainWindow", "Ctrl+I")) + self.actFormatStrike.setText(_translate("MainWindow", "&Strike")) + self.actFormatVerbatim.setText(_translate("MainWindow", "&Verbatim")) + self.actFormatSuperscript.setText(_translate("MainWindow", "Su&perscript")) + self.actFormatSuperscript.setShortcut(_translate("MainWindow", "Ctrl++")) + self.actFormatSubscript.setText(_translate("MainWindow", "Subsc&ript")) + self.actFormatSubscript.setShortcut(_translate("MainWindow", "Ctrl+-")) + self.actFormatCommentBlock.setText(_translate("MainWindow", "Co&mment block")) + self.actFormatCommentBlock.setShortcut(_translate("MainWindow", "Ctrl+Shift+C")) + self.actFormatClear.setText(_translate("MainWindow", "Clear &formats")) + self.actFormatClear.setShortcut(_translate("MainWindow", "Ctrl+0")) + self.actFormatCommentLines.setText(_translate("MainWindow", "&Comment line(s)")) + self.actFormatCommentLines.setShortcut(_translate("MainWindow", "Ctrl+C")) + self.actFormatUnorderedList.setText(_translate("MainWindow", "&Ordered list")) + self.actFormatList.setText(_translate("MainWindow", "&Unordered list")) + self.actFormatBlockquote.setText(_translate("MainWindow", "B&lockquote")) from manuskript.ui.cheatSheet import cheatSheet from manuskript.ui.editors.mainEditor import mainEditor diff --git a/manuskript/ui/mainWindow.ui b/manuskript/ui/mainWindow.ui index 150f7040..0d13a749 100644 --- a/manuskript/ui/mainWindow.ui +++ b/manuskript/ui/mainWindow.ui @@ -629,7 +629,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -640,7 +640,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -651,7 +651,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -662,7 +662,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -737,7 +737,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -751,7 +751,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -815,8 +815,8 @@ 0 0 - 426 - 688 + 204 + 606 @@ -905,7 +905,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -988,7 +988,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -1033,7 +1033,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -1044,7 +1044,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -1075,7 +1075,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. @@ -1136,7 +1136,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1150,7 +1150,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1264,7 +1264,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1281,7 +1281,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1355,7 +1355,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. Ctrl+Return @@ -1375,7 +1375,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. Ctrl+Backspace @@ -1405,7 +1405,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1557,7 +1557,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1571,7 +1571,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1770,7 +1770,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1784,7 +1784,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1798,7 +1798,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1825,7 +1825,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1917,7 +1917,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1931,7 +1931,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -1945,7 +1945,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. true @@ -2137,12 +2137,53 @@ &Edit + + + &Format + + + + .. + + + + &Header + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2286,7 +2327,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. &Open @@ -2298,7 +2339,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. &Save @@ -2310,7 +2351,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. Sa&ve as... @@ -2322,7 +2363,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. &Quit @@ -2340,7 +2381,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. &Show help texts @@ -2358,7 +2399,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. &Spellcheck @@ -2430,7 +2471,7 @@ - ../../../../../../../.designer/backup../../../../../../../.designer/backup + .. S&ettings @@ -2569,9 +2610,6 @@ Dupl&icate - - Ctrl+D - @@ -2621,18 +2659,178 @@ F2 + + + &Level 1 (setext) + + + Ctrl+Alt+1 + + + + + Level &2 + + + Ctrl+Alt+2 + + + + + Level &1 (atx) + + + Ctrl+1 + + + + + L&evel 2 + + + Ctrl+2 + + + + + Level &3 + + + Ctrl+3 + + + + + Level &4 + + + Ctrl+4 + + + + + Level &5 + + + Ctrl+5 + + + + + Level &6 + + + Ctrl+6 + + + + + + .. + + + &Bold + + + Ctrl+B + + + + + + .. + + + &Italic + + + Ctrl+I + + + + + + .. + + + &Strike + + + + + &Verbatim + + + + + Su&perscript + + + Ctrl++ + + + + + Subsc&ript + + + Ctrl+- + + + + + Co&mment block + + + Ctrl+Shift+C + + + + + + .. + + + Clear &formats + + + Ctrl+0 + + + + + &Comment line(s) + + + Ctrl+C + + + + + &Ordered list + + + + + + .. + + + &Unordered list + + + + + B&lockquote + + - textEditView + MDEditCompleter QTextEdit -
manuskript.ui.views.textEditView.h
+
manuskript.ui.views.MDEditCompleter.h
- - MDEditCompleter - QTextEdit -
manuskript.ui.views.MDEditCompleter.h
-
lineEditView QLineEdit From f3156f5bbdf86130c2a1f7eb7dd9d591d43b67b9 Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Thu, 30 Nov 2017 13:12:55 +0100 Subject: [PATCH 2/3] Adds formatting support to MDEditView --- manuskript/mainWindow.py | 78 ++++++++++++++++++++++++++++--- manuskript/ui/mainWindow.py | 10 ++-- manuskript/ui/mainWindow.ui | 6 +-- manuskript/ui/views/MDEditView.py | 25 +++++----- 4 files changed, 94 insertions(+), 25 deletions(-) diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 8fe626af..be771d09 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -28,6 +28,7 @@ from manuskript.ui.mainWindow import Ui_MainWindow from manuskript.ui.tools.frequencyAnalyzer import frequencyAnalyzer from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate from manuskript.ui.views.plotDelegate import plotDelegate +from manuskript.ui.views.MDEditView import MDEditView # Spellcheck support from manuskript.ui.views.textEditView import textEditView @@ -57,6 +58,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Var self.currentProject = None self._lastFocus = None + self._lastMDEditView = None self._defaultCursorFlashTime = 1000 # Overriden at startup with system # value. In manuskript.main. @@ -113,19 +115,43 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.actSaveAs.triggered.connect(self.welcome.saveAsFile) self.actImport.triggered.connect(self.doImport) self.actCompile.triggered.connect(self.doCompile) - self.actLabels.triggered.connect(self.settingsLabel) - self.actStatus.triggered.connect(self.settingsStatus) - self.actSettings.triggered.connect(self.settingsWindow) self.actCloseProject.triggered.connect(self.closeProject) self.actQuit.triggered.connect(self.close) - # Main menu:: Documents + # Main menu:: Edit self.actCopy.triggered.connect(self.documentsCopy) self.actCut.triggered.connect(self.documentsCut) self.actPaste.triggered.connect(self.documentsPaste) self.actRename.triggered.connect(self.documentsRename) self.actDuplicate.triggered.connect(self.documentsDuplicate) self.actDelete.triggered.connect(self.documentsDelete) + self.actLabels.triggered.connect(self.settingsLabel) + self.actStatus.triggered.connect(self.settingsStatus) + self.actSettings.triggered.connect(self.settingsWindow) + + # Main menu:: Edit:: Format + self.actHeaderSetextL1.triggered.connect(self.formatSetext1) + self.actHeaderSetextL2.triggered.connect(self.formatSetext2) + self.actHeaderAtxL1.triggered.connect(self.formatAtx1) + self.actHeaderAtxL2.triggered.connect(self.formatAtx2) + self.actHeaderAtxL3.triggered.connect(self.formatAtx3) + self.actHeaderAtxL4.triggered.connect(self.formatAtx4) + self.actHeaderAtxL5.triggered.connect(self.formatAtx5) + self.actHeaderAtxL6.triggered.connect(self.formatAtx6) + self.actFormatBold.triggered.connect(self.formatBold) + self.actFormatItalic.triggered.connect(self.formatItalic) + self.actFormatStrike.triggered.connect(self.formatStrike) + self.actFormatVerbatim.triggered.connect(self.formatVerbatim) + self.actFormatSuperscript.triggered.connect(self.formatSuperscript) + self.actFormatSubscript.triggered.connect(self.formatSubscript) + self.actFormatCommentLines.triggered.connect(self.formatCommentLines) + self.actFormatList.triggered.connect(self.formatList) + self.actFormatOrderedList.triggered.connect(self.formatOrderedList) + self.actFormatBlockquote.triggered.connect(self.formatBlockquote) + self.actFormatCommentBlock.triggered.connect(self.formatCommentBlock) + self.actFormatClear.triggered.connect(self.formatClear) + + # Main menu:: Organize self.actMoveUp.triggered.connect(self.documentsMoveUp) self.actMoveDown.triggered.connect(self.documentsMoveDown) self.actSplitDialog.triggered.connect(self.documentsSplitDialog) @@ -225,6 +251,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): We get notified by qApp when focus changes, from old to new widget. """ + # If new is a MDEditView, we keep it in memory + if issubclass(type(new), MDEditView): + self._lastMDEditView = new + else: + self._lastMDEditView = None + # Determine which view had focus last, to send the keyboard shortcuts # to the right place @@ -443,12 +475,14 @@ class MainWindow(QMainWindow, Ui_MainWindow): def openIndexes(self, indexes, newTab=True): self.mainEditor.openIndexes(indexes, newTab=True) - # Menu Documents ############################################################# + # Menu ############################################################# - # Functions called by the menu Documents + # Functions called by the menus # self._lastFocus is the last editor that had focus (either treeView or # mainEditor). So we just pass along the signal. + # Edit + def documentsCopy(self): "Copy selected item(s)." if self._lastFocus: self._lastFocus.copy() @@ -467,6 +501,38 @@ class MainWindow(QMainWindow, Ui_MainWindow): def documentsDelete(self): "Delete selected item(s)." if self._lastFocus: self._lastFocus.delete() + + # Formats + def callLastMDEditView(self, functionName, param=[]): + """ + If last focused widget was MDEditView, call the given function. + """ + if self._lastMDEditView: + function = getattr(self._lastMDEditView, functionName) + function(*param) + def formatSetext1(self): self.callLastMDEditView("titleSetext", [1]) + def formatSetext2(self): self.callLastMDEditView("titleSetext", [2]) + def formatAtx1(self): self.callLastMDEditView("titleATX", [1]) + def formatAtx2(self): self.callLastMDEditView("titleATX", [2]) + def formatAtx3(self): self.callLastMDEditView("titleATX", [3]) + def formatAtx4(self): self.callLastMDEditView("titleATX", [4]) + def formatAtx5(self): self.callLastMDEditView("titleATX", [5]) + def formatAtx6(self): self.callLastMDEditView("titleATX", [6]) + def formatBold(self): self.callLastMDEditView("bold") + def formatItalic(self): self.callLastMDEditView("italic") + def formatStrike(self): self.callLastMDEditView("strike") + def formatVerbatim(self): self.callLastMDEditView("verbatim") + def formatSuperscript(self): self.callLastMDEditView("superscript") + def formatSubscript(self): self.callLastMDEditView("subscript") + def formatCommentLines(self): self.callLastMDEditView("commentLine") + def formatList(self): self.callLastMDEditView("unorderedList") + def formatOrderedList(self): self.callLastMDEditView("orderedList") + def formatBlockquote(self): self.callLastMDEditView("blockquote") + def formatCommentBlock(self): self.callLastMDEditView("comment") + def formatClear(self): self.callLastMDEditView("clearFormat") + + # Organize + def documentsMoveUp(self): "Move up selected item(s)." if self._lastFocus: self._lastFocus.moveUp() diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 30df4f4c..b7514909 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -1262,8 +1262,8 @@ class Ui_MainWindow(object): self.actFormatClear.setObjectName("actFormatClear") self.actFormatCommentLines = QtWidgets.QAction(MainWindow) self.actFormatCommentLines.setObjectName("actFormatCommentLines") - self.actFormatUnorderedList = QtWidgets.QAction(MainWindow) - self.actFormatUnorderedList.setObjectName("actFormatUnorderedList") + self.actFormatOrderedList = QtWidgets.QAction(MainWindow) + self.actFormatOrderedList.setObjectName("actFormatOrderedList") self.actFormatList = QtWidgets.QAction(MainWindow) icon = QtGui.QIcon.fromTheme("view-list") self.actFormatList.setIcon(icon) @@ -1304,7 +1304,7 @@ class Ui_MainWindow(object): self.mnuFormat.addAction(self.actFormatCommentLines) self.mnuFormat.addSeparator() self.mnuFormat.addAction(self.actFormatList) - self.mnuFormat.addAction(self.actFormatUnorderedList) + self.mnuFormat.addAction(self.actFormatOrderedList) self.mnuFormat.addAction(self.actFormatBlockquote) self.mnuFormat.addAction(self.actFormatCommentBlock) self.mnuFormat.addSeparator() @@ -1539,8 +1539,8 @@ class Ui_MainWindow(object): self.actFormatClear.setText(_translate("MainWindow", "Clear &formats")) self.actFormatClear.setShortcut(_translate("MainWindow", "Ctrl+0")) self.actFormatCommentLines.setText(_translate("MainWindow", "&Comment line(s)")) - self.actFormatCommentLines.setShortcut(_translate("MainWindow", "Ctrl+C")) - self.actFormatUnorderedList.setText(_translate("MainWindow", "&Ordered list")) + self.actFormatCommentLines.setShortcut(_translate("MainWindow", "Ctrl+D")) + self.actFormatOrderedList.setText(_translate("MainWindow", "&Ordered list")) self.actFormatList.setText(_translate("MainWindow", "&Unordered list")) self.actFormatBlockquote.setText(_translate("MainWindow", "B&lockquote")) diff --git a/manuskript/ui/mainWindow.ui b/manuskript/ui/mainWindow.ui index 0d13a749..b7bd72df 100644 --- a/manuskript/ui/mainWindow.ui +++ b/manuskript/ui/mainWindow.ui @@ -2170,7 +2170,7 @@ - + @@ -2802,10 +2802,10 @@ &Comment line(s)
- Ctrl+C + Ctrl+D
- + &Ordered list diff --git a/manuskript/ui/views/MDEditView.py b/manuskript/ui/views/MDEditView.py index 5b020cf0..40912e22 100644 --- a/manuskript/ui/views/MDEditView.py +++ b/manuskript/ui/views/MDEditView.py @@ -10,6 +10,7 @@ from PyQt5.QtGui import QTextCursor from manuskript.ui.views.textEditView import textEditView from manuskript.ui.highlighters import MarkdownHighlighter from manuskript import settings +from manuskript.ui.highlighters.markdownEnums import MarkdownState as MS # from manuskript.ui.editors.textFormat import textFormat # from manuskript.ui.editors.MDFunctions import MDFormatSelection @@ -79,23 +80,18 @@ class MDEditView(textEditView): self.verticalScrollBar().blockSignals(False) ########################################################################### - # FORMATTING (#FIXME) + # FORMATTING ########################################################################### - def applyFormat(self, _format): - - if self._textFormat == "md": - if _format == "Bold": self.bold() - elif _format == "Italic": self.italic() - elif _format == "Code": self.verbatim() - elif _format == "Clear": self.clearFormat() - def bold(self): self.insertFormattingMarkup("**") def italic(self): self.insertFormattingMarkup("*") def strike(self): self.insertFormattingMarkup("~~") def verbatim(self): self.insertFormattingMarkup("`") def superscript(self): self.insertFormattingMarkup("^") def subscript(self): self.insertFormattingMarkup("~") + def blockquote(self): self.lineFormattingMarkup("> ") + def orderedList(self): self.lineFormattingMarkup(" 1. ") + def unorderedList(self): self.lineFormattingMarkup(" - ") def selectWord(self, cursor): if cursor.selectedText(): @@ -161,6 +157,14 @@ class MDEditView(textEditView): self.selectBlock(cursor) cursor.insertText(text2) + def lineFormattingMarkup(self, markup): + """ + Adds (or remove if present) `markup` at the begining of block. + """ + cursor = self.textCursor() + cursor.movePosition(cursor.StartOfBlock) + cursor.insertText(markup) + def insertFormattingMarkup(self, markup): cursor = self.textCursor() @@ -211,8 +215,7 @@ class MDEditView(textEditView): ("~~(.*?)~~", "\\1", None), # strike ("\^(.*?)\^", "\\1", None), # superscript ("~(.*?)~", "\\1", None), # subscript - ("", "\\1", re.S), # comments - + ("", "\\1", re.S), # comments # LINES OR BLOCKS (r"^#*\s*(.+?)\s*", "\\1", re.M), # ATX From 92e5c351b77d4b1ef0bf73a4165a87c4b5757cde Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Thu, 30 Nov 2017 13:21:40 +0100 Subject: [PATCH 3/3] Adds: smart formatting on keypress --- manuskript/ui/views/MDEditView.py | 146 ++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 16 deletions(-) diff --git a/manuskript/ui/views/MDEditView.py b/manuskript/ui/views/MDEditView.py index 40912e22..d021bf84 100644 --- a/manuskript/ui/views/MDEditView.py +++ b/manuskript/ui/views/MDEditView.py @@ -11,11 +11,13 @@ from manuskript.ui.views.textEditView import textEditView from manuskript.ui.highlighters import MarkdownHighlighter from manuskript import settings from manuskript.ui.highlighters.markdownEnums import MarkdownState as MS -# from manuskript.ui.editors.textFormat import textFormat -# from manuskript.ui.editors.MDFunctions import MDFormatSelection class MDEditView(textEditView): + + blockquoteRegex = QRegExp("^ {0,3}(>\\s*)+") + listRegex = QRegExp("^(\\s*)([+*-]|([0-9a-z])+([.\)]))(\\s+)") + def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="", autoResize=False): textEditView.__init__(self, parent, index, html, spellcheck, @@ -34,19 +36,131 @@ class MDEditView(textEditView): self.verticalScrollBar().rangeChanged.connect( self.scrollBarRangeChanged) - # def focusInEvent(self, event): - # """Finds textFormatter and attach them to that view.""" - # textEditView.focusInEvent(self, event) - # - # p = self.parent() - # while p.parent(): - # p = p.parent() - # - # if self._index: - # for tF in p.findChildren(textFormat, QRegExp(".*"), - # Qt.FindChildrenRecursively): - # tF.updateFromIndex(self._index) - # tF.setTextEdit(self) + ########################################################################### + # KEYPRESS + ########################################################################### + + def keyPressEvent(self, event): + k = event.key() + m = event.modifiers() + cursor = self.textCursor() + + # RETURN + if k == Qt.Key_Return: + if not cursor.hasSelection(): + if m & Qt.ShiftModifier: + # Insert Markdown-style line break + cursor.insertText(" ") + + if m & Qt.ControlModifier: + cursor.insertText("\n") + else: + self.handleCarriageReturn() + else: + textEditView.keyPressEvent(self, event) + + # TAB + elif k == Qt.Key_Tab: + #self.indentText() + # FIXME + textEditView.keyPressEvent(self, event) + elif k == Qt.Key_Backtab: + #self.unindentText() + # FIXME + textEditView.keyPressEvent(self, event) + + else: + textEditView.keyPressEvent(self, event) + + # Thanks to GhostWriter, mainly + def handleCarriageReturn(self): + autoInsertText = ""; + cursor = self.textCursor() + endList = False + moveBack = False + text = cursor.block().text() + + if cursor.positionInBlock() < cursor.block().length() - 1: + autoInsertText = self.getPriorIndentation() + if cursor.positionInBlock() < len(autoInsertText): + autoInsertText = autoInsertText[:cursor.positionInBlock()] + + else: + s = cursor.block().userState() + + if s in [MS.MarkdownStateNumberedList, + MS.MarkdownStateBulletPointList]: + self.listRegex.indexIn(text) + g = self.listRegex.capturedTexts() + # 0 = " a. " or " * " + # 1 = " " " " + # 2 = "a." "*" + # 3 = "a" "" + # 4 = "." "" + # 5 = " " " " + + # If the line of text is an empty list item, end the list. + if len(g[0].strip()) == len(text.strip()): + endList = True + + # Else increment the list number + elif g[3]: # Numbered list + try: # digit + i = int(g[3])+1 + + except: # letter + i = chr(ord(g[3])+1) + + autoInsertText = "{}{}{}{}".format( + g[1], i, g[4], g[5]) + + else: # Bullet list + autoInsertText = g[0] + + if text[-2:] == " ": + autoInsertText = " " * len(autoInsertText) + + elif s == MS.MarkdownStateBlockquote: + self.blockquoteRegex.indexIn(text) + g = self.blockquoteRegex.capturedTexts() + autoInsertText = g[0] + + elif s in [MS.MarkdownStateInGithubCodeFence, + MS.MarkdownStateInPandocCodeFence] and \ + cursor.block().previous().userState() != s: + autoInsertText = "\n" + text + moveBack = True + + else: + autoInsertText = self.getPriorIndentation() + + # Clear the list + if endList: + autoInsertText = self.getPriorIndentation() + cursor.movePosition(QTextCursor.StartOfBlock) + cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) + cursor.insertText(autoInsertText) + autoInsertText = "" + + # Finally, we insert + cursor.insertText("\n" + autoInsertText) + if moveBack: + cursor.movePosition(QTextCursor.PreviousBlock) + self.setTextCursor(cursor) + + self.ensureCursorVisible() + + def getPriorIndentation(self): + text = self.textCursor().block().text() + l = len(text) - len(text.lstrip()) + return text[:l] + + def getPriorMarkdownBlockItemStart(self, itemRegex): + text = self.textCursor().block().text() + if itemRegex.indexIn(text) >= 0: + return text[itemRegex.matchedLength():] + + return "" ########################################################################### # TypeWriterScrolling @@ -159,7 +273,7 @@ class MDEditView(textEditView): def lineFormattingMarkup(self, markup): """ - Adds (or remove if present) `markup` at the begining of block. + Adds `markup` at the begining of block. """ cursor = self.textCursor() cursor.movePosition(cursor.StartOfBlock)