Adds new markdown highlighter and many little tweaks

This commit is contained in:
Olivier Keshavjee 2017-11-27 21:35:32 +01:00
commit c2dcbf56a0
29 changed files with 2248 additions and 296 deletions

View file

@ -5,7 +5,7 @@ from PyQt5.QtWidgets import QPlainTextEdit, QGroupBox, qApp, QVBoxLayout, QCheck
from manuskript.exporter.manuskript.plainText import plainText from manuskript.exporter.manuskript.plainText import plainText
from manuskript.functions import mainWindow from manuskript.functions import mainWindow
from manuskript.ui.editors.MMDHighlighter import MMDHighlighter from manuskript.ui.highlighters import MMDHighlighter
from manuskript.ui.exporters.manuskript.plainTextSettings import exporterSettings from manuskript.ui.exporters.manuskript.plainTextSettings import exporterSettings
@ -72,4 +72,4 @@ class markdownSettings(exporterSettings):
self.settings = exporterSettings.getSettings(self) self.settings = exporterSettings.getSettings(self)
self.settings["Preview"]["MarkdownHighlighter"] = self.chkMarkdownHighlighter.isChecked() self.settings["Preview"]["MarkdownHighlighter"] = self.chkMarkdownHighlighter.isChecked()
return self.settings return self.settings

View file

@ -6,7 +6,7 @@ import re
from random import * from random import *
from PyQt5.QtCore import Qt, QRect, QStandardPaths, QObject, QRegExp, QDir from PyQt5.QtCore import Qt, QRect, QStandardPaths, QObject, QRegExp, QDir
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl, QTimer
from PyQt5.QtGui import QBrush, QIcon, QPainter, QColor, QImage, QPixmap from PyQt5.QtGui import QBrush, QIcon, QPainter, QColor, QImage, QPixmap
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import qApp, QTextEdit from PyQt5.QtWidgets import qApp, QTextEdit
@ -357,7 +357,9 @@ def statusMessage(message, duration=5000):
""" """
Shows a message in MainWindow's status bar. Shows a message in MainWindow's status bar.
""" """
mainWindow().statusBar().show()
mainWindow().statusBar().showMessage(message, duration) mainWindow().statusBar().showMessage(message, duration)
QTimer.singleShot(duration, mainWindow().statusBar().hide)
def openURL(url): def openURL(url):
""" """

View file

@ -492,9 +492,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
It assumes that the datas have been populated in a different way.""" It assumes that the datas have been populated in a different way."""
if loadFromFile and not os.path.exists(project): if loadFromFile and not os.path.exists(project):
print(self.tr("The file {} does not exist. Try again.").format(project)) print(self.tr("The file {} does not exist. Try again.").format(project))
self.statusBar().showMessage( F.statusMessage(
self.tr("The file {} does not exist. Try again.").format(project), self.tr("The file {} does not exist. Try again.").format(project))
5000)
return return
if loadFromFile: if loadFromFile:
@ -712,7 +711,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Giving some feedback # Giving some feedback
print(feedback) print(feedback)
self.statusBar().showMessage(feedback, 5000) F.statusMessage(feedback)
def loadEmptyDatas(self): def loadEmptyDatas(self):
self.mdlFlatData = QStandardItemModel(self) self.mdlFlatData = QStandardItemModel(self)
@ -732,13 +731,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Giving some feedback # Giving some feedback
if not errors: if not errors:
print(self.tr("Project {} loaded.").format(project)) print(self.tr("Project {} loaded.").format(project))
self.statusBar().showMessage( F.statusMessage(
self.tr("Project {} loaded.").format(project), 5000) self.tr("Project {} loaded.").format(project), 5000)
else: else:
print(self.tr("Project {} loaded with some errors:").format(project)) print(self.tr("Project {} loaded with some errors:").format(project))
for e in errors: for e in errors:
print(self.tr(" * {} wasn't found in project file.").format(e)) print(self.tr(" * {} wasn't found in project file.").format(e))
self.statusBar().showMessage( F.statusMessage(
self.tr("Project {} loaded with some errors.").format(project), 5000) self.tr("Project {} loaded with some errors.").format(project), 5000)
############################################################################### ###############################################################################

View file

@ -64,15 +64,15 @@ textEditor = {
"misspelled": "#F00", "misspelled": "#F00",
"lineSpacing": 100, "lineSpacing": 100,
"tabWidth": 20, "tabWidth": 20,
"indent": True, "indent": False,
"spacingAbove": 5, "spacingAbove": 5,
"spacingBelow": 5, "spacingBelow": 5,
"textAlignment": 0, # 0: left, 1: center, 2: right, 3: justify "textAlignment": 0, # 0: left, 1: center, 2: right, 3: justify
"cursorWidth": 1, "cursorWidth": 1,
"cursorNotBlinking": False, "cursorNotBlinking": False,
"maxWidth": 0, "maxWidth": 600,
"marginsLR": 0, "marginsLR": 0,
"marginsTB": 0, "marginsTB": 20,
"backgroundTransparent": False, "backgroundTransparent": False,
} }
@ -185,6 +185,8 @@ def load(string, fromString=False, protocol=None):
#print("Loading:") #print("Loading:")
#pp.pprint(allSettings) #pp.pprint(allSettings)
# FIXME: use dict.update(dict) to update settings in newer versions.
if "viewSettings" in allSettings: if "viewSettings" in allSettings:
global viewSettings global viewSettings
viewSettings = allSettings["viewSettings"] viewSettings = allSettings["viewSettings"]
@ -267,9 +269,9 @@ def load(string, fromString=False, protocol=None):
"textAlignment": 0, # Added in 0.5.0 "textAlignment": 0, # Added in 0.5.0
"cursorWidth": 1, "cursorWidth": 1,
"cursorNotBlinking": False, # Added in 0.6.0 "cursorNotBlinking": False, # Added in 0.6.0
"maxWidth": 0, "maxWidth": 600,
"marginsLR": 0, "marginsLR": 0,
"marginsTB": 0, "marginsTB": 20,
"backgroundTransparent": False, # Added in 0.6.0 "backgroundTransparent": False, # Added in 0.6.0
} }

View file

@ -2,12 +2,13 @@
# --!-- coding: utf8 --!-- # --!-- coding: utf8 --!--
from PyQt5.QtCore import pyqtSignal, QModelIndex from PyQt5.QtCore import pyqtSignal, QModelIndex
from PyQt5.QtGui import QPalette from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QWidget, QFrame, QSpacerItem, QSizePolicy, QVBoxLayout from PyQt5.QtWidgets import QWidget, QFrame, QSpacerItem, QSizePolicy
from PyQt5.QtWidgets import QVBoxLayout, qApp, QStyle
from manuskript import settings from manuskript import settings
from manuskript.functions import AUC, mainWindow from manuskript.functions import AUC, mainWindow
from manuskript.ui.editors.editorWidget_ui import Ui_editorWidget_ui from manuskript.ui.editors.editorWidget_ui import Ui_editorWidget_ui
from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.MDEditView import MDEditView
from manuskript.ui.tools.splitDialog import splitDialog from manuskript.ui.tools.splitDialog import splitDialog
@ -60,10 +61,37 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
self._model = None self._model = None
# Capture textEdit scrollbar, so that we can put it outside the margins.
self.txtEditScrollBar = self.txtRedacText.verticalScrollBar()
self.txtEditScrollBar.setParent(self)
self.stack.currentChanged.connect(self.setScrollBarVisibility)
# def setModel(self, model): # def setModel(self, model):
# self._model = model # self._model = model
# self.setView() # self.setView()
def resizeEvent(self, event):
"""
textEdit's scrollBar has been reparented to self. So we need to
update it's geomtry when self is resized, and put it where we want it
to be.
"""
# Update scrollbar geometry
r = self.geometry()
w = 10 # Cf. style.mainEditorTabSS
r.setWidth(w)
r.moveRight(self.geometry().width())
self.txtEditScrollBar.setGeometry(r)
QWidget.resizeEvent(self, event)
def setScrollBarVisibility(self):
"""
Since the texteEdit scrollBar has been reparented to self, it is not
hidden when stack changes. We have to do it manually.
"""
self.txtEditScrollBar.setVisible(self.stack.currentIndex() == 0)
def setFolderView(self, v): def setFolderView(self, v):
oldV = self.folderView oldV = self.folderView
if v == "cork": if v == "cork":
@ -150,7 +178,7 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
self.updateTabTitle() self.updateTabTitle()
def addTitle(itm): def addTitle(itm):
edt = textEditView(self, html="<h{l}>{t}</h{l}>".format(l=min(itm.level() + 1, 5), t=itm.title()), edt = MDEditView(self, html="<h{l}>{t}</h{l}>".format(l=min(itm.level() + 1, 5), t=itm.title()),
autoResize=True) autoResize=True)
edt.setFrameShape(QFrame.NoFrame) edt.setFrameShape(QFrame.NoFrame)
self.txtEdits.append(edt) self.txtEdits.append(edt)
@ -163,7 +191,7 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
l.addWidget(line) l.addWidget(line)
def addText(itm): def addText(itm):
edt = textEditView(self, edt = MDEditView(self,
index=itm.index(), index=itm.index(),
spellcheck=self.spellcheck, spellcheck=self.spellcheck,
dict=settings.dict, dict=settings.dict,
@ -214,7 +242,12 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
w = QWidget() w = QWidget()
w.setObjectName("editorWidgetFolderText") w.setObjectName("editorWidgetFolderText")
l = QVBoxLayout(w) l = QVBoxLayout(w)
w.setStyleSheet("background: {};".format(settings.textEditor["background"])) opt = settings.textEditor
background = (opt["background"] if not opt["backgroundTransparent"]
else "transparent")
w.setStyleSheet("background: {};".format(background))
self.stack.widget(1).setStyleSheet("background: {}"
.format(background))
# self.scroll.setWidgetResizable(False) # self.scroll.setWidgetResizable(False)
self.txtEdits = [] self.txtEdits = []

View file

@ -2,8 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/editors/editorWidget_ui.ui' # Form implementation generated from reading ui file 'manuskript/ui/editors/editorWidget_ui.ui'
# #
# Created: Fri Apr 8 20:03:08 2016 # Created by: PyQt5 UI code generator 5.5.1
# by: PyQt5 UI code generator 5.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -23,7 +22,7 @@ class Ui_editorWidget_ui(object):
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.text) self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.text)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.txtRedacText = textEditView(self.text) self.txtRedacText = MDEditView(self.text)
self.txtRedacText.setFrameShape(QtWidgets.QFrame.NoFrame) self.txtRedacText.setFrameShape(QtWidgets.QFrame.NoFrame)
self.txtRedacText.setObjectName("txtRedacText") self.txtRedacText.setObjectName("txtRedacText")
self.horizontalLayout_2.addWidget(self.txtRedacText) self.horizontalLayout_2.addWidget(self.txtRedacText)
@ -31,8 +30,8 @@ class Ui_editorWidget_ui(object):
self.folder = QtWidgets.QWidget() self.folder = QtWidgets.QWidget()
self.folder.setObjectName("folder") self.folder.setObjectName("folder")
self.verticalLayout = QtWidgets.QVBoxLayout(self.folder) self.verticalLayout = QtWidgets.QVBoxLayout(self.folder)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.scroll = QtWidgets.QScrollArea(self.folder) self.scroll = QtWidgets.QScrollArea(self.folder)
self.scroll.setAutoFillBackground(True) self.scroll.setAutoFillBackground(True)
@ -75,6 +74,6 @@ class Ui_editorWidget_ui(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
editorWidget_ui.setWindowTitle(_translate("editorWidget_ui", "Form")) editorWidget_ui.setWindowTitle(_translate("editorWidget_ui", "Form"))
from manuskript.ui.views.outlineView import outlineView from manuskript.ui.views.MDEditView import MDEditView
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.corkView import corkView from manuskript.ui.views.corkView import corkView
from manuskript.ui.views.outlineView import outlineView

View file

@ -46,7 +46,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="textEditView" name="txtRedacText"> <widget class="MDEditView" name="txtRedacText">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
@ -147,12 +147,12 @@
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>textEditView</class> <class>MDEditView</class>
<extends>QTextEdit</extends> <extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditView.h</header> <header>manuskript.ui.views.MDEditView.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>outlineView</class> <class>outlineView</class>
<extends>QTreeView</extends> <extends>QTreeView</extends>
<header>manuskript.ui.views.outlineView.h</header> <header>manuskript.ui.views.outlineView.h</header>

View file

@ -13,10 +13,9 @@ from manuskript import settings
from manuskript.enums import Outline from manuskript.enums import Outline
from manuskript.functions import allPaths, drawProgress from manuskript.functions import allPaths, drawProgress
from manuskript.ui.editors.locker import locker from manuskript.ui.editors.locker import locker
from manuskript.ui.editors.textFormat import textFormat
from manuskript.ui.editors.themes import findThemePath, generateTheme, setThemeEditorDatas from manuskript.ui.editors.themes import findThemePath, generateTheme, setThemeEditorDatas
from manuskript.ui.editors.themes import loadThemeDatas from manuskript.ui.editors.themes import loadThemeDatas
from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.MDEditView import MDEditView
try: try:
import enchant import enchant
@ -35,11 +34,11 @@ class fullScreenEditor(QWidget):
self._geometries = {} self._geometries = {}
# Text editor # Text editor
self.editor = textEditView(self, self.editor = MDEditView(self,
index=index, index=index,
spellcheck=settings.spellcheck, spellcheck=settings.spellcheck,
highlighting=True, highlighting=True,
dict=settings.dict) dict=settings.dict)
self.editor.setFrameStyle(QFrame.NoFrame) self.editor.setFrameStyle(QFrame.NoFrame)
self.editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
@ -65,11 +64,7 @@ class fullScreenEditor(QWidget):
self.topPanel.layout().addStretch(1) self.topPanel.layout().addStretch(1)
# Formatting # Close
self.textFormat = textFormat(self)
self.topPanel.layout().addWidget(self.textFormat)
self.topPanel.layout().addStretch(1)
self.btnClose = QPushButton(self) self.btnClose = QPushButton(self)
self.btnClose.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCloseButton)) self.btnClose.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCloseButton))
self.btnClose.clicked.connect(self.close) self.btnClose.clicked.connect(self.close)

View file

@ -270,9 +270,6 @@ class mainEditor(QWidget, Ui_mainEditor):
else: else:
visible = True visible = True
# Hides / show textFormat
self.textFormat.updateFromIndex(index)
self.btnRedacFolderText.setVisible(visible) self.btnRedacFolderText.setVisible(visible)
self.btnRedacFolderCork.setVisible(visible) self.btnRedacFolderCork.setVisible(visible)
self.btnRedacFolderOutline.setVisible(visible) self.btnRedacFolderOutline.setVisible(visible)

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/editors/mainEditor_ui.ui' # Form implementation generated from reading ui file 'manuskript/ui/editors/mainEditor_ui.ui'
# #
# Created by: PyQt5 UI code generator 5.9 # Created by: PyQt5 UI code generator 5.5.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -65,17 +65,6 @@ class Ui_mainEditor(object):
self.horizontalLayout_19.addWidget(self.sldCorkSizeFactor) self.horizontalLayout_19.addWidget(self.sldCorkSizeFactor)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_19.addItem(spacerItem) self.horizontalLayout_19.addItem(spacerItem)
self.textFormat = textFormat(mainEditor)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textFormat.sizePolicy().hasHeightForWidth())
self.textFormat.setSizePolicy(sizePolicy)
self.textFormat.setMinimumSize(QtCore.QSize(20, 20))
self.textFormat.setObjectName("textFormat")
self.horizontalLayout_19.addWidget(self.textFormat)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_19.addItem(spacerItem1)
self.lblRedacWC = QtWidgets.QLabel(mainEditor) self.lblRedacWC = QtWidgets.QLabel(mainEditor)
self.lblRedacWC.setMinimumSize(QtCore.QSize(10, 0)) self.lblRedacWC.setMinimumSize(QtCore.QSize(10, 0))
self.lblRedacWC.setText("") self.lblRedacWC.setText("")
@ -110,4 +99,3 @@ class Ui_mainEditor(object):
self.btnRedacFullscreen.setShortcut(_translate("mainEditor", "F11")) self.btnRedacFullscreen.setShortcut(_translate("mainEditor", "F11"))
from manuskript.ui.editors.tabSplitter import tabSplitter from manuskript.ui.editors.tabSplitter import tabSplitter
from manuskript.ui.editors.textFormat import textFormat

View file

@ -51,8 +51,7 @@
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="go-up"> <iconset theme="go-up">
<normaloff/> <normaloff>.</normaloff>.</iconset>
</iconset>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Alt+Up</string> <string>Alt+Up</string>
@ -141,35 +140,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="textFormat" name="textFormat" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
<property name="orientation"> <property name="orientation">
@ -237,12 +207,6 @@
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget>
<class>textFormat</class>
<extends>QWidget</extends>
<header>manuskript.ui.editors.textFormat.h</header>
<container>1</container>
</customwidget>
<customwidget> <customwidget>
<class>tabSplitter</class> <class>tabSplitter</class>
<extends>QWidget</extends> <extends>QWidget</extends>

View file

@ -10,7 +10,7 @@ from PyQt5.QtGui import QPixmap, QPainter, QColor, QBrush, QImage, QTextBlockFor
from PyQt5.QtWidgets import qApp, QFrame from PyQt5.QtWidgets import qApp, QFrame
from manuskript.functions import allPaths, appPath, findBackground, findFirstFile from manuskript.functions import allPaths, appPath, findBackground, findFirstFile
from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.MDEditView import MDEditView
_thumbCache = {} _thumbCache = {}
@ -89,13 +89,13 @@ def themeTextRect(themeDatas, screenRect):
def createThemePreview(theme, screenRect, size=QSize(200, 120)): def createThemePreview(theme, screenRect, size=QSize(200, 120)):
""" """
Generates a QPixmap preview for given theme. Generates a QPixmap preview for given theme.
Theme can be either a string containing the filename of the ini Theme can be either a string containing the filename of the ini
file with the theme settings, or it can be a dict with the settings. file with the theme settings, or it can be a dict with the settings.
If theme is a filename, the result is cached. If theme is a filename, the result is cached.
""" """
# Checking whether theme is a string or dict # Checking whether theme is a string or dict
if type(theme) == str and os.path.exists(theme): if type(theme) == str and os.path.exists(theme):
# Theme is the path to an ini file # Theme is the path to an ini file
@ -126,7 +126,7 @@ def createThemePreview(theme, screenRect, size=QSize(200, 120)):
painter.setPen(Qt.white) painter.setPen(Qt.white)
painter.drawRect(QRect(w, h, w * 4, h * 5)) painter.drawRect(QRect(w, h, w * 4, h * 5))
painter.end() painter.end()
# If theme is a themefile, we keep it in cache # If theme is a themefile, we keep it in cache
if fromFile: if fromFile:
_thumbCache[theme] = [themeDatas, px] _thumbCache[theme] = [themeDatas, px]
@ -265,11 +265,12 @@ def setThemeEditorDatas(editor, themeDatas, pixmap, screenRect):
) )
editor._fromTheme = True editor._fromTheme = True
editor._themeData = themeDatas
editor.highlighter.updateColorScheme()
def addThemePreviewText(pixmap, themeDatas, screenRect): def addThemePreviewText(pixmap, themeDatas, screenRect):
# Text # Text
previewText = textEditView(highlighting=True) previewText = MDEditView(highlighting=True)
previewText.setFrameStyle(QFrame.NoFrame) previewText.setFrameStyle(QFrame.NoFrame)
previewText.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) previewText.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
previewText.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) previewText.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

View file

@ -5,10 +5,10 @@ import re
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextCharFormat, QFont, QTextCursor, QFontMetrics from PyQt5.QtGui import QTextCharFormat, QFont, QTextCursor, QFontMetrics
from manuskript.ui.editors.basicHighlighter import basicHighlighter from manuskript.ui.highlighters import BasicHighlighter
class MMDHighlighter(basicHighlighter): class MMDHighlighter(BasicHighlighter):
MARKDOWN_REGEX = { MARKDOWN_REGEX = {
'Bold': '(\*\*)(.+?)(\*\*)', 'Bold': '(\*\*)(.+?)(\*\*)',
@ -27,7 +27,7 @@ class MMDHighlighter(basicHighlighter):
} }
def __init__(self, editor, style="Default"): def __init__(self, editor, style="Default"):
basicHighlighter.__init__(self, editor) BasicHighlighter.__init__(self, editor)
self.editor = editor self.editor = editor
@ -35,13 +35,6 @@ class MMDHighlighter(basicHighlighter):
for key in self.MARKDOWN_REGEX: for key in self.MARKDOWN_REGEX:
self.rules[key] = re.compile(self.MARKDOWN_REGEX[key]) self.rules[key] = re.compile(self.MARKDOWN_REGEX[key])
def highlightBlock(self, text):
basicHighlighter.highlightBlockBefore(self, text)
self.doHighlightBlock(text)
basicHighlighter.highlightBlockAfter(self, text)
def doHighlightBlock(self, text): def doHighlightBlock(self, text):
""" """
A quick-n-dirty very basic highlighter, that fails in most non-trivial cases. And is ugly. A quick-n-dirty very basic highlighter, that fails in most non-trivial cases. And is ugly.

View file

@ -0,0 +1,12 @@
#!/usr/bin/python
# -*- coding: utf8 -*-
from manuskript.ui.highlighters.basicHighlighter import BasicHighlighter
from manuskript.ui.highlighters.MMDHighlighter import MMDHighlighter
# Markdown highlighter
from manuskript.ui.highlighters.markdownEnums import MarkdownState
from manuskript.ui.highlighters.markdownEnums import MarkdownTokenType
from manuskript.ui.highlighters.markdownEnums import BlockquoteStyle
from manuskript.ui.highlighters.markdownTokenizer import MarkdownTokenizer
from manuskript.ui.highlighters.markdownHighlighter import MarkdownHighlighter

View file

@ -4,12 +4,16 @@
import re import re
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QBrush, QTextCursor, QColor, QFont, QSyntaxHighlighter, QTextBlockFormat, QTextCharFormat from PyQt5.QtGui import QBrush, QTextCursor, QColor, QFont, QSyntaxHighlighter
from PyQt5.QtGui import QTextBlockFormat, QTextCharFormat
import manuskript.models.references as Ref import manuskript.models.references as Ref
import manuskript.ui.style as S
from manuskript import settings
from manuskript import functions as F
class basicHighlighter(QSyntaxHighlighter): class BasicHighlighter(QSyntaxHighlighter):
def __init__(self, editor): def __init__(self, editor):
QSyntaxHighlighter.__init__(self, editor.document()) QSyntaxHighlighter.__init__(self, editor.document())
@ -17,6 +21,11 @@ class basicHighlighter(QSyntaxHighlighter):
self._misspelledColor = Qt.red self._misspelledColor = Qt.red
self._defaultBlockFormat = QTextBlockFormat() self._defaultBlockFormat = QTextBlockFormat()
self._defaultCharFormat = QTextCharFormat() self._defaultCharFormat = QTextCharFormat()
self.defaultTextColor = QColor(S.text)
self.backgroundColor = QColor(S.base)
self.markupColor = QColor(S.textLight)
self.linkColor = QColor(S.link)
self.spellingErrorColor = QColor(Qt.red)
def setDefaultBlockFormat(self, bf): def setDefaultBlockFormat(self, bf):
self._defaultBlockFormat = bf self._defaultBlockFormat = bf
@ -29,17 +38,63 @@ class basicHighlighter(QSyntaxHighlighter):
def setMisspelledColor(self, color): def setMisspelledColor(self, color):
self._misspelledColor = color self._misspelledColor = color
def updateColorScheme(self, rehighlight=True):
"""
Generates a base set of colors that will take account of user
preferences, and use system style.
"""
# Reading user settings
opt = settings.textEditor
if not self.editor._fromTheme or not self.editor._themeData:
self.defaultTextColor = QColor(opt["fontColor"])
self.backgroundColor = (QColor(opt["background"])
if not opt["backgroundTransparent"]
else QColor(S.window))
self.markupColor = F.mixColors(self.defaultTextColor,
self.backgroundColor,
.3)
self.linkColor = QColor(S.link)
self.spellingErrorColor = QColor(opt["misspelled"])
self._defaultCharFormat.setForeground(QBrush(self.defaultTextColor))
# FullscreenEditor probably
else:
opt = self.editor._themeData
self.defaultTextColor = QColor(opt["Text/Color"])
self.backgroundColor = F.mixColors(
QColor(opt["Foreground/Color"]),
QColor(opt["Background/Color"]),
int(opt["Foreground/Opacity"])/100.)
self.markupColor = F.mixColors(self.defaultTextColor,
self.backgroundColor,
.3)
self.linkColor = QColor(S.link)
self.spellingErrorColor = QColor(opt["Text/Misspelled"])
if rehighlight:
self.rehighlight()
def highlightBlock(self, text): def highlightBlock(self, text):
"""Apply syntax highlighting to the given block of text. """Apply syntax highlighting to the given block of text.
""" """
self.highlightBlockBefore(text) self.highlightBlockBefore(text)
self.doHighlightBlock(text)
self.highlightBlockAfter(text) self.highlightBlockAfter(text)
def doHighlightBlock(self, text):
"""
Virtual funtion to subclass.
"""
pass
def highlightBlockBefore(self, text): def highlightBlockBefore(self, text):
"""Highlighting to do before anything else. """Highlighting to do before anything else.
When subclassing basicHighlighter, you must call highlightBlockBefore When subclassing BasicHighlighter, you must call highlightBlockBefore
before you do any custom highlighting. before you do any custom highlighting. Or implement doHighlightBlock.
""" """
#print(">", self.currentBlock().document().availableUndoSteps()) #print(">", self.currentBlock().document().availableUndoSteps())
@ -56,8 +111,8 @@ class basicHighlighter(QSyntaxHighlighter):
def highlightBlockAfter(self, text): def highlightBlockAfter(self, text):
"""Highlighting to do after everything else. """Highlighting to do after everything else.
When subclassing basicHighlighter, you must call highlightBlockAfter When subclassing BasicHighlighter, you must call highlightBlockAfter
after your custom highlighting. after your custom highlighting. Or implement doHighlightBlock.
""" """
# References # References
@ -91,13 +146,16 @@ class basicHighlighter(QSyntaxHighlighter):
textedText = text + " " textedText = text + " "
# Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
WORDS = '(?iu)([\w\']+)[^\'\w]' # (?iu) means case insensitive and unicode WORDS = r'(?iu)([\w\']+)[^\'\w]'
# (?iu) means case insensitive and unicode
if hasattr(self.editor, "spellcheck") and self.editor.spellcheck: if hasattr(self.editor, "spellcheck") and self.editor.spellcheck:
for word_object in re.finditer(WORDS, textedText): for word_object in re.finditer(WORDS, textedText):
if self.editor._dict and not self.editor._dict.check(word_object.group(1)): if (self.editor._dict
and not self.editor._dict.check(word_object.group(1))):
format = self.format(word_object.start(1)) format = self.format(word_object.start(1))
format.setUnderlineColor(self._misspelledColor) format.setUnderlineColor(self._misspelledColor)
# SpellCheckUnderline fails with some fonts # SpellCheckUnderline fails with some fonts
format.setUnderlineStyle(QTextCharFormat.WaveUnderline) format.setUnderlineStyle(QTextCharFormat.WaveUnderline)
self.setFormat(word_object.start(1), self.setFormat(word_object.start(1),
word_object.end(1) - word_object.start(1), format) word_object.end(1) - word_object.start(1),
format)

View file

@ -0,0 +1,100 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#==============================================================================
# MARKDOWN STATES
#==============================================================================
class MarkdownState:
MarkdownStateUnknown = -1
MarkdownStateParagraphBreak = 0
MarkdownStateListLineBreak = 1
MarkdownStateParagraph = 2
MarkdownStateAtxHeading1 = 3
MarkdownStateAtxHeading2 = 4
MarkdownStateAtxHeading3 = 5
MarkdownStateAtxHeading4 = 6
MarkdownStateAtxHeading5 = 7
MarkdownStateAtxHeading6 = 8
MarkdownStateBlockquote = 9
MarkdownStateCodeBlock = 10
MarkdownStateInGithubCodeFence = 11
MarkdownStateInPandocCodeFence = 12
MarkdownStateCodeFenceEnd = 13
MarkdownStateComment = 14
MarkdownStateHorizontalRule = 15
MarkdownStateNumberedList = 16
MarkdownStateBulletPointList = 17
MarkdownStateSetextHeading1Line1 = 18
MarkdownStateSetextHeading1Line2 = 19
MarkdownStateSetextHeading2Line1 = 20
MarkdownStateSetextHeading2Line2 = 21
MarkdownStatePipeTableHeader = 22
MarkdownStatePipeTableDivider = 23
MarkdownStatePipeTableRow = 24
#==============================================================================
# MARKDOWN TOKEN TYPE
#==============================================================================
class MarkdownTokenType:
TokenUnknown = -1
# Titles
TokenAtxHeading1 = 0
TokenAtxHeading2 = 1
TokenAtxHeading3 = 2
TokenAtxHeading4 = 3
TokenAtxHeading5 = 4
TokenAtxHeading6 = 5
TokenSetextHeading1Line1 = 6
TokenSetextHeading1Line2 = 7
TokenSetextHeading2Line1 = 8
TokenSetextHeading2Line2 = 9
TokenEmphasis = 10
TokenStrong = 11
TokenStrikethrough = 12
TokenVerbatim = 13
TokenHtmlTag = 14
TokenHtmlEntity = 15
TokenAutomaticLink = 16
TokenInlineLink = 17
TokenReferenceLink = 18
TokenReferenceDefinition = 19
TokenImage = 20
TokenHtmlComment = 21
TokenNumberedList = 22
TokenBulletPointList = 23
TokenHorizontalRule = 24
TokenLineBreak = 25
TokenBlockquote = 26
TokenCodeBlock = 27
TokenGithubCodeFence = 28
TokenPandocCodeFence = 29
TokenCodeFenceEnd = 30
TokenMention = 31
TokenTableHeader = 32
TokenTableDivider = 33
TokenTablePipe = 34
TokenSuperScript = 35
TokenSubScript = 36
# CriticMarkup
TokenCMAddition = 37 # {++ ++}
TokenCMDeletion = 38 # {-- --}
TokenCMSubstitution = 39 #{~~ ~> ~~}
TokenCMComment = 40 # {>> <<}
TokenCMHighlight = 41 # {== ==}{>> <<}
TokenLast = 42
TITLES = [TokenAtxHeading1, TokenAtxHeading2, TokenAtxHeading3,
TokenAtxHeading4, TokenAtxHeading5, TokenAtxHeading6,
TokenSetextHeading1Line1, TokenSetextHeading1Line2,
TokenSetextHeading2Line1, TokenSetextHeading2Line2]
class BlockquoteStyle:
BlockquoteStylePlain = 0
BlockquoteStyleItalic = 1
BlockquoteStyleFancy = 2

View file

@ -0,0 +1,665 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
A QSyntaxHighlighter for markdown, using tokenizer. More accurate than simple
regexp, but not yet perfect.
"""
import re
from PyQt5.QtCore import Qt, pyqtSignal, qWarning, QRegExp
from PyQt5.QtGui import (QSyntaxHighlighter, QTextBlock, QColor, QFont,
QTextCharFormat, QBrush, QPalette)
from PyQt5.QtWidgets import qApp, QStyle
from manuskript.ui.highlighters import BasicHighlighter
from manuskript.ui.highlighters import MarkdownTokenizer
from manuskript.ui.highlighters import MarkdownState as MS
from manuskript.ui.highlighters import MarkdownTokenType as MTT
from manuskript.ui.highlighters import BlockquoteStyle as BS
from manuskript.ui import style as S
from manuskript import settings
from manuskript import functions as F
# Un longue ligne. Un longue ligne. Un longue ligne. Un longue ligne.asdasdasda
GW_FADE_ALPHA = 140
# Highlighter based on GhostWriter (http://wereturtle.github.io/ghostwriter/).
# GPLV3+.
#FIXME: Setext heading don't work anymore
class MarkdownHighlighter(BasicHighlighter):
highlightBlockAtPosition = pyqtSignal(int)
headingFound = pyqtSignal(int, str, QTextBlock)
headingRemoved = pyqtSignal(int)
def __init__(self, editor):
BasicHighlighter.__init__(self, editor)
#default values
self.editor = editor
self.tokenizer = MarkdownTokenizer()
self.spellCheckEnabled = False
#self.typingPaused = True
self.inBlockquote = False
self.blockquoteStyle = BS.BlockquoteStyleFancy
# Settings
self.useUndlerlineForEmphasis = False
self.highlightLineBreaks = True
self.highlightBlockAtPosition.connect(self.onHighlightBlockAtPosition,
Qt.QueuedConnection)
self.theme = self.defaultTheme()
self.setupHeadingFontSize(True)
self.highlightedWords = []
self.highlightedTags = []
self.searchExpression = ""
self.searchExpressionRegExp = False
self.searchExpressionCase = False
#f = self.document().defaultFont()
#f.setFamily("monospace")
#self.document().setDefaultFont(f)
def doHighlightBlock(self, text):
"""
Note: Never set the QTextBlockFormat for a QTextBlock from within
the highlighter. Depending on how the block format is modified,
a recursive call to the highlighter may be triggered, which will
cause the application to crash.
Likewise, don't try to set the QTextBlockFormat outside the highlighter
(i.e., from within the text editor). While the application will not
crash, the format change will be added to the undo stack. Attempting
to undo from that point on will cause the undo stack to be virtually
frozen, since undoing the format operation causes the text to be
considered changed, thus triggering the slot that changes the text
formatting to be triggered yet again.
"""
lastState = self.currentBlockState()
self.setFormat(0, len(text), self._defaultCharFormat)
if self.tokenizer != None:
self.tokenizer.clear()
block = self.currentBlock()
nextState = MS.MarkdownStateUnknown
previousState = self.previousBlockState()
if block.next().isValid():
nextState = block.next().userState()
self.tokenizer.tokenize(text, lastState, previousState, nextState)
self.setCurrentBlockState(self.tokenizer.getState())
self.inBlockquote = self.tokenizer.getState() == MS.MarkdownStateBlockquote
# STATE FORMATTING
# FIXME: generic
if self.currentBlockState() in [
MS.MarkdownStatePipeTableHeader,
MS.MarkdownStatePipeTableDivider,
MS.MarkdownStatePipeTableRow]:
fmt = QTextCharFormat()
f = fmt.font()
f.setFamily("Monospace")
fmt.setFont(f)
self.setFormat(0, len(text), fmt)
# Monospace the blank chars
i = 0
while i <= len(text)-1 and text[i] in [" ", "\t"]:
fmt = self.format(i)
fmt.setFontFamily("Monospace")
self.setFormat(i, 1, fmt)
i += 1
#if self.currentBlockState() == MS.MarkdownStateBlockquote:
#fmt = QTextCharFormat(self._defaultCharFormat)
#fmt.setForeground(Qt.lightGray)
#self.setFormat(0, len(text), fmt)
tokens = self.tokenizer.getTokens()
for token in tokens:
if token.type == MTT.TokenUnknown:
qWarning("Highlighter found unknown token type in text block.")
continue
if token.type in [
MTT.TokenAtxHeading1,
MTT.TokenAtxHeading2,
MTT.TokenAtxHeading3,
MTT.TokenAtxHeading4,
MTT.TokenAtxHeading5,
MTT.TokenAtxHeading6,
MTT.TokenSetextHeading1Line1,
MTT.TokenSetextHeading2Line1,
]:
self.storeHeadingData(token, text)
self.applyFormattingForToken(token, text)
if self.tokenizer.backtrackRequested():
previous = self.currentBlock().previous()
self.highlightBlockAtPosition.emit(previous.position())
if self.spellCheckEnabled:
self.spellCheck(text)
# If the block has transitioned from previously being a heading to now
# being a non-heading, signal that the position in the document no
# longer contains a heading.
if self.isHeadingBlockState(lastState) and \
not self.isHeadingBlockState(self.currentBlockState()):
self.headingRemoved.emit(self.currentBlock().position())
###########################################################################
# COLORS & FORMATTING
###########################################################################
def updateColorScheme(self, rehighlight=True):
BasicHighlighter.updateColorScheme(self, rehighlight)
self.theme = self.defaultTheme()
self.setEnableLargeHeadingSizes(True)
def defaultTheme(self):
# Base Colors
background = self.backgroundColor
text = self.defaultTextColor
highlightedText = QColor(S.highlightedText)
highlightedTextDark = QColor(S.highlightedTextDark)
highlightedTextLight = QColor(S.highlightedTextLight)
highlight = QColor(S.highlight)
link = self.linkColor
linkVisited = QColor(S.linkVisited)
# titleColor = highlight
titleColor = QColor(S.highlightedTextDark)
# FullscreenEditor probably
if self.editor._fromTheme and self.editor._themeData:
text = QColor(self.editor._themeData["Text/Color"])
background = QColor(self.editor._themeData["Background/Color"])
titleColor = text
# Compositions
light = F.mixColors(text, background, .75)
markup = F.mixColors(text, background, .5)
veryLight = F.mixColors(text, background, .25)
listToken = F.mixColors(highlight, background, .4)
titleMarkupColor = F.mixColors(titleColor, background, .3)
theme = {
"markup": markup}
#Exemple:
#"color": Qt.red,
#"deltaSize": 10,
#"background": Qt.yellow,
#"monospace": True,
#"bold": True,
#"italic": True,
#"underline": True,
#"overline": True,
#"strike": True,
#"formatMarkup": True,
#"markupBold": True,
#"markupColor": Qt.blue,
#"markupBackground": Qt.green,
#"markupMonospace": True,
#"super":True,
#"sub":True
for i in MTT.TITLES:
theme[i] = {
"formatMarkup":True,
"bold": True,
# "monospace": True,
"markupColor": titleMarkupColor
}
theme[MTT.TokenAtxHeading1]["color"] = titleColor
theme[MTT.TokenAtxHeading2]["color"] = F.mixColors(titleColor,
background, .9)
theme[MTT.TokenAtxHeading3]["color"] = F.mixColors(titleColor,
background, .8)
theme[MTT.TokenAtxHeading4]["color"] = F.mixColors(titleColor,
background, .7)
theme[MTT.TokenAtxHeading5]["color"] = F.mixColors(titleColor,
background, .6)
theme[MTT.TokenAtxHeading6]["color"] = F.mixColors(titleColor,
background, .5)
theme[MTT.TokenSetextHeading1Line1]["color"] = titleColor
theme[MTT.TokenSetextHeading2Line1]["color"] = F.mixColors(titleColor,
background,
.9)
for i in [MTT.TokenSetextHeading1Line1, MTT.TokenSetextHeading2Line1]:
theme[i]["monospace"] = True
for i in [MTT.TokenSetextHeading1Line2, MTT.TokenSetextHeading2Line2]:
theme[i] = {
"color": titleMarkupColor,
"monospace":True}
# Beautifiers
theme[MTT.TokenEmphasis] = {
"italic":True}
theme[MTT.TokenStrong] = {
"bold":True}
theme[MTT.TokenStrikethrough] = {
"strike":True}
theme[MTT.TokenVerbatim] = {
"monospace":True,
"background": veryLight,
"formatMarkup": True,
"markupColor": markup,
"deltaSize": -1}
theme[MTT.TokenSuperScript] = {
"super":True,
"formatMarkup":True}
theme[MTT.TokenSubScript] = {
"sub":True,
"formatMarkup":True}
theme[MTT.TokenHtmlTag] = {
"color": linkVisited}
theme[MTT.TokenHtmlEntity] = { # &nbsp;
"color": linkVisited}
theme[MTT.TokenAutomaticLink] = {
"color": link}
theme[MTT.TokenInlineLink] = {
"color": link}
theme[MTT.TokenReferenceLink] = {
"color": link}
theme[MTT.TokenReferenceDefinition] = {
"color": link}
theme[MTT.TokenImage] = {
"color": highlightedTextDark}
theme[MTT.TokenHtmlComment] = {
"color": markup}
theme[MTT.TokenNumberedList] = {
"markupColor": listToken,
"markupBold": True,
"markupMonospace": True,}
theme[MTT.TokenBulletPointList] = {
"markupColor": listToken,
"markupBold": True,
"markupMonospace": True,}
theme[MTT.TokenHorizontalRule] = {
"overline": True,
"underline": True,
"monospace": True,
"color": markup}
theme[MTT.TokenLineBreak] = {
"background": markup}
theme[MTT.TokenBlockquote] = {
"color": light,
"markupColor": veryLight,
"markupBackground": veryLight}
theme[MTT.TokenCodeBlock] = {
"color": light,
"markupBackground": veryLight,
"formatMarkup": True,
"monospace":True,
"deltaSize":-1}
theme[MTT.TokenGithubCodeFence] = {
"color": markup}
theme[MTT.TokenPandocCodeFence] = {
"color": markup}
theme[MTT.TokenCodeFenceEnd] = {
"color": markup}
theme[MTT.TokenMention] = {} # FIXME
theme[MTT.TokenTableHeader] = {
"color": light, "monospace":True}
theme[MTT.TokenTableDivider] = {
"color": markup, "monospace":True}
theme[MTT.TokenTablePipe] = {
"color": markup, "monospace":True}
# CriticMarkup
theme[MTT.TokenCMAddition] = {
"color": QColor("#00bb00"),
"markupColor": QColor(F.mixColors("#00bb00", background, .4)),
"markupMonospace": True,}
theme[MTT.TokenCMDeletion] = {
"color": QColor("#dd0000"),
"markupColor": QColor(F.mixColors("#dd0000", background, .4)),
"markupMonospace": True,
"strike": True}
theme[MTT.TokenCMSubstitution] = {
"color": QColor("#ff8600"),
"markupColor": QColor(F.mixColors("#ff8600", background, .4)),
"markupMonospace": True,}
theme[MTT.TokenCMComment] = {
"color": QColor("#0000bb"),
"markupColor": QColor(F.mixColors("#0000bb", background, .4)),
"markupMonospace": True,}
theme[MTT.TokenCMHighlight] = {
"color": QColor("#aa53a9"),
"background": QColor(F.mixColors("#aa53a9", background, .1)),
"markupBackground": QColor(F.mixColors("#aa53a9", background, .1)),
"markupColor": QColor(F.mixColors("#aa53a9", background, .5)),
"markupMonospace": True,}
return theme
###########################################################################
# ACTUAL FORMATTING
###########################################################################
def applyFormattingForToken(self, token, text):
if token.type != MTT.TokenUnknown:
fmt = self.format(token.position + token.openingMarkupLength)
markupFormat = self.format(token.position)
if self.theme.get("markup"):
markupFormat.setForeground(self.theme["markup"])
## Debug
def debug():
print("{}\n{}{}{}{} (state:{})".format(
text,
" "*token.position,
"^"*token.openingMarkupLength,
str(token.type).center(token.length
- token.openingMarkupLength
- token.closingMarkupLength, "-"),
"^" * token.closingMarkupLength,
self.currentBlockState(),)
)
# if token.type in range(6, 10):
# debug()
theme = self.theme.get(token.type)
if theme:
fmt, markupFormat = self.formatsFromTheme(theme,
fmt,
markupFormat)
# Format openning Markup
self.setFormat(token.position, token.openingMarkupLength,
markupFormat)
# Format Text
self.setFormat(
token.position + token.openingMarkupLength,
token.length - token.openingMarkupLength - token.closingMarkupLength,
fmt)
# Format closing Markup
if token.closingMarkupLength > 0:
self.setFormat(
token.position + token.length - token.closingMarkupLength,
token.closingMarkupLength,
markupFormat)
else:
qWarning("MarkdownHighlighter.applyFormattingForToken() was passed"
" in a token of unknown type.")
def formatsFromTheme(self, theme, format=None,
markupFormat=QTextCharFormat()):
# Token
if theme.get("color"):
format.setForeground(theme["color"])
if theme.get("deltaSize"):
size = self.editor._defaultFontSize + theme["deltaSize"]
if size >= 0:
f = format.font()
f.setPointSize(size)
format.setFont(f)
if theme.get("background"):
format.setBackground(theme["background"])
if theme.get("monospace"):
format.setFontFamily("Monospace")
if theme.get("bold"):
format.setFontWeight(QFont.Bold)
if theme.get("italic"):
format.setFontItalic(theme["italic"])
if theme.get("underline"):
format.setFontUnderline(theme["underline"])
if theme.get("overline"):
format.setFontOverline(theme["overline"])
if theme.get("strike"):
format.setFontStrikeOut(theme["strike"])
if theme.get("super"):
format.setVerticalAlignment(QTextCharFormat.AlignSuperScript)
if theme.get("sub"):
format.setVerticalAlignment(QTextCharFormat.AlignSubScript)
# Markup
if theme.get("formatMarkup"):
c = markupFormat.foreground()
markupFormat = QTextCharFormat(format)
markupFormat.setForeground(c)
if theme.get("markupBold"):
markupFormat.setFontWeight(QFont.Bold)
if theme.get("markupColor"):
markupFormat.setForeground(theme["markupColor"])
if theme.get("markupBackground"):
markupFormat.setBackground(theme["markupBackground"])
if theme.get("markupMonospace"):
markupFormat.setFontFamily("Monospace")
return format, markupFormat
###########################################################################
# SETTINGS
###########################################################################
def setHighlighted(self, words, tags):
rehighlight = (self.highlightedWords != words
or self.highlightedTags != tags)
self.highlightedWords = words
self.highlightedTags = tags
if rehighlight:
self.rehighlight()
def setSearched(self, expression, regExp=False, caseSensitivity=False):
"""
Define an expression currently searched, to be highlighted.
Can be regExp.
"""
rehighlight = self.searchExpression != expression or \
self.searchExpressionRegExp != regExp or \
self.searchExpressionCase != caseSensitivity
self.searchExpression = expression
self.searchExpressionRegExp = regExp
self.searchExpressionCase = caseSensitivity
if rehighlight:
self.rehighlight()
def setDictionary(self, dictionary):
self.dictionary = dictionary
if self.spellCheckEnabled:
self.rehighlight()
def increaseFontSize(self):
self._defaultCharFormat.setFontPointSize(
self._defaultCharFormat.font().pointSize() + 1.0)
self.rehighlight()
def decreaseFontSize(self):
self._defaultCharFormat.setFontPointSize(
self._defaultCharFormat.font().pointSize() - 1.0)
self.rehighlight()
def setEnableLargeHeadingSizes(self, enable):
self.setupHeadingFontSize(enable)
self.rehighlight()
def setupHeadingFontSize(self, useLargeHeadings):
if useLargeHeadings:
self.theme[MTT.TokenSetextHeading1Line1]["deltaSize"] = 7
self.theme[MTT.TokenSetextHeading2Line1]["deltaSize"] = 5
self.theme[MTT.TokenSetextHeading1Line2]["deltaSize"] = 7
self.theme[MTT.TokenSetextHeading2Line2]["deltaSize"] = 5
self.theme[MTT.TokenAtxHeading1]["deltaSize"] = 7
self.theme[MTT.TokenAtxHeading2]["deltaSize"] = 5
self.theme[MTT.TokenAtxHeading3]["deltaSize"] = 3
self.theme[MTT.TokenAtxHeading4]["deltaSize"] = 2
self.theme[MTT.TokenAtxHeading5]["deltaSize"] = 1
self.theme[MTT.TokenAtxHeading6]["deltaSize"] = 0
else:
for i in MTT.TITLES:
self.theme[i]["deltaSize"] = 0
def setUseUnderlineForEmphasis(self, enable):
self.useUndlerlineForEmphasis = enable
self.rehighlight()
def setFont(self, fontFamily, fontSize):
font = QFont(family=fontFamily, pointSize=fontSize,
weight=QFont.Normal, italic=False)
self._defaultCharFormat.setFont(font)
self.rehighlight()
def setSpellCheckEnabled(self, enabled):
self.spellCheckEnabled = enabled
self.rehighlight()
def setBlockquoteStyle(self, style):
self.blockquoteStyle = style
if style == BS.BlockquoteStyleItalic:
self.emphasizeToken[MTT.TokenBlockquote] = True
else:
self.emphasizeToken[MTT.TokenBlockquote] = False
self.rehighlight()
def setHighlightLineBreaks(self, enable):
self.highlightLineBreaks = enable
self.rehighlight()
###########################################################################
# GHOSTWRITER SPECIFIC?
###########################################################################
def onTypingResumed(self):
self.typingPaused = False
def onTypingPaused(self):
self.typingPaused = True
block = self.document().findBlock(self.editor.textCursor().position())
self.rehighlightBlock(block)
def onHighlightBlockAtPosition(self, position):
block = self.document().findBlock(position)
self.rehighlightBlock(block)
def onTextBlockRemoved(self, block):
if self.isHeadingBlockState(block.userState):
self.headingRemoved.emit(block.position())
###########################################################################
# SPELLCHECK
###########################################################################
def spellCheck(self, text):
cursorPosition = self.editor.textCursor().position()
cursorPosBlock = self.document().findBlock(cursorPosition)
cursorPosInBlock = -1
if self.currentBlock() == cursorPosBlock:
cursorPosInBlock = cursorPosition - cursorPosBlock.position()
misspelledWord = self.dictionary.check(text, 0)
while not misspelledWord.isNull():
startIndex = misspelledWord.position()
length = misspelledWord.length()
if self.typingPaused or cursorPosInBlock != startIndex + length:
spellingErrorFormat = self.format(startIndex)
spellingErrorFormat.setUnderlineColor(self.spellingErrorColor)
spellingErrorFormat.setUnderlineStyle(
qApp.stlye().styleHint(QStyle.SH_SpellCheckUnderlineStyle))
self.setFormat(startIndex, length, spellingErrorFormat)
startIndex += length
misspelledWord = self.dictionary.check(text, startIndex)
def storeHeadingData(self, token, text):
if token.type in [
MTT.TokenAtxHeading1,
MTT.TokenAtxHeading2,
MTT.TokenAtxHeading3,
MTT.TokenAtxHeading4,
MTT.TokenAtxHeading5,
MTT.TokenAtxHeading6]:
level = token.type - MTT.TokenAtxHeading1 + 1
s = token.position + token.openingMarkupLength
l = (token.length
- token.openingMarkupLength
- token.closingMarkupLength)
headingText = text[s:s+l].strip()
elif token.type == MTT.TokenSetextHeading1Line1:
level = 1
headingText = text
elif token.type == MTT.TokenSetextHeading2Line1:
level = 2
headingText = text
else:
qWarning("MarkdownHighlighter.storeHeadingData() encountered" +
" unexpected token: {}".format(token.getType()))
return
# FIXME: TypeError: could not convert 'TextBlockData' to 'QTextBlockUserData'
# blockData = self.currentBlockUserData()
# if blockData is None:
# blockData = TextBlockData(self.document(), self.currentBlock())
#
# self.setCurrentBlockUserData(blockData)
self.headingFound.emit(level, headingText, self.currentBlock())
def isHeadingBlockState(self, state):
return state in [
MS.MarkdownStateAtxHeading1,
MS.MarkdownStateAtxHeading2,
MS.MarkdownStateAtxHeading3,
MS.MarkdownStateAtxHeading4,
MS.MarkdownStateAtxHeading5,
MS.MarkdownStateAtxHeading6,
MS.MarkdownStateSetextHeading1Line1,
MS.MarkdownStateSetextHeading2Line1,]
def getLuminance(color):
return (0.30 * color.redF()) + \
(0.59 * color.greenF()) + \
(0.11 * color.blueF())
def applyAlphaToChannel(foreground, background, alpha):
return (foreground * alpha) + (background * (1.0 - alpha))
def applyAlpha(foreground, background, alpha):
blendedColor = QColor(0, 0, 0)
normalizedAlpha = alpha / 255.0
blendedColor.setRed(applyAlphaToChannel(
foreground.red(), background.red(), normalizedAlpha))
blendedColor.setGreen(applyAlphaToChannel(
foreground.green(), background.green(), normalizedAlpha))
blendedColor.setBlue(applyAlphaToChannel(
foreground.blue(), background.blue(), normalizedAlpha))
return blendedColor

View file

@ -0,0 +1,902 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from manuskript.ui.highlighters import MarkdownState as MS
from manuskript.ui.highlighters import MarkdownTokenType as MTT
# This file is simply a python translation of GhostWriter's Tokenizer.
# http://wereturtle.github.io/ghostwriter/
# GPLV3+.
# ==============================================================================
# TOKEN
# ==============================================================================
class Token:
def __init__(self):
self.type = -1
self.position = 0
self.length = 0
self.openingMarkupLength = 0
self.closingMarkupLength = 0
# ==============================================================================
# HIGHLIGHT TOKENIZER
# ==============================================================================
class HighlightTokenizer:
def __init__(self):
self.tokens = []
def tokenize(text, currentState, previousState, nextState):
# Subclass me
return 0
def getTokens(self):
self.tokens = sorted(self.tokens, key=lambda t: t.position)
return self.tokens
def getState(self):
return self.state
def backtrackRequested(self):
return self.backtrack
def clear(self):
self.tokens = []
self.backtrack = False
self.state = -1
def addToken(self, token):
self.tokens.append(token)
if token.type == -1:
print("Error here", token.position, token.length)
def setState(self, state):
self.state = state
def requestBacktrack(self):
self.backtrack = True
def tokenLessThan(self, t1, t2):
return t1.getPosition() < t2.getPosition()
class MarkdownTokenizer(HighlightTokenizer):
DUMMY_CHAR = "$"
MAX_MARKDOWN_HEADING_LEVEL = 6
paragraphBreakRegex = QRegExp("^\\s*$")
heading1SetextRegex = QRegExp("^===+\\s*$")
heading2SetextRegex = QRegExp("^---+\\s*$")
blockquoteRegex = QRegExp("^ {0,3}>.*$")
githubCodeFenceStartRegex = QRegExp("^```+.*$")
githubCodeFenceEndRegex = QRegExp("^```+\\s*$")
pandocCodeFenceStartRegex = QRegExp("^~~~+.*$")
pandocCodeFenceEndRegex = QRegExp("^~~~+\\s*$")
numberedListRegex = QRegExp("^ {0,3}[0-9a-z]+[.)]\\s+.*$")
numberedNestedListRegex = QRegExp("^\\s*[0-9a-z]+[.)]\\s+.*$")
hruleRegex = QRegExp("\\s*(\\*\\s*){3,}|(\\s*(_\\s*){3,})|((\\s*(-\\s*){3,}))")
lineBreakRegex = QRegExp(".*\\s{2,}$")
emphasisRegex = QRegExp("(\\*(?![\\s*]).*[^\\s*]\\*)|_(?![\\s_]).*[^\\s_]_")
emphasisRegex.setMinimal(True)
strongRegex = QRegExp("\\*\\*(?=\\S).*\\S\\*\\*(?!\\*)|__(?=\\S).*\\S__(?!_)")
strongRegex.setMinimal(True)
strikethroughRegex = QRegExp("~~[^\\s]+.*[^\\s]+~~")
strikethroughRegex.setMinimal(True)
superScriptRegex = QRegExp("\^([^\\s]|(\\\\\\s))+\^") # Spaces must be escaped "\ "
superScriptRegex.setMinimal(True)
subScriptRegex = QRegExp("~([^\\s]|(\\\\\\s))+~") # Spaces must be escaped "\ "
subScriptRegex.setMinimal(True)
verbatimRegex = QRegExp("`+")
htmlTagRegex = QRegExp("<[^<>]+>")
htmlTagRegex.setMinimal(True)
htmlEntityRegex = QRegExp("&[a-zA-Z]+;|&#x?[0-9]+;")
automaticLinkRegex = QRegExp("(<[a-zA-Z]+\\:.+>)|(<.+@.+>)")
automaticLinkRegex.setMinimal(True)
inlineLinkRegex = QRegExp("\\[.+\\]\\(.+\\)")
inlineLinkRegex.setMinimal(True)
referenceLinkRegex = QRegExp("\\[(.+)\\]")
referenceLinkRegex.setMinimal(True)
referenceDefinitionRegex = QRegExp("^\\s*\\[.+\\]:")
imageRegex = QRegExp("!\\[.*\\]\\(.+\\)")
imageRegex.setMinimal(True)
htmlInlineCommentRegex = QRegExp("<!--.*-->")
htmlInlineCommentRegex.setMinimal(True)
mentionRegex = QRegExp("\\B@\\w+(\\-\\w+)*(/\\w+(\\-\\w+)*)?")
pipeTableDividerRegex = QRegExp("^ {0,3}(\\|[ :]?)?-{3,}([ :]?\\|[ :]?-{3,}([ :]?\\|)?)+\\s*$")
CMAdditionRegex = QRegExp("(\\{\\+\\+.*\\+\\+\\})")
CMAdditionRegex.setMinimal(True)
CMDeletionRegex = QRegExp("(\\{--.*--\\})")
CMDeletionRegex.setMinimal(True)
CMSubstitutionRegex = QRegExp("(\\{~~.*~>.*~~\\})")
CMSubstitutionRegex.setMinimal(True)
CMCommentRegex = QRegExp("(\\{>>.*<<\\})")
CMCommentRegex.setMinimal(True)
CMHighlightRegex = QRegExp("(\\{==.*==\\})")
CMHighlightRegex.setMinimal(True)
def __init__(self):
HighlightTokenizer.__init__(self)
def tokenize(self, text, currentState, previousState, nextState):
self.currentState = currentState
self.previousState = previousState
self.nextState = nextState
if (self.previousState == MS.MarkdownStateInGithubCodeFence or \
self.previousState == MS.MarkdownStateInPandocCodeFence) and \
self.tokenizeCodeBlock(text):
# No further tokenizing required
pass
elif self.previousState != MS.MarkdownStateComment \
and self.paragraphBreakRegex.exactMatch(text):
if previousState in [MS.MarkdownStateListLineBreak,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList]:
self.setState(MS.MarkdownStateListLineBreak)
elif previousState != MS.MarkdownStateCodeBlock or \
(text[:1] != "\t" and text[-4:] != " "):
self.setState(MS.MarkdownStateParagraphBreak)
elif self.tokenizeSetextHeadingLine2(text) or \
self.tokenizeCodeBlock(text) or \
self.tokenizeMultilineComment(text) or \
self.tokenizeHorizontalRule(text) or \
self.tokenizeTableDivider(text):
# No further tokenizing required
pass
elif self.tokenizeSetextHeadingLine1(text) or \
self.tokenizeAtxHeading(text) or \
self.tokenizeBlockquote(text) or \
self.tokenizeNumberedList(text) or \
self.tokenizeBulletPointList(text):
self.tokenizeLineBreak(text)
self.tokenizeInline(text)
else:
if previousState in [MS.MarkdownStateListLineBreak,
MS.MarkdownStateNumberedList,
MS.MarkdownStateNumberedList]:
if not self.tokenizeNumberedList(text) and \
not self.tokenizeBulletPointList(text) and \
(text[:1] == "\t" or text[:4] == " "):
self.setState(previousState)
else:
self.setState(MS.MarkdownStateParagraph)
else:
self.setState(MS.MarkdownStateParagraph)
self.tokenizeLineBreak(text)
self.tokenizeInline(text)
# Make sure that if the second line of a setext heading is removed the
# first line is reprocessed. Otherwise, it will still show up in the
# document as a heading.
if (previousState == MS.MarkdownStateSetextHeading1Line1 and \
self.getState() != MS.MarkdownStateSetextHeading1Line2) or \
(previousState == MS.MarkdownStateSetextHeading2Line1 and \
self.getState() != MS.MarkdownStateSetextHeading2Line2):
self.requestBacktrack()
def tokenizeSetextHeadingLine1(self, text):
#Check the next line's state to see if this is a setext-style heading.
level = 0
token = Token()
nextState = self.nextState
if MS.MarkdownStateSetextHeading1Line2 == nextState:
level = 1
self.setState(MS.MarkdownStateSetextHeading1Line1)
token.type = MTT.TokenSetextHeading1Line1
elif MS.MarkdownStateSetextHeading2Line2 == nextState:
level = 2
self.setState(MS.MarkdownStateSetextHeading2Line1)
token.type = MTT.TokenSetextHeading2Line1
if level > 0:
token.length = len(text)
token.position = 0
self.addToken(token)
return True
return False
def tokenizeSetextHeadingLine2(self, text):
level = 0
setextMatch = False
token = Token()
previousState = self.previousState
if previousState == MS.MarkdownStateSetextHeading1Line1:
level = 1
setextMatch = self.heading1SetextRegex.exactMatch(text)
self.setState(MS.MarkdownStateSetextHeading1Line2)
token.type = MTT.TokenSetextHeading1Line2
elif previousState == MS.MarkdownStateSetextHeading2Line1:
level = 2
setextMatch = self.heading2SetextRegex.exactMatch(text)
self.setState(MS.MarkdownStateSetextHeading2Line2)
token.type = MTT.TokenSetextHeading2Line2
elif previousState == MS.MarkdownStateParagraph:
h1Line2 = self.heading1SetextRegex.exactMatch(text)
h2Line2 = self.heading2SetextRegex.exactMatch(text)
if h1Line2 or h2Line2:
# Restart tokenizing on the previous line.
self.requestBacktrack()
token.length = len(text)
token.position = 0
if h1Line2:
self.setState(MS.MarkdownStateSetextHeading1Line2)
token.type = MTT.TokenSetextHeading1Line2
else:
self.setState(MS.MarkdownStateSetextHeading2Line2)
token.type = MTT.TokenSetextHeading2Line2
self.addToken(token)
return True
if level > 0:
if setextMatch:
token.length = len(text)
token.position = 0
self.addToken(token)
return True
else:
# Restart tokenizing on the previous line.
self.requestBacktrack()
False
return False
def tokenizeAtxHeading(self, text):
escapedText = self.dummyOutEscapeCharacters(text)
trailingPoundCount = 0
level = 0
#Count the number of pound signs at the front of the string,
#up to the maximum allowed, to determine the heading level.
while escapedText[level] == "#":
level += 1
if level >= len(escapedText) or level >= self.MAX_MARKDOWN_HEADING_LEVEL:
break
if level > 0 and level < len(text):
# Count how many pound signs are at the end of the text.
while escapedText[-trailingPoundCount -1] == "#":
trailingPoundCount += 1
token = Token()
token.position = 0
token.length = len(text)
token.type = MTT.TokenAtxHeading1 + level -1
token.openingMarkupLength = level
token.closingMarkupLength = trailingPoundCount
self.addToken(token)
self.setState(MS.MarkdownStateAtxHeading1 + level -1)
return True
return False
def tokenizeNumberedList(self, text):
previousState = self.previousState
if (previousState in [MS.MarkdownStateParagraphBreak,
MS.MarkdownStateUnknown,
MS.MarkdownStateCodeBlock,
MS.MarkdownStateCodeFenceEnd,] and \
self.numberedListRegex.exactMatch(text)) or \
(previousState in [MS.MarkdownStateListLineBreak,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,] and \
self.numberedNestedListRegex.exactMatch(text)):
periodIndex = text.find(".")
parenthIndex = text.find(")")
if periodIndex < 0:
index = parenthIndex
elif parenthIndex < 0:
index = periodIndex
elif parenthIndex > periodIndex:
index = periodIndex
else:
index = parenthIndex
if index > 0:
token = Token()
token.type = MTT.TokenNumberedList
token.position = 0
token.length = len(text)
token.openingMarkupLength = index + 2
self.addToken(token)
self.setState(MS.MarkdownStateNumberedList)
return True
return False
return False
def tokenizeBulletPointList(self, text):
foundBulletChar = False
bulletCharIndex = -1
spaceCount = 0
whitespaceFoundAfterBulletChar = False
previousState = self.previousState
if previousState not in [MS.MarkdownStateUnknown,
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateListLineBreak,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,
MS.MarkdownStateCodeBlock,
MS.MarkdownStateCodeFenceEnd]:
return False
# Search for the bullet point character, which can
# be either a '+', '-', or '*'.
for i in range(len(text)):
if text[i] == " ":
if foundBulletChar:
# We've confirmed it's a bullet point by the whitespace that
# follows the bullet point character, and can now exit the
# loop.
whitespaceFoundAfterBulletChar = True
break
else:
spaceCount += 1
# If this list item is the first in the list, ensure the
# number of spaces preceeding the bullet point does not
# exceed three, as that would indicate a code block rather
# than a bullet point list.
if spaceCount > 3 and previousState not in [
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,
MS.MarkdownStateListLineBreak,] and \
previousState in [
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateUnknown,
MS.MarkdownStateCodeBlock,
MS.MarkdownStateCodeFenceEnd,]:
return False
elif text[i] == "\t":
if foundBulletChar:
# We've confirmed it's a bullet point by the whitespace that
# follows the bullet point character, and can now exit the
# loop.
whitespaceFoundAfterBulletChar = True
break
elif previousState in [
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateUnknown]:
# If this list item is the first in the list, ensure that
# no tab character preceedes the bullet point, as that would
# indicate a code block rather than a bullet point list.
return False
elif text[i] in ["+", "-", "*"]:
foundBulletChar = True
bulletCharIndex = i
else:
return False
if bulletCharIndex >= 0 and whitespaceFoundAfterBulletChar:
token = Token()
token.type = MTT.TokenBulletPointList
token.position = 0
token.length = len(text)
token.openingMarkupLength = bulletCharIndex + 2
self.addToken(token)
self.setState(MS.MarkdownStateBulletPointList)
return True
return False
def tokenizeHorizontalRule (self, text):
if self.hruleRegex.exactMatch(text):
token = Token()
token.type = MTT.TokenHorizontalRule
token.position = 0
token.length = len(text)
self.addToken(token)
self.setState(MS.MarkdownStateHorizontalRule)
return True
return False
def tokenizeLineBreak(self, text):
currentState = self.currentState
previousState = self.previousState
nextState = self.nextState
if currentState in [
MS.MarkdownStateParagraph,
MS.MarkdownStateBlockquote,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,]:
if previousState in [
MS.MarkdownStateParagraph,
MS.MarkdownStateBlockquote,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,]:
self.requestBacktrack()
if nextState in [
MS.MarkdownStateParagraph,
MS.MarkdownStateBlockquote,
MS.MarkdownStateNumberedList,
MS.MarkdownStateBulletPointList,]:
self.requestBacktrack()
if self.lineBreakRegex.exactMatch(text):
token = Token()
token.type = MTT.TokenLineBreak
token.position = len(text) - 1
token.length = 1
self.addToken(token)
return True
return False
def tokenizeBlockquote(self, text):
previousState = self.previousState
if previousState == MS.MarkdownStateBlockquote or \
self.blockquoteRegex.exactMatch(text):
# Find any '>' characters at the front of the line.
markupLength = 0
for i in range(len(text)):
if text[i] == ">":
markupLength = i + 1
elif text[i] != " ":
# There are no more '>' characters at the front of the line,
# so stop processing.
break
token = Token()
token.type = MTT.TokenBlockquote
token.position = 0
token.length = len(text)
if markupLength > 0:
token.openingMarkupLength = markupLength
self.addToken(token)
self.setState(MS.MarkdownStateBlockquote)
return True
return False
def tokenizeCodeBlock(self, text):
previousState = self.previousState
if previousState in [
MS.MarkdownStateInGithubCodeFence,
MS.MarkdownStateInPandocCodeFence]:
self.setState(previousState)
if (previousState == MS.MarkdownStateInGithubCodeFence and \
self.githubCodeFenceEndRegex.exactMatch(text)) or \
(previousState == MS.MarkdownStateInPandocCodeFence and \
self.pandocCodeFenceEndRegex.exactMatch(text)):
token = Token()
token.type = MTT.TokenCodeFenceEnd
token.position = 0
token.length = len(text)
self.addToken(token)
self.setState(MS.MarkdownStateCodeFenceEnd)
else:
token = Token()
token.type = MTT.TokenCodeBlock
token.position = 0
token.length = len(text)
self.addToken(token)
return True
elif previousState in [
MS.MarkdownStateCodeBlock,
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateUnknown,] and \
(text[:1] == "\t" or text[:4] == " "):
token = Token()
token.type = MTT.TokenCodeBlock
token.position = 0
token.length = len(text)
token.openingMarkupLength = len(text) - len(text.lstrip())
self.addToken(token)
self.setState(MS.MarkdownStateCodeBlock)
return True
elif previousState in [
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateParagraph,
MS.MarkdownStateUnknown,
MS.MarkdownStateListLineBreak,]:
foundCodeFenceStart = False
token = Token()
if self.githubCodeFenceStartRegex.exactMatch(text):
foundCodeFenceStart = True
token.type = MTT.TokenGithubCodeFence
self.setState(MS.MarkdownStateInGithubCodeFence)
elif self.pandocCodeFenceStartRegex.exactMatch(text):
foundCodeFenceStart = True
token.type = MTT.TokenPandocCodeFence
self.setState(MS.MarkdownStateInPandocCodeFence)
if foundCodeFenceStart:
token.position = 0
token.length = len(text)
self.addToken(token)
return True
return False
def tokenizeMultilineComment(self, text):
previousState = self.previousState
if previousState == MS.MarkdownStateComment:
# Find the end of the comment, if any.
index = text.find("-->")
token = Token()
token.type = MTT.TokenHtmlComment
token.position = 0
if index >= 0:
token.length = index + 3
self.addToken(token)
# Return false so that the rest of the line that isn't within
# the commented segment can be highlighted as normal paragraph
# text.
else:
token.length = len(text)
self.addToken(token)
self.setState(MS.MarkdownStateComment)
return True
return False
def tokenizeInline(self, text):
escapedText = self.dummyOutEscapeCharacters(text)
# Check if the line is a reference definition.
if self.referenceDefinitionRegex.exactMatch(text):
colonIndex = escapedText.find(":")
token = Token()
token.type = MTT.TokenReferenceDefinition
token.position = 0
token.length = colonIndex + 1
self.addToken(token)
# Replace the first bracket so that the '[...]:' reference definition
# start doesn't get highlighted as a reference link.
firstBracketIndex = escapedText.find("[")
if firstBracketIndex >= 0:
i = firstBracketIndex
escapedText = escapedText[:i] + self.DUMMY_CHAR + escapedText[i+1:]
escapedText = self.tokenizeVerbatim(escapedText)
escapedText = self.tokenizeHtmlComments(escapedText)
escapedText = self.tokenizeTableHeaderRow(escapedText)
escapedText = self.tokenizeTableRow(escapedText)
escapedText = self.tokenizeMatches(MTT.TokenImage, escapedText, self.imageRegex, 0, 0, False, True)
escapedText = self.tokenizeMatches(MTT.TokenInlineLink, escapedText, self.inlineLinkRegex, 0, 0, False, True)
escapedText = self.tokenizeMatches(MTT.TokenReferenceLink, escapedText, self.referenceLinkRegex, 0, 0, False, True)
escapedText = self.tokenizeMatches(MTT.TokenHtmlEntity, escapedText, self.htmlEntityRegex)
escapedText = self.tokenizeMatches(MTT.TokenAutomaticLink, escapedText, self.automaticLinkRegex, 0, 0, False, True)
escapedText = self.tokenizeMatches(MTT.TokenStrong, escapedText, self.strongRegex, 2, 2, True)
escapedText = self.tokenizeMatches(MTT.TokenEmphasis, escapedText, self.emphasisRegex, 1, 1, True)
escapedText = self.tokenizeMatches(MTT.TokenMention, escapedText, self.mentionRegex, 0, 0, False, True)
escapedText = self.tokenizeMatches(MTT.TokenCMAddition, escapedText, self.CMAdditionRegex, 3, 3, True)
escapedText = self.tokenizeMatches(MTT.TokenCMDeletion, escapedText, self.CMDeletionRegex, 3, 3, True)
escapedText = self.tokenizeMatches(MTT.TokenCMSubstitution, escapedText, self.CMSubstitutionRegex, 3, 3, True)
escapedText = self.tokenizeMatches(MTT.TokenCMComment, escapedText, self.CMCommentRegex, 3, 3, True)
escapedText = self.tokenizeMatches(MTT.TokenCMHighlight, escapedText, self.CMHighlightRegex, 3, 3, True)
escapedText = self.tokenizeMatches(MTT.TokenStrikethrough, escapedText, self.strikethroughRegex, 2, 2, True)
escapedText = self.tokenizeMatches(MTT.TokenHtmlTag, escapedText, self.htmlTagRegex)
escapedText = self.tokenizeMatches(MTT.TokenSubScript, escapedText, self.subScriptRegex, 1, 1, True)
escapedText = self.tokenizeMatches(MTT.TokenSuperScript, escapedText, self.superScriptRegex, 1, 1, True)
return True
def tokenizeVerbatim(self, text):
index = self.verbatimRegex.indexIn(text)
while index >= 0:
end = ""
count = self.verbatimRegex.matchedLength()
# Search for the matching end, which should have the same number
# of back ticks as the start.
for i in range(count):
end += '`'
endIndex = text.find(end, index + count)
# If the end was found, add the verbatim token.
if endIndex >= 0:
token = Token()
token.type = MTT.TokenVerbatim
token.position = index
token.length = endIndex + count - index
token.openingMarkupLength = count
token.closingMarkupLength = count
self.addToken(token)
# Fill out the token match in the string with the dummy
# character so that searches for other Markdown elements
# don't find anything within this token's range in the string.
for i in range(index, index + token.length):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
index += token.length
# Else start searching again at the very next character.
else:
index += 1
index = self.verbatimRegex.indexIn(text, index)
return text
def tokenizeHtmlComments(self, text):
previousState = self.previousState
# Check for the end of a multiline comment so that it doesn't get further
# tokenized. Don't bother formatting the comment itself, however, because
# it should have already been tokenized in tokenizeMultilineComment().
if previousState == MS.MarkdownStateComment:
commentEnd = text.find("-->")
for i in range(commentEnd + 3):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
# Now check for inline comments (non-multiline).
commentStart = self.htmlInlineCommentRegex.indexIn(text)
while commentStart >= 0:
commentLength = self.htmlInlineCommentRegex.matchedLength()
token = Token()
token.type = MTT.TokenHtmlComment
token.position = commentStart
token.length = commentLength
self.addToken(token)
# Replace comment segment with dummy characters so that it doesn't
# get tokenized again.
for i in range(commentStart, commentStart + commentLength):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
commentStart = self.htmlInlineCommentRegex.indexIn(text, commentStart + commentLength)
# Find multiline comment start, if any.
commentStart = text.find("<!--")
if commentStart >= 0:
token = Token()
token.type = MTT.TokenHtmlComment
token.position = commentStart
token.length = len(text) - commentStart
self.addToken(token)
self.setState(MS.MarkdownStateComment)
# Replace comment segment with dummy characters so that it doesn't
# get tokenized again.
for i in range(commentStart, len(text)):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
return text
def tokenizeTableHeaderRow(self, text):
previousState = self.previousState
nextState = self.nextState
if previousState in [
MS.MarkdownStateParagraphBreak,
MS.MarkdownStateListLineBreak,
MS.MarkdownStateSetextHeading1Line2,
MS.MarkdownStateSetextHeading2Line2,
MS.MarkdownStateAtxHeading1,
MS.MarkdownStateAtxHeading2,
MS.MarkdownStateAtxHeading3,
MS.MarkdownStateAtxHeading4,
MS.MarkdownStateAtxHeading5,
MS.MarkdownStateAtxHeading6,
MS.MarkdownStateHorizontalRule,
MS.MarkdownStateCodeFenceEnd,
MS.MarkdownStateUnknown,] and \
self.getState() in [
MS.MarkdownStateParagraph,
MS.MarkdownStateUnknown] and \
nextState == MS.MarkdownStatePipeTableDivider:
self.setState(MS.MarkdownStatePipeTableHeader)
headerStart = 0
for i in range(len(text)):
if text[i] == "|":
# Replace pipe with space so that it doesn't get formatted
# again with, for example, strong or emphasis formatting.
# Note that we use a space rather than DUMMY_CHAR for this,
# to prevent formatting such as strong and emphasis from
# picking it up.
text = text[:i] + " " + text[i+1:]
token = Token()
if i > 0:
token.type = MTT.TokenTableHeader
token.position = headerStart
token.length = i - headerStart
self.addToken(token)
token.type = MTT.TokenTablePipe
token.position = i
token.length = 1
self.addToken(token)
headerStart = i + 1
if headerStart < len(text):
token = Token()
token.type = MTT.TokenTableHeader
token.position = headerStart
token.length = len(text) - headerStart
self.addToken(token)
return text
def tokenizeTableDivider(self, text):
previousState = self.previousState
if previousState == MS.MarkdownStatePipeTableHeader:
if self.pipeTableDividerRegex.exactMatch(text):
self.setState(MS.MarkdownStatePipeTableDivider)
token = Token()
token.type = MTT.TokenTableDivider
token.length = len(text)
token.position = 0
self.addToken(token)
return True
else:
# Restart tokenizing on the previous line.
self.requestBacktrack()
elif previousState == MS.MarkdownStateParagraph:
if self.pipeTableDividerRegex.exactMatch(text):
# Restart tokenizing on the previous line.
self.requestBacktrack()
self.setState(MS.MarkdownStatePipeTableDivider)
token = Token()
token.length = len(text)
token.position = 0
token.type = MTT.TokenTableDivider
self.addToken(token)
return True
return False
def tokenizeTableRow(self, text):
previousState = self.previousState
if previousState in [
MS.MarkdownStatePipeTableDivider,
MS.MarkdownStatePipeTableRow]:
self.setState(MS.MarkdownStatePipeTableRow)
for i in range(len(text)):
if text[i] == "|":
# Replace pipe with space so that it doesn't get formatted
# again with, for example, strong or emphasis formatting.
# Note that we use a space rather than DUMMY_CHAR for this,
# to prevent formatting such as strong and emphasis from
# picking it up.
text = text[:i] + " " + text[i+1:]
token = Token()
token.type = MTT.TokenTablePipe
token.position = i
token.length = 1
self.addToken(token)
return text
def tokenizeMatches(self, tokenType, text, regex,
markupStartCount=0, markupEndCount=0,
replaceMarkupChars=False, replaceAllChars=False):
"""
Tokenizes a block of text, searching for all occurrances of regex.
Occurrances are set to the given token type and added to the list of
tokens. The markupStartCount and markupEndCount values are used to
indicate how many markup special characters preceed and follow the
main text, respectively.
For example, if the matched string is "**bold**", and
markupStartCount = 2 and markupEndCount = 2, then the asterisks
preceeding and following the word "bold" will be set as opening and
closing markup in the token.
If replaceMarkupChars is true, then the markupStartCount and
markupEndCount characters will be replaced with a dummy character in
the text QString so that subsequent parsings of the same line do not
pick up the original characters.
If replaceAllChars is true instead, then the entire matched text will
be replaced with dummy characters--again, for ease in parsing the
same line for other regular expression matches.
"""
index = regex.indexIn(text)
while index >= 0:
length = regex.matchedLength()
token = Token()
token.type = tokenType
token.position = index
token.length = length
if markupStartCount > 0:
token.openingMarkupLength = markupStartCount
if markupEndCount > 0:
token.closingMarkupLength = markupEndCount
if replaceAllChars:
for i in range(index, index + length):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
elif replaceMarkupChars:
for i in range(index, index + markupStartCount):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
for i in range(index + length - markupEndCount, index + length):
text = text[:i] + self.DUMMY_CHAR + text[i+1:]
self.addToken(token)
index = regex.indexIn(text, index + length)
return text
def dummyOutEscapeCharacters(self, text):
"""
Replaces escaped characters in text so they aren't picked up
during parsing. Returns a copy of the input text string
with the escaped characters replaced with a dummy character.
"""
return re.sub("\\\\.", "\$", text)
#escape = False
#escapedText = text
#for i in range(len(text)):
#if escape:
#escapedText = escapedText[:i] + self.DUMMY_CHAR + escapedText[i+1:]
#escape = False
#elif text[i] == "\\":
#escape = True
#return escapedText

View file

@ -7,7 +7,7 @@ from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QBrush, QColor, QIcon from PyQt5.QtGui import QBrush, QColor, QIcon
from PyQt5.QtWidgets import QWidget, QFileDialog, QMessageBox, QStyle from PyQt5.QtWidgets import QWidget, QFileDialog, QMessageBox, QStyle
from manuskript.functions import writablePath, appPath, openURL from manuskript.functions import writablePath, appPath, openURL, statusMessage
from manuskript.ui.importers.importer_ui import Ui_importer from manuskript.ui.importers.importer_ui import Ui_importer
from manuskript.ui.importers.generalSettings import generalSettings from manuskript.ui.importers.generalSettings import generalSettings
from manuskript.ui import style from manuskript.ui import style
@ -259,7 +259,7 @@ class importerDialog(QWidget, Ui_importer):
# Using status bar message instead... # Using status bar message instead...
#QMessageBox.information(self, self.tr("Import status"), #QMessageBox.information(self, self.tr("Import status"),
#self.tr("Import Complete.")) #self.tr("Import Complete."))
self.mw.statusBar().showMessage("Import complete!", 5000) statusMessage("Import complete!", 5000)
self.close() self.close()
@ -320,5 +320,3 @@ class importerDialog(QWidget, Ui_importer):
item.split(self.settingsWidget.splitScenes(), recursive=False) item.split(self.settingsWidget.splitScenes(), recursive=False)
return items return items

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui' # Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui'
# #
# Created by: PyQt5 UI code generator 5.9 # Created by: PyQt5 UI code generator 5.5.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -24,7 +24,6 @@ class Ui_MainWindow(object):
self.welcomePage = QtWidgets.QWidget() self.welcomePage = QtWidgets.QWidget()
self.welcomePage.setObjectName("welcomePage") self.welcomePage.setObjectName("welcomePage")
self.gridLayout = QtWidgets.QGridLayout(self.welcomePage) self.gridLayout = QtWidgets.QGridLayout(self.welcomePage)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem, 1, 0, 1, 1) self.gridLayout.addItem(spacerItem, 1, 0, 1, 1)
@ -161,12 +160,11 @@ class Ui_MainWindow(object):
self.tabSummaryPage1 = QtWidgets.QWidget() self.tabSummaryPage1 = QtWidgets.QWidget()
self.tabSummaryPage1.setObjectName("tabSummaryPage1") self.tabSummaryPage1.setObjectName("tabSummaryPage1")
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.tabSummaryPage1) self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.tabSummaryPage1)
self.verticalLayout_5.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_5.setObjectName("verticalLayout_5") self.verticalLayout_5.setObjectName("verticalLayout_5")
self.label = QtWidgets.QLabel(self.tabSummaryPage1) self.label = QtWidgets.QLabel(self.tabSummaryPage1)
self.label.setObjectName("label") self.label.setObjectName("label")
self.verticalLayout_5.addWidget(self.label) self.verticalLayout_5.addWidget(self.label)
self.txtSummarySentence = textEditView(self.tabSummaryPage1) self.txtSummarySentence = MDEditCompleter(self.tabSummaryPage1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@ -184,14 +182,13 @@ class Ui_MainWindow(object):
self.tabSummaryPage2 = QtWidgets.QWidget() self.tabSummaryPage2 = QtWidgets.QWidget()
self.tabSummaryPage2.setObjectName("tabSummaryPage2") self.tabSummaryPage2.setObjectName("tabSummaryPage2")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tabSummaryPage2) self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tabSummaryPage2)
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.label_21 = QtWidgets.QLabel(self.tabSummaryPage2) self.label_21 = QtWidgets.QLabel(self.tabSummaryPage2)
self.label_21.setObjectName("label_21") self.label_21.setObjectName("label_21")
self.verticalLayout.addWidget(self.label_21) self.verticalLayout.addWidget(self.label_21)
self.txtSummarySentence_2 = textEditView(self.tabSummaryPage2) self.txtSummarySentence_2 = MDEditCompleter(self.tabSummaryPage2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@ -213,7 +210,7 @@ class Ui_MainWindow(object):
self.label_2 = QtWidgets.QLabel(self.tabSummaryPage2) self.label_2 = QtWidgets.QLabel(self.tabSummaryPage2)
self.label_2.setObjectName("label_2") self.label_2.setObjectName("label_2")
self.verticalLayout_2.addWidget(self.label_2) self.verticalLayout_2.addWidget(self.label_2)
self.txtSummaryPara = textEditView(self.tabSummaryPage2) self.txtSummaryPara = MDEditCompleter(self.tabSummaryPage2)
self.txtSummaryPara.setObjectName("txtSummaryPara") self.txtSummaryPara.setObjectName("txtSummaryPara")
self.verticalLayout_2.addWidget(self.txtSummaryPara) self.verticalLayout_2.addWidget(self.txtSummaryPara)
self.lblSummaryWCPara = QtWidgets.QLabel(self.tabSummaryPage2) self.lblSummaryWCPara = QtWidgets.QLabel(self.tabSummaryPage2)
@ -227,14 +224,13 @@ class Ui_MainWindow(object):
self.tabSummaryPage3 = QtWidgets.QWidget() self.tabSummaryPage3 = QtWidgets.QWidget()
self.tabSummaryPage3.setObjectName("tabSummaryPage3") self.tabSummaryPage3.setObjectName("tabSummaryPage3")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.tabSummaryPage3) self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.tabSummaryPage3)
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_7.setObjectName("horizontalLayout_7") self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.verticalLayout_6 = QtWidgets.QVBoxLayout() self.verticalLayout_6 = QtWidgets.QVBoxLayout()
self.verticalLayout_6.setObjectName("verticalLayout_6") self.verticalLayout_6.setObjectName("verticalLayout_6")
self.label_22 = QtWidgets.QLabel(self.tabSummaryPage3) self.label_22 = QtWidgets.QLabel(self.tabSummaryPage3)
self.label_22.setObjectName("label_22") self.label_22.setObjectName("label_22")
self.verticalLayout_6.addWidget(self.label_22) self.verticalLayout_6.addWidget(self.label_22)
self.txtSummaryPara_2 = textEditView(self.tabSummaryPage3) self.txtSummaryPara_2 = MDEditCompleter(self.tabSummaryPage3)
self.txtSummaryPara_2.setReadOnly(True) self.txtSummaryPara_2.setReadOnly(True)
self.txtSummaryPara_2.setObjectName("txtSummaryPara_2") self.txtSummaryPara_2.setObjectName("txtSummaryPara_2")
self.verticalLayout_6.addWidget(self.txtSummaryPara_2) self.verticalLayout_6.addWidget(self.txtSummaryPara_2)
@ -251,7 +247,7 @@ class Ui_MainWindow(object):
self.label_17 = QtWidgets.QLabel(self.tabSummaryPage3) self.label_17 = QtWidgets.QLabel(self.tabSummaryPage3)
self.label_17.setObjectName("label_17") self.label_17.setObjectName("label_17")
self.verticalLayout_3.addWidget(self.label_17) self.verticalLayout_3.addWidget(self.label_17)
self.txtSummaryPage = textEditView(self.tabSummaryPage3) self.txtSummaryPage = MDEditCompleter(self.tabSummaryPage3)
self.txtSummaryPage.setObjectName("txtSummaryPage") self.txtSummaryPage.setObjectName("txtSummaryPage")
self.verticalLayout_3.addWidget(self.txtSummaryPage) self.verticalLayout_3.addWidget(self.txtSummaryPage)
self.lblSummaryWCPage = QtWidgets.QLabel(self.tabSummaryPage3) self.lblSummaryWCPage = QtWidgets.QLabel(self.tabSummaryPage3)
@ -263,14 +259,13 @@ class Ui_MainWindow(object):
self.tabSummaryPage4 = QtWidgets.QWidget() self.tabSummaryPage4 = QtWidgets.QWidget()
self.tabSummaryPage4.setObjectName("tabSummaryPage4") self.tabSummaryPage4.setObjectName("tabSummaryPage4")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.tabSummaryPage4) self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.tabSummaryPage4)
self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7 = QtWidgets.QVBoxLayout()
self.verticalLayout_7.setObjectName("verticalLayout_7") self.verticalLayout_7.setObjectName("verticalLayout_7")
self.label_23 = QtWidgets.QLabel(self.tabSummaryPage4) self.label_23 = QtWidgets.QLabel(self.tabSummaryPage4)
self.label_23.setObjectName("label_23") self.label_23.setObjectName("label_23")
self.verticalLayout_7.addWidget(self.label_23) self.verticalLayout_7.addWidget(self.label_23)
self.txtSummaryPage_2 = textEditView(self.tabSummaryPage4) self.txtSummaryPage_2 = MDEditCompleter(self.tabSummaryPage4)
self.txtSummaryPage_2.setReadOnly(True) self.txtSummaryPage_2.setReadOnly(True)
self.txtSummaryPage_2.setObjectName("txtSummaryPage_2") self.txtSummaryPage_2.setObjectName("txtSummaryPage_2")
self.verticalLayout_7.addWidget(self.txtSummaryPage_2) self.verticalLayout_7.addWidget(self.txtSummaryPage_2)
@ -285,7 +280,7 @@ class Ui_MainWindow(object):
self.label_20 = QtWidgets.QLabel(self.tabSummaryPage4) self.label_20 = QtWidgets.QLabel(self.tabSummaryPage4)
self.label_20.setObjectName("label_20") self.label_20.setObjectName("label_20")
self.verticalLayout_4.addWidget(self.label_20) self.verticalLayout_4.addWidget(self.label_20)
self.txtSummaryFull = textEditView(self.tabSummaryPage4) self.txtSummaryFull = MDEditCompleter(self.tabSummaryPage4)
self.txtSummaryFull.setObjectName("txtSummaryFull") self.txtSummaryFull.setObjectName("txtSummaryFull")
self.verticalLayout_4.addWidget(self.txtSummaryFull) self.verticalLayout_4.addWidget(self.txtSummaryFull)
self.lblSummaryWCFull = QtWidgets.QLabel(self.tabSummaryPage4) self.lblSummaryWCFull = QtWidgets.QLabel(self.tabSummaryPage4)
@ -387,42 +382,41 @@ class Ui_MainWindow(object):
self.scrollAreaPersoInfosWidget.setObjectName("scrollAreaPersoInfosWidget") self.scrollAreaPersoInfosWidget.setObjectName("scrollAreaPersoInfosWidget")
self.formLayout_8 = QtWidgets.QFormLayout(self.scrollAreaPersoInfosWidget) self.formLayout_8 = QtWidgets.QFormLayout(self.scrollAreaPersoInfosWidget)
self.formLayout_8.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_8.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
self.formLayout_8.setContentsMargins(0, 0, 0, 0)
self.formLayout_8.setObjectName("formLayout_8") self.formLayout_8.setObjectName("formLayout_8")
self.label_4 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_4 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_4.setObjectName("label_4") self.label_4.setObjectName("label_4")
self.formLayout_8.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4) self.formLayout_8.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.txtPersoMotivation = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoMotivation = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoMotivation.setObjectName("txtPersoMotivation") self.txtPersoMotivation.setObjectName("txtPersoMotivation")
self.formLayout_8.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.txtPersoMotivation) self.formLayout_8.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.txtPersoMotivation)
self.label_5 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_5 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_5.setObjectName("label_5") self.label_5.setObjectName("label_5")
self.formLayout_8.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5) self.formLayout_8.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.txtPersoGoal = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoGoal = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoGoal.setObjectName("txtPersoGoal") self.txtPersoGoal.setObjectName("txtPersoGoal")
self.formLayout_8.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.txtPersoGoal) self.formLayout_8.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.txtPersoGoal)
self.label_6 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_6 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_6.setObjectName("label_6") self.label_6.setObjectName("label_6")
self.formLayout_8.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6) self.formLayout_8.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.txtPersoConflict = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoConflict = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoConflict.setObjectName("txtPersoConflict") self.txtPersoConflict.setObjectName("txtPersoConflict")
self.formLayout_8.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.txtPersoConflict) self.formLayout_8.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.txtPersoConflict)
self.label_7 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_7 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_7.setObjectName("label_7") self.label_7.setObjectName("label_7")
self.formLayout_8.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7) self.formLayout_8.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
self.txtPersoEpiphany = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoEpiphany = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoEpiphany.setObjectName("txtPersoEpiphany") self.txtPersoEpiphany.setObjectName("txtPersoEpiphany")
self.formLayout_8.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.txtPersoEpiphany) self.formLayout_8.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.txtPersoEpiphany)
self.label_24 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_24 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_24.setObjectName("label_24") self.label_24.setObjectName("label_24")
self.formLayout_8.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_24) self.formLayout_8.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_24)
self.txtPersoSummarySentence = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoSummarySentence = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoSummarySentence.setObjectName("txtPersoSummarySentence") self.txtPersoSummarySentence.setObjectName("txtPersoSummarySentence")
self.formLayout_8.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.txtPersoSummarySentence) self.formLayout_8.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.txtPersoSummarySentence)
self.label_8 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget) self.label_8 = QtWidgets.QLabel(self.scrollAreaPersoInfosWidget)
self.label_8.setObjectName("label_8") self.label_8.setObjectName("label_8")
self.formLayout_8.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_8) self.formLayout_8.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_8)
self.txtPersoSummaryPara = textEditView(self.scrollAreaPersoInfosWidget) self.txtPersoSummaryPara = MDEditCompleter(self.scrollAreaPersoInfosWidget)
self.txtPersoSummaryPara.setObjectName("txtPersoSummaryPara") self.txtPersoSummaryPara.setObjectName("txtPersoSummaryPara")
self.formLayout_8.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.txtPersoSummaryPara) self.formLayout_8.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.txtPersoSummaryPara)
self.horizontalLayout_21 = QtWidgets.QHBoxLayout() self.horizontalLayout_21 = QtWidgets.QHBoxLayout()
@ -467,7 +461,7 @@ class Ui_MainWindow(object):
self.tab_11.setObjectName("tab_11") self.tab_11.setObjectName("tab_11")
self.verticalLayout_17 = QtWidgets.QVBoxLayout(self.tab_11) self.verticalLayout_17 = QtWidgets.QVBoxLayout(self.tab_11)
self.verticalLayout_17.setObjectName("verticalLayout_17") self.verticalLayout_17.setObjectName("verticalLayout_17")
self.txtPersoSummaryFull = textEditView(self.tab_11) self.txtPersoSummaryFull = MDEditCompleter(self.tab_11)
self.txtPersoSummaryFull.setObjectName("txtPersoSummaryFull") self.txtPersoSummaryFull.setObjectName("txtPersoSummaryFull")
self.verticalLayout_17.addWidget(self.txtPersoSummaryFull) self.verticalLayout_17.addWidget(self.txtPersoSummaryFull)
self.horizontalLayout_22 = QtWidgets.QHBoxLayout() self.horizontalLayout_22 = QtWidgets.QHBoxLayout()
@ -485,7 +479,7 @@ class Ui_MainWindow(object):
self.tab_19.setObjectName("tab_19") self.tab_19.setObjectName("tab_19")
self.horizontalLayout_30 = QtWidgets.QHBoxLayout(self.tab_19) self.horizontalLayout_30 = QtWidgets.QHBoxLayout(self.tab_19)
self.horizontalLayout_30.setObjectName("horizontalLayout_30") self.horizontalLayout_30.setObjectName("horizontalLayout_30")
self.txtPersoNotes = textEditView(self.tab_19) self.txtPersoNotes = MDEditCompleter(self.tab_19)
self.txtPersoNotes.setObjectName("txtPersoNotes") self.txtPersoNotes.setObjectName("txtPersoNotes")
self.horizontalLayout_30.addWidget(self.txtPersoNotes) self.horizontalLayout_30.addWidget(self.txtPersoNotes)
self.tabPersos.addTab(self.tab_19, "") self.tabPersos.addTab(self.tab_19, "")
@ -632,10 +626,10 @@ class Ui_MainWindow(object):
self.sldPlotImportance.setSizePolicy(sizePolicy) self.sldPlotImportance.setSizePolicy(sizePolicy)
self.sldPlotImportance.setObjectName("sldPlotImportance") self.sldPlotImportance.setObjectName("sldPlotImportance")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.sldPlotImportance) self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.sldPlotImportance)
self.txtPlotDescription = textEditView(self.infos_2) self.txtPlotDescription = MDEditCompleter(self.infos_2)
self.txtPlotDescription.setObjectName("txtPlotDescription") self.txtPlotDescription.setObjectName("txtPlotDescription")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.txtPlotDescription) self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.txtPlotDescription)
self.txtPlotResult = textEditView(self.infos_2) self.txtPlotResult = MDEditCompleter(self.infos_2)
self.txtPlotResult.setObjectName("txtPlotResult") self.txtPlotResult.setObjectName("txtPlotResult")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.txtPlotResult) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.txtPlotResult)
self.tabPlot.addTab(self.infos_2, "") self.tabPlot.addTab(self.infos_2, "")
@ -654,7 +648,7 @@ class Ui_MainWindow(object):
self.grpSubPlotSummary.setObjectName("grpSubPlotSummary") self.grpSubPlotSummary.setObjectName("grpSubPlotSummary")
self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.grpSubPlotSummary) self.verticalLayout_11 = QtWidgets.QVBoxLayout(self.grpSubPlotSummary)
self.verticalLayout_11.setObjectName("verticalLayout_11") self.verticalLayout_11.setObjectName("verticalLayout_11")
self.txtSubPlotSummary = textEditView(self.grpSubPlotSummary) self.txtSubPlotSummary = MDEditCompleter(self.grpSubPlotSummary)
self.txtSubPlotSummary.setObjectName("txtSubPlotSummary") self.txtSubPlotSummary.setObjectName("txtSubPlotSummary")
self.verticalLayout_11.addWidget(self.txtSubPlotSummary) self.verticalLayout_11.addWidget(self.txtSubPlotSummary)
self.verticalLayout_28.addWidget(self.grpSubPlotSummary) self.verticalLayout_28.addWidget(self.grpSubPlotSummary)
@ -703,27 +697,24 @@ class Ui_MainWindow(object):
self.page = QtWidgets.QWidget() self.page = QtWidgets.QWidget()
self.page.setObjectName("page") self.page.setObjectName("page")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.page) self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.page)
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.txtPlotSummaryPara = textEditView(self.page) self.txtPlotSummaryPara = MDEditCompleter(self.page)
self.txtPlotSummaryPara.setObjectName("txtPlotSummaryPara") self.txtPlotSummaryPara.setObjectName("txtPlotSummaryPara")
self.horizontalLayout_6.addWidget(self.txtPlotSummaryPara) self.horizontalLayout_6.addWidget(self.txtPlotSummaryPara)
self.stkPlotSummary.addWidget(self.page) self.stkPlotSummary.addWidget(self.page)
self.page_2 = QtWidgets.QWidget() self.page_2 = QtWidgets.QWidget()
self.page_2.setObjectName("page_2") self.page_2.setObjectName("page_2")
self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.page_2) self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.page_2)
self.horizontalLayout_10.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_10.setObjectName("horizontalLayout_10") self.horizontalLayout_10.setObjectName("horizontalLayout_10")
self.txtPlotSummaryPage = textEditView(self.page_2) self.txtPlotSummaryPage = MDEditCompleter(self.page_2)
self.txtPlotSummaryPage.setObjectName("txtPlotSummaryPage") self.txtPlotSummaryPage.setObjectName("txtPlotSummaryPage")
self.horizontalLayout_10.addWidget(self.txtPlotSummaryPage) self.horizontalLayout_10.addWidget(self.txtPlotSummaryPage)
self.stkPlotSummary.addWidget(self.page_2) self.stkPlotSummary.addWidget(self.page_2)
self.page_3 = QtWidgets.QWidget() self.page_3 = QtWidgets.QWidget()
self.page_3.setObjectName("page_3") self.page_3.setObjectName("page_3")
self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.page_3) self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.page_3)
self.horizontalLayout_13.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_13.setObjectName("horizontalLayout_13") self.horizontalLayout_13.setObjectName("horizontalLayout_13")
self.txtPlotSummaryFull = textEditView(self.page_3) self.txtPlotSummaryFull = MDEditCompleter(self.page_3)
self.txtPlotSummaryFull.setObjectName("txtPlotSummaryFull") self.txtPlotSummaryFull.setObjectName("txtPlotSummaryFull")
self.horizontalLayout_13.addWidget(self.txtPlotSummaryFull) self.horizontalLayout_13.addWidget(self.txtPlotSummaryFull)
self.stkPlotSummary.addWidget(self.page_3) self.stkPlotSummary.addWidget(self.page_3)
@ -798,7 +789,7 @@ class Ui_MainWindow(object):
self.label_32 = QtWidgets.QLabel(self.tab_3) self.label_32 = QtWidgets.QLabel(self.tab_3)
self.label_32.setObjectName("label_32") self.label_32.setObjectName("label_32")
self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_32) self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_32)
self.txtWorldDescription = textEditCompleter(self.tab_3) self.txtWorldDescription = MDEditCompleter(self.tab_3)
self.txtWorldDescription.setObjectName("txtWorldDescription") self.txtWorldDescription.setObjectName("txtWorldDescription")
self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txtWorldDescription) self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txtWorldDescription)
self.tabWorld.addTab(self.tab_3, "") self.tabWorld.addTab(self.tab_3, "")
@ -810,13 +801,13 @@ class Ui_MainWindow(object):
self.label_33 = QtWidgets.QLabel(self.tab_4) self.label_33 = QtWidgets.QLabel(self.tab_4)
self.label_33.setObjectName("label_33") self.label_33.setObjectName("label_33")
self.formLayout_7.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_33) self.formLayout_7.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_33)
self.txtWorldPassion = textEditCompleter(self.tab_4) self.txtWorldPassion = MDEditCompleter(self.tab_4)
self.txtWorldPassion.setObjectName("txtWorldPassion") self.txtWorldPassion.setObjectName("txtWorldPassion")
self.formLayout_7.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.txtWorldPassion) self.formLayout_7.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.txtWorldPassion)
self.label_34 = QtWidgets.QLabel(self.tab_4) self.label_34 = QtWidgets.QLabel(self.tab_4)
self.label_34.setObjectName("label_34") self.label_34.setObjectName("label_34")
self.formLayout_7.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_34) self.formLayout_7.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_34)
self.txtWorldConflict = textEditCompleter(self.tab_4) self.txtWorldConflict = MDEditCompleter(self.tab_4)
self.txtWorldConflict.setObjectName("txtWorldConflict") self.txtWorldConflict.setObjectName("txtWorldConflict")
self.formLayout_7.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txtWorldConflict) self.formLayout_7.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txtWorldConflict)
self.tabWorld.addTab(self.tab_4, "") self.tabWorld.addTab(self.tab_4, "")
@ -839,7 +830,6 @@ class Ui_MainWindow(object):
self.layoutWidget = QtWidgets.QWidget(self.splitterOutlineH) self.layoutWidget = QtWidgets.QWidget(self.splitterOutlineH)
self.layoutWidget.setObjectName("layoutWidget") self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout_14.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_14.setObjectName("verticalLayout_14") self.verticalLayout_14.setObjectName("verticalLayout_14")
self.splitterOutlineV = QtWidgets.QSplitter(self.layoutWidget) self.splitterOutlineV = QtWidgets.QSplitter(self.layoutWidget)
self.splitterOutlineV.setOrientation(QtCore.Qt.Vertical) self.splitterOutlineV.setOrientation(QtCore.Qt.Vertical)
@ -1265,8 +1255,8 @@ class Ui_MainWindow(object):
self.stack.setCurrentIndex(1) self.stack.setCurrentIndex(1)
self.tabMain.setCurrentIndex(3) self.tabMain.setCurrentIndex(3)
self.tabSummary.setCurrentIndex(0) self.tabSummary.setCurrentIndex(0)
self.tabPersos.setCurrentIndex(0) self.tabPersos.setCurrentIndex(2)
self.tabPlot.setCurrentIndex(0) self.tabPlot.setCurrentIndex(1)
self.comboBox_2.setCurrentIndex(0) self.comboBox_2.setCurrentIndex(0)
self.stkPlotSummary.setCurrentIndex(0) self.stkPlotSummary.setCurrentIndex(0)
self.tabWorld.setCurrentIndex(0) self.tabWorld.setCurrentIndex(0)
@ -1432,6 +1422,7 @@ class Ui_MainWindow(object):
from manuskript.ui.cheatSheet import cheatSheet from manuskript.ui.cheatSheet import cheatSheet
from manuskript.ui.editors.mainEditor import mainEditor from manuskript.ui.editors.mainEditor import mainEditor
from manuskript.ui.search import search from manuskript.ui.search import search
from manuskript.ui.views.MDEditCompleter import MDEditCompleter
from manuskript.ui.views.basicItemView import basicItemView from manuskript.ui.views.basicItemView import basicItemView
from manuskript.ui.views.characterTreeView import characterTreeView from manuskript.ui.views.characterTreeView import characterTreeView
from manuskript.ui.views.lineEditView import lineEditView from manuskript.ui.views.lineEditView import lineEditView
@ -1440,7 +1431,5 @@ from manuskript.ui.views.outlineView import outlineView
from manuskript.ui.views.plotTreeView import plotTreeView from manuskript.ui.views.plotTreeView import plotTreeView
from manuskript.ui.views.sldImportance import sldImportance from manuskript.ui.views.sldImportance import sldImportance
from manuskript.ui.views.storylineView import storylineView from manuskript.ui.views.storylineView import storylineView
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.treeView import treeView from manuskript.ui.views.treeView import treeView
from manuskript.ui.welcome import welcome from manuskript.ui.welcome import welcome

View file

@ -379,7 +379,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummarySentence"> <widget class="MDEditCompleter" name="txtSummarySentence">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -422,7 +422,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummarySentence_2"> <widget class="MDEditCompleter" name="txtSummarySentence_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -466,7 +466,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryPara"/> <widget class="MDEditCompleter" name="txtSummaryPara"/>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblSummaryWCPara"> <widget class="QLabel" name="lblSummaryWCPara">
@ -504,7 +504,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryPara_2"> <widget class="MDEditCompleter" name="txtSummaryPara_2">
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -542,7 +542,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryPage"/> <widget class="MDEditCompleter" name="txtSummaryPage"/>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblSummaryWCPage"> <widget class="QLabel" name="lblSummaryWCPage">
@ -567,7 +567,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryPage_2"> <widget class="MDEditCompleter" name="txtSummaryPage_2">
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -592,7 +592,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryFull"/> <widget class="MDEditCompleter" name="txtSummaryFull"/>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblSummaryWCFull"> <widget class="QLabel" name="lblSummaryWCFull">
@ -774,7 +774,7 @@
</widget> </widget>
<widget class="QTabWidget" name="tabPersos"> <widget class="QTabWidget" name="tabPersos">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>2</number>
</property> </property>
<widget class="QWidget" name="info"> <widget class="QWidget" name="info">
<attribute name="title"> <attribute name="title">
@ -831,7 +831,7 @@
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="textEditView" name="txtPersoMotivation"/> <widget class="MDEditCompleter" name="txtPersoMotivation"/>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
@ -841,7 +841,7 @@
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="textEditView" name="txtPersoGoal"/> <widget class="MDEditCompleter" name="txtPersoGoal"/>
</item> </item>
<item row="6" column="0"> <item row="6" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
@ -851,7 +851,7 @@
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
<widget class="textEditView" name="txtPersoConflict"/> <widget class="MDEditCompleter" name="txtPersoConflict"/>
</item> </item>
<item row="7" column="0"> <item row="7" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
@ -861,7 +861,7 @@
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="7" column="1">
<widget class="textEditView" name="txtPersoEpiphany"/> <widget class="MDEditCompleter" name="txtPersoEpiphany"/>
</item> </item>
<item row="8" column="0"> <item row="8" column="0">
<widget class="QLabel" name="label_24"> <widget class="QLabel" name="label_24">
@ -871,7 +871,7 @@
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="8" column="1">
<widget class="textEditView" name="txtPersoSummarySentence"/> <widget class="MDEditCompleter" name="txtPersoSummarySentence"/>
</item> </item>
<item row="9" column="0"> <item row="9" column="0">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
@ -881,7 +881,7 @@
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="9" column="1">
<widget class="textEditView" name="txtPersoSummaryPara"/> <widget class="MDEditCompleter" name="txtPersoSummaryPara"/>
</item> </item>
<item row="10" column="1"> <item row="10" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_21"> <layout class="QHBoxLayout" name="horizontalLayout_21">
@ -964,7 +964,7 @@
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_17"> <layout class="QVBoxLayout" name="verticalLayout_17">
<item> <item>
<widget class="textEditView" name="txtPersoSummaryFull"/> <widget class="MDEditCompleter" name="txtPersoSummaryFull"/>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_22"> <layout class="QHBoxLayout" name="horizontalLayout_22">
@ -1002,7 +1002,7 @@
</attribute> </attribute>
<layout class="QHBoxLayout" name="horizontalLayout_30"> <layout class="QHBoxLayout" name="horizontalLayout_30">
<item> <item>
<widget class="textEditView" name="txtPersoNotes"/> <widget class="MDEditCompleter" name="txtPersoNotes"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1173,7 +1173,7 @@
</widget> </widget>
<widget class="QTabWidget" name="tabPlot"> <widget class="QTabWidget" name="tabPlot">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<property name="documentMode"> <property name="documentMode">
<bool>true</bool> <bool>true</bool>
@ -1303,10 +1303,10 @@
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="textEditView" name="txtPlotDescription"/> <widget class="MDEditCompleter" name="txtPlotDescription"/>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="textEditView" name="txtPlotResult"/> <widget class="MDEditCompleter" name="txtPlotResult"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1338,7 +1338,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_11">
<item> <item>
<widget class="textEditView" name="txtSubPlotSummary"/> <widget class="MDEditCompleter" name="txtSubPlotSummary"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1461,21 +1461,21 @@
<widget class="QWidget" name="page"> <widget class="QWidget" name="page">
<layout class="QHBoxLayout" name="horizontalLayout_6"> <layout class="QHBoxLayout" name="horizontalLayout_6">
<item> <item>
<widget class="textEditView" name="txtPlotSummaryPara"/> <widget class="MDEditCompleter" name="txtPlotSummaryPara"/>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_2"> <widget class="QWidget" name="page_2">
<layout class="QHBoxLayout" name="horizontalLayout_10"> <layout class="QHBoxLayout" name="horizontalLayout_10">
<item> <item>
<widget class="textEditView" name="txtPlotSummaryPage"/> <widget class="MDEditCompleter" name="txtPlotSummaryPage"/>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_3"> <widget class="QWidget" name="page_3">
<layout class="QHBoxLayout" name="horizontalLayout_13"> <layout class="QHBoxLayout" name="horizontalLayout_13">
<item> <item>
<widget class="textEditView" name="txtPlotSummaryFull"/> <widget class="MDEditCompleter" name="txtPlotSummaryFull"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1645,7 +1645,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="textEditCompleter" name="txtWorldDescription"/> <widget class="MDEditCompleter" name="txtWorldDescription"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1665,7 +1665,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="textEditCompleter" name="txtWorldPassion"/> <widget class="MDEditCompleter" name="txtWorldPassion"/>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_34"> <widget class="QLabel" name="label_34">
@ -1675,7 +1675,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="textEditCompleter" name="txtWorldConflict"/> <widget class="MDEditCompleter" name="txtWorldConflict"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -2616,6 +2616,11 @@
<extends>QTextEdit</extends> <extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditView.h</header> <header>manuskript.ui.views.textEditView.h</header>
</customwidget> </customwidget>
<customwidget>
<class>MDEditCompleter</class>
<extends>QTextEdit</extends>
<header>manuskript.ui.views.MDEditCompleter.h</header>
</customwidget>
<customwidget> <customwidget>
<class>lineEditView</class> <class>lineEditView</class>
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
@ -2683,11 +2688,6 @@
<header>manuskript.ui.search.h</header> <header>manuskript.ui.search.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>textEditCompleter</class>
<extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditCompleter.h</header>
</customwidget>
<customwidget> <customwidget>
<class>storylineView</class> <class>storylineView</class>
<extends>QWidget</extends> <extends>QWidget</extends>

View file

@ -24,11 +24,13 @@ button = p.color(QPalette.Button).name() # Button background
buttonText = p.color(QPalette.ButtonText).name() # Button Text buttonText = p.color(QPalette.ButtonText).name() # Button Text
highlight = p.color(QPalette.Highlight).name() # Other background highlight = p.color(QPalette.Highlight).name() # Other background
highlightedText = p.color(QPalette.HighlightedText).name() # Base Text highlightedText = p.color(QPalette.HighlightedText).name() # Base Text
link = p.color(QPalette.Link).name() # Link
linkVisited = p.color(QPalette.LinkVisited).name() # Link visited
light = p.color(QPalette.Light).name() # Lighter than Button color light = p.color(QPalette.Light).name() # Lighter than Button color
midlight = p.color(QPalette.Midlight).name() # Between Button and Light midlight = p.color(QPalette.Midlight).name() # Between Button and Light
dark = p.color(QPalette.Dark).name() # Darker than Button
mid = p.color(QPalette.Mid).name() # Between Button and Dark mid = p.color(QPalette.Mid).name() # Between Button and Dark
dark = p.color(QPalette.Dark).name() # Darker than Button
shadow = p.color(QPalette.Shadow).name() # A very dark color shadow = p.color(QPalette.Shadow).name() # A very dark color
highlightLight = F.mixColors(highlight, window, .3) highlightLight = F.mixColors(highlight, window, .3)

View file

@ -7,7 +7,7 @@ from PyQt5.QtGui import QTextCursor, QFont, QFontMetrics
from PyQt5.QtWidgets import QAction, qApp, QToolTip, QTextEdit from PyQt5.QtWidgets import QAction, qApp, QToolTip, QTextEdit
from manuskript.ui.editors.completer import completer from manuskript.ui.editors.completer import completer
from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.MDEditView import MDEditView
from manuskript.models import references as Ref from manuskript.models import references as Ref
try: try:
@ -16,10 +16,10 @@ except ImportError:
enchant = None enchant = None
class textEditCompleter(textEditView): class MDEditCompleter(MDEditView):
def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="", def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="",
autoResize=False): autoResize=False):
textEditView.__init__(self, parent=parent, index=index, html=html, spellcheck=spellcheck, highlighting=True, MDEditView.__init__(self, parent=parent, index=index, html=html, spellcheck=spellcheck, highlighting=True,
dict=dict, autoResize=autoResize) dict=dict, autoResize=autoResize)
self.completer = None self.completer = None
@ -30,7 +30,7 @@ class textEditCompleter(textEditView):
self.document().documentLayoutChanged.connect(self.getRefRects) self.document().documentLayoutChanged.connect(self.getRefRects)
def setCurrentModelIndex(self, index): def setCurrentModelIndex(self, index):
textEditView.setCurrentModelIndex(self, index) MDEditView.setCurrentModelIndex(self, index)
if self._index and not self.completer: if self._index and not self.completer:
self.setCompleter(completer()) self.setCompleter(completer())
@ -69,10 +69,10 @@ class textEditCompleter(textEditView):
# else: # else:
# QToolTip.hideText() # QToolTip.hideText()
# return True # return True
# return textEditView.event(self, event) # return MDEditView.event(self, event)
def createStandardContextMenu(self): def createStandardContextMenu(self):
menu = textEditView.createStandardContextMenu(self) menu = MDEditView.createStandardContextMenu(self)
a = QAction(self.tr("Insert reference"), menu) a = QAction(self.tr("Insert reference"), menu)
a.triggered.connect(self.popupCompleter) a.triggered.connect(self.popupCompleter)
@ -96,7 +96,7 @@ class textEditCompleter(textEditView):
if not self.completer or not isShortcut: if not self.completer or not isShortcut:
self.completer.setVisible(False) self.completer.setVisible(False)
textEditView.keyPressEvent(self, event) MDEditView.keyPressEvent(self, event)
return return
self.popupCompleter() self.popupCompleter()
@ -110,7 +110,7 @@ class textEditCompleter(textEditView):
self.completer.popup(self.textUnderCursor(select=True)) self.completer.popup(self.textUnderCursor(select=True))
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
textEditView.mouseMoveEvent(self, event) MDEditView.mouseMoveEvent(self, event)
onRef = [r for r in self.refRects if r.contains(event.pos())] onRef = [r for r in self.refRects if r.contains(event.pos())]
@ -127,7 +127,7 @@ class textEditCompleter(textEditView):
QToolTip.showText(self.mapToGlobal(event.pos()), Ref.tooltip(ref)) QToolTip.showText(self.mapToGlobal(event.pos()), Ref.tooltip(ref))
def mouseReleaseEvent(self, event): def mouseReleaseEvent(self, event):
textEditView.mouseReleaseEvent(self, event) MDEditView.mouseReleaseEvent(self, event)
onRef = [r for r in self.refRects if r.contains(event.pos())] onRef = [r for r in self.refRects if r.contains(event.pos())]
if onRef: if onRef:
cursor = self.cursorForPosition(event.pos()) cursor = self.cursorForPosition(event.pos())
@ -137,7 +137,7 @@ class textEditCompleter(textEditView):
qApp.restoreOverrideCursor() qApp.restoreOverrideCursor()
def resizeEvent(self, event): def resizeEvent(self, event):
textEditView.resizeEvent(self, event) MDEditView.resizeEvent(self, event)
self.getRefRects() self.getRefRects()
def getRefRects(self): def getRefRects(self):

View file

@ -0,0 +1,274 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
import re
from PyQt5.QtCore import QRegExp, Qt
from PyQt5.QtGui import QTextCursor
# from PyQt5.QtWidgets import
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.highlighters import MarkdownHighlighter
# from manuskript.ui.editors.textFormat import textFormat
# from manuskript.ui.editors.MDFunctions import MDFormatSelection
class MDEditView(textEditView):
def __init__(self, parent=None, index=None, html=None, spellcheck=True,
highlighting=False, dict="", autoResize=False):
textEditView.__init__(self, parent, index, html, spellcheck,
highlighting=True, dict=dict,
autoResize=autoResize)
# Highlighter
self._textFormat = "md"
self._highlighterClass = MarkdownHighlighter
if index:
# We have to setup things anew, for the highlighter notably
self.setCurrentModelIndex(index)
# 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)
###########################################################################
# FORMATTING (#FIXME)
###########################################################################
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 selectWord(self, cursor):
if cursor.selectedText():
return
end = cursor.selectionEnd()
cursor.movePosition(QTextCursor.StartOfWord)
cursor.setPosition(end, QTextCursor.KeepAnchor)
cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
def selectBlock(self, cursor):
cursor.movePosition(QTextCursor.StartOfBlock)
cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
def comment(self):
cursor = self.textCursor()
# Select begining and end of words
self.selectWord(cursor)
if cursor.hasSelection():
text = cursor.selectedText()
cursor.insertText("<!-- " + text + " -->")
else:
cursor.insertText("<!-- -->")
cursor.movePosition(QTextCursor.PreviousCharacter,
QTextCursor.MoveAnchor, 4)
self.setTextCursor(cursor)
def commentLine(self):
cursor = self.textCursor()
start = cursor.selectionStart()
end = cursor.selectionEnd()
block = self.document().findBlock(start)
block2 = self.document().findBlock(end)
if True:
# Method 1
cursor.beginEditBlock()
while block.isValid():
self.commentBlock(block)
if block == block2: break
block = block.next()
cursor.endEditBlock()
else:
# Method 2
cursor.beginEditBlock()
cursor.setPosition(block.position())
cursor.insertText("<!--\n")
cursor.setPosition(block2.position() + block2.length() - 1)
cursor.insertText("\n-->")
cursor.endEditBlock()
def commentBlock(self, block):
cursor = QTextCursor(block)
text = block.text()
if text[:5] == "<!-- " and \
text[-4:] == " -->":
text2 = text[5:-4]
else:
text2 = "<!-- " + text + " -->"
self.selectBlock(cursor)
cursor.insertText(text2)
def insertFormattingMarkup(self, markup):
cursor = self.textCursor()
# Select begining and end of words
self.selectWord(cursor)
if cursor.hasSelection():
start = cursor.selectionStart()
end = cursor.selectionEnd() + len(markup)
cursor.beginEditBlock()
cursor.setPosition(start)
cursor.insertText(markup)
cursor.setPosition(end)
cursor.insertText(markup)
cursor.endEditBlock()
cursor.movePosition(QTextCursor.PreviousCharacter,
QTextCursor.KeepAnchor, len(markup))
#self.setTextCursor(cursor)
else:
# Insert markup twice (for opening and closing around the cursor),
# and then move the cursor to be between the pair.
cursor.beginEditBlock()
cursor.insertText(markup)
cursor.insertText(markup)
cursor.movePosition(QTextCursor.PreviousCharacter,
QTextCursor.MoveAnchor, len(markup))
cursor.endEditBlock()
self.setTextCursor(cursor)
def clearFormat(self):
cursor = self.textCursor()
text = cursor.selectedText()
if not text:
self.selectBlock(cursor)
text = cursor.selectedText()
text = self.clearedFormat(text)
cursor.insertText(text)
def clearedFormat(self, text):
# FIXME: clear also block formats
for reg, rep, flags in [
("\*\*(.*?)\*\*", "\\1", None), # bold
("__(.*?)__", "\\1", None), # bold
("\*(.*?)\*", "\\1", None), # emphasis
("_(.*?)_", "\\1", None), # emphasis
("`(.*?)`", "\\1", None), # verbatim
("~~(.*?)~~", "\\1", None), # strike
("\^(.*?)\^", "\\1", None), # superscript
("~(.*?)~", "\\1", None), # subscript
("<!--(.*)-->", "\\1", re.S), # comments
# LINES OR BLOCKS
(r"^#*\s*(.+?)\s*", "\\1", re.M), # ATX
(r"^[=-]*$", "", re.M), # Setext
(r"^`*$", "", re.M), # Code block fenced
(r"^\s*[-+*]\s*(.*?)\s*$", "\\1", re.M), # Bullet List
(r"^\s*[0-9a-z](\.|\))\s*(.*?)\s*$", "\\2", re.M), # Bullet List
(r"\s*[>\s]*(.*?)\s*$", "\\1", re.M), # Code block and blockquote
]:
text = re.sub(reg, rep, text, flags if flags else 0)
return text
def clearedFormatForStats(self, text):
# Remove stuff that musn't be counted
# FIXME: clear also block formats
for reg, rep, flags in [
("<!--.*-->", "", re.S), # comments
]:
text = re.sub(reg, rep, text, flags if flags else 0)
return text
def titleSetext(self, level):
cursor = self.textCursor()
cursor.beginEditBlock()
# Is it already a Setext header?
if cursor.block().userState() in [
MS.MarkdownStateSetextHeading1Line2,
MS.MarkdownStateSetextHeading2Line2]:
cursor.movePosition(QTextCursor.PreviousBlock)
text = cursor.block().text()
if cursor.block().userState() in [
MS.MarkdownStateSetextHeading1Line1,
MS.MarkdownStateSetextHeading2Line1]:
# Need to remove line below
c = QTextCursor(cursor.block().next())
self.selectBlock(c)
c.insertText("")
char = "=" if level == 1 else "-"
text = re.sub("^#*\s*(.*)\s*#*", "\\1", text) # Removes #
sub = char * len(text)
text = text + "\n" + sub
self.selectBlock(cursor)
cursor.insertText(text)
cursor.endEditBlock()
def titleATX(self, level):
cursor = self.textCursor()
text = cursor.block().text()
# Are we in a Setext Header?
if cursor.block().userState() in [
MS.MarkdownStateSetextHeading1Line1,
MS.MarkdownStateSetextHeading2Line1]:
# Need to remove line below
cursor.beginEditBlock()
c = QTextCursor(cursor.block().next())
self.selectBlock(c)
c.insertText("")
self.selectBlock(cursor)
cursor.insertText(text)
cursor.endEditBlock()
return
elif cursor.block().userState() in [
MS.MarkdownStateSetextHeading1Line2,
MS.MarkdownStateSetextHeading2Line2]:
cursor.movePosition(QTextCursor.PreviousBlock)
self.setTextCursor(cursor)
self.titleATX(level)
return
m = re.match("^(#+)(\s*)(.+)", text)
if m:
pre = m.group(1)
space = m.group(2)
txt = m.group(3)
if len(pre) == level:
# Remove title
text = txt
else:
text = "#" * level + space + txt
else:
text = "#" * level + " " + text
self.selectBlock(cursor)
cursor.insertText(text)

View file

@ -2,8 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/views/basicItemView_ui.ui' # Form implementation generated from reading ui file 'manuskript/ui/views/basicItemView_ui.ui'
# #
# Created: Thu Mar 3 17:26:11 2016 # Created by: PyQt5 UI code generator 5.5.1
# by: PyQt5 UI code generator 5.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -51,7 +50,7 @@ class Ui_basicItemView(object):
self.label_9 = QtWidgets.QLabel(basicItemView) self.label_9 = QtWidgets.QLabel(basicItemView)
self.label_9.setObjectName("label_9") self.label_9.setObjectName("label_9")
self.verticalLayout.addWidget(self.label_9) self.verticalLayout.addWidget(self.label_9)
self.txtSummaryFull = textEditView(basicItemView) self.txtSummaryFull = MDEditCompleter(basicItemView)
self.txtSummaryFull.setObjectName("txtSummaryFull") self.txtSummaryFull.setObjectName("txtSummaryFull")
self.verticalLayout.addWidget(self.txtSummaryFull) self.verticalLayout.addWidget(self.txtSummaryFull)
@ -67,6 +66,6 @@ class Ui_basicItemView(object):
self.txtSummarySentence.setPlaceholderText(_translate("basicItemView", "One line summary")) self.txtSummarySentence.setPlaceholderText(_translate("basicItemView", "One line summary"))
self.label_9.setText(_translate("basicItemView", "Few sentences summary:")) self.label_9.setText(_translate("basicItemView", "Few sentences summary:"))
from manuskript.ui.views.MDEditCompleter import MDEditCompleter
from manuskript.ui.views.cmbOutlineCharacterChoser import cmbOutlineCharacterChoser from manuskript.ui.views.cmbOutlineCharacterChoser import cmbOutlineCharacterChoser
from manuskript.ui.views.lineEditView import lineEditView from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.views.textEditView import textEditView

View file

@ -101,15 +101,15 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryFull"/> <widget class="MDEditCompleter" name="txtSummaryFull"/>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>textEditView</class> <class>MDEditCompleter</class>
<extends>QTextEdit</extends> <extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditView.h</header> <header>manuskript.ui.views.MDEditCompleter.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>cmbOutlineCharacterChoser</class> <class>cmbOutlineCharacterChoser</class>

View file

@ -2,8 +2,7 @@
# Form implementation generated from reading ui file 'manuskript/ui/views/metadataView_ui.ui' # Form implementation generated from reading ui file 'manuskript/ui/views/metadataView_ui.ui'
# #
# Created: Fri Apr 8 14:24:47 2016 # Created by: PyQt5 UI code generator 5.5.1
# by: PyQt5 UI code generator 5.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -14,8 +13,8 @@ class Ui_metadataView(object):
metadataView.setObjectName("metadataView") metadataView.setObjectName("metadataView")
metadataView.resize(400, 537) metadataView.resize(400, 537)
self.verticalLayout = QtWidgets.QVBoxLayout(metadataView) self.verticalLayout = QtWidgets.QVBoxLayout(metadataView)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.grpProperties = collapsibleGroupBox2(metadataView) self.grpProperties = collapsibleGroupBox2(metadataView)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
@ -27,8 +26,8 @@ class Ui_metadataView(object):
self.grpProperties.setCheckable(True) self.grpProperties.setCheckable(True)
self.grpProperties.setObjectName("grpProperties") self.grpProperties.setObjectName("grpProperties")
self.verticalLayout_28 = QtWidgets.QVBoxLayout(self.grpProperties) self.verticalLayout_28 = QtWidgets.QVBoxLayout(self.grpProperties)
self.verticalLayout_28.setSpacing(0)
self.verticalLayout_28.setContentsMargins(0, 0, 0, 0) self.verticalLayout_28.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_28.setSpacing(0)
self.verticalLayout_28.setObjectName("verticalLayout_28") self.verticalLayout_28.setObjectName("verticalLayout_28")
self.properties = propertiesView(self.grpProperties) self.properties = propertiesView(self.grpProperties)
self.properties.setMinimumSize(QtCore.QSize(0, 50)) self.properties.setMinimumSize(QtCore.QSize(0, 50))
@ -40,8 +39,8 @@ class Ui_metadataView(object):
self.grpSummary.setCheckable(True) self.grpSummary.setCheckable(True)
self.grpSummary.setObjectName("grpSummary") self.grpSummary.setObjectName("grpSummary")
self.verticalLayout_22 = QtWidgets.QVBoxLayout(self.grpSummary) self.verticalLayout_22 = QtWidgets.QVBoxLayout(self.grpSummary)
self.verticalLayout_22.setSpacing(0)
self.verticalLayout_22.setContentsMargins(0, 0, 0, 0) self.verticalLayout_22.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_22.setSpacing(0)
self.verticalLayout_22.setObjectName("verticalLayout_22") self.verticalLayout_22.setObjectName("verticalLayout_22")
self.txtSummarySentence = lineEditView(self.grpSummary) self.txtSummarySentence = lineEditView(self.grpSummary)
self.txtSummarySentence.setInputMask("") self.txtSummarySentence.setInputMask("")
@ -53,10 +52,9 @@ class Ui_metadataView(object):
self.line.setLineWidth(0) self.line.setLineWidth(0)
self.line.setMidLineWidth(0) self.line.setMidLineWidth(0)
self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line") self.line.setObjectName("line")
self.verticalLayout_22.addWidget(self.line) self.verticalLayout_22.addWidget(self.line)
self.txtSummaryFull = textEditView(self.grpSummary) self.txtSummaryFull = MDEditCompleter(self.grpSummary)
self.txtSummaryFull.setFrameShape(QtWidgets.QFrame.NoFrame) self.txtSummaryFull.setFrameShape(QtWidgets.QFrame.NoFrame)
self.txtSummaryFull.setObjectName("txtSummaryFull") self.txtSummaryFull.setObjectName("txtSummaryFull")
self.verticalLayout_22.addWidget(self.txtSummaryFull) self.verticalLayout_22.addWidget(self.txtSummaryFull)
@ -66,10 +64,10 @@ class Ui_metadataView(object):
self.grpNotes.setCheckable(True) self.grpNotes.setCheckable(True)
self.grpNotes.setObjectName("grpNotes") self.grpNotes.setObjectName("grpNotes")
self.horizontalLayout_29 = QtWidgets.QHBoxLayout(self.grpNotes) self.horizontalLayout_29 = QtWidgets.QHBoxLayout(self.grpNotes)
self.horizontalLayout_29.setSpacing(0)
self.horizontalLayout_29.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_29.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_29.setSpacing(0)
self.horizontalLayout_29.setObjectName("horizontalLayout_29") self.horizontalLayout_29.setObjectName("horizontalLayout_29")
self.txtNotes = textEditCompleter(self.grpNotes) self.txtNotes = MDEditCompleter(self.grpNotes)
self.txtNotes.setFrameShape(QtWidgets.QFrame.NoFrame) self.txtNotes.setFrameShape(QtWidgets.QFrame.NoFrame)
self.txtNotes.setObjectName("txtNotes") self.txtNotes.setObjectName("txtNotes")
self.horizontalLayout_29.addWidget(self.txtNotes) self.horizontalLayout_29.addWidget(self.txtNotes)
@ -79,8 +77,8 @@ class Ui_metadataView(object):
self.grpRevisions.setCheckable(True) self.grpRevisions.setCheckable(True)
self.grpRevisions.setObjectName("grpRevisions") self.grpRevisions.setObjectName("grpRevisions")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.grpRevisions) self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.grpRevisions)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout_2.setObjectName("verticalLayout_2")
self.revisions = revisions(self.grpRevisions) self.revisions = revisions(self.grpRevisions)
self.revisions.setMinimumSize(QtCore.QSize(0, 50)) self.revisions.setMinimumSize(QtCore.QSize(0, 50))
@ -103,8 +101,7 @@ class Ui_metadataView(object):
self.grpRevisions.setTitle(_translate("metadataView", "Revisions")) self.grpRevisions.setTitle(_translate("metadataView", "Revisions"))
from manuskript.ui.collapsibleGroupBox2 import collapsibleGroupBox2 from manuskript.ui.collapsibleGroupBox2 import collapsibleGroupBox2
from manuskript.ui.views.textEditView import textEditView
from manuskript.ui.views.textEditCompleter import textEditCompleter
from manuskript.ui.views.propertiesView import propertiesView
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.revisions import revisions from manuskript.ui.revisions import revisions
from manuskript.ui.views.MDEditCompleter import MDEditCompleter
from manuskript.ui.views.lineEditView import lineEditView
from manuskript.ui.views.propertiesView import propertiesView

View file

@ -132,7 +132,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="textEditView" name="txtSummaryFull"> <widget class="MDEditCompleter" name="txtSummaryFull">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
@ -172,7 +172,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="textEditCompleter" name="txtNotes"> <widget class="MDEditCompleter" name="txtNotes">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
@ -228,9 +228,9 @@
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>textEditView</class> <class>MDEditCompleter</class>
<extends>QTextEdit</extends> <extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditView.h</header> <header>manuskript.ui.views.MDEditCompleter.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>lineEditView</class> <class>lineEditView</class>
@ -249,11 +249,6 @@
<header>manuskript.ui.views.propertiesView.h</header> <header>manuskript.ui.views.propertiesView.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>textEditCompleter</class>
<extends>QTextEdit</extends>
<header>manuskript.ui.views.textEditCompleter.h</header>
</customwidget>
<customwidget> <customwidget>
<class>revisions</class> <class>revisions</class>
<extends>QWidget</extends> <extends>QWidget</extends>

View file

@ -7,13 +7,10 @@ from PyQt5.QtGui import QTextBlockFormat, QTextCharFormat, QFont, QColor, QIcon,
from PyQt5.QtWidgets import QWidget, QTextEdit, qApp, QAction, QMenu from PyQt5.QtWidgets import QWidget, QTextEdit, qApp, QAction, QMenu
from manuskript import settings from manuskript import settings
from manuskript.enums import Outline from manuskript.enums import Outline, World, Character, Plot
from manuskript import functions as F from manuskript import functions as F
from manuskript.models.outlineModel import outlineModel from manuskript.models.outlineModel import outlineModel
from manuskript.ui.editors.MDFunctions import MDFormatSelection from manuskript.ui.highlighters import BasicHighlighter
from manuskript.ui.editors.MMDHighlighter import MMDHighlighter
from manuskript.ui.editors.basicHighlighter import basicHighlighter
from manuskript.ui.editors.textFormat import textFormat
from manuskript.ui import style as S from manuskript.ui import style as S
try: try:
@ -23,8 +20,8 @@ except ImportError:
class textEditView(QTextEdit): class textEditView(QTextEdit):
def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="", def __init__(self, parent=None, index=None, html=None, spellcheck=True,
autoResize=False): highlighting=False, dict="", autoResize=False):
QTextEdit.__init__(self, parent) QTextEdit.__init__(self, parent)
self._column = Outline.text self._column = Outline.text
self._index = None self._index = None
@ -42,16 +39,18 @@ class textEditView(QTextEdit):
# position, so we only have it's ID as reference. We store it to # position, so we only have it's ID as reference. We store it to
# update at the propper time. # update at the propper time.
self._updateIndexFromID = None self._updateIndexFromID = None
self._themeData = None
self._highlighterClass = BasicHighlighter
self.spellcheck = spellcheck self.spellcheck = spellcheck
self.currentDict = dict if dict else settings.dict self.currentDict = dict if dict else settings.dict
self._defaultFontSize = qApp.font().pointSize()
self.highlighter = None self.highlighter = None
self.setAutoResize(autoResize) self.setAutoResize(autoResize)
self._defaultBlockFormat = QTextBlockFormat() self._defaultBlockFormat = QTextBlockFormat()
self._defaultCharFormat = QTextCharFormat() self._defaultCharFormat = QTextCharFormat()
self.highlightWord = "" self.highlightWord = ""
self.highligtCS = False self.highligtCS = False
self.defaultFontPointSize = qApp.font().pointSize()
self._dict = None self._dict = None
# self.document().contentsChanged.connect(self.submit, F.AUC) # self.document().contentsChanged.connect(self.submit, F.AUC)
@ -80,7 +79,8 @@ class textEditView(QTextEdit):
# Spellchecking # Spellchecking
if enchant and self.spellcheck: if enchant and self.spellcheck:
try: try:
self._dict = enchant.Dict(self.currentDict if self.currentDict else self.getDefaultLocale()) self._dict = enchant.Dict(self.currentDict if self.currentDict
else self.getDefaultLocale())
except enchant.errors.DictNotFoundError: except enchant.errors.DictNotFoundError:
self.spellcheck = False self.spellcheck = False
@ -88,7 +88,7 @@ class textEditView(QTextEdit):
self.spellcheck = False self.spellcheck = False
if self._highlighting and not self.highlighter: if self._highlighting and not self.highlighter:
self.highlighter = basicHighlighter(self) self.highlighter = self._highlighterClass(self)
self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat)
def getDefaultLocale(self): def getDefaultLocale(self):
@ -177,27 +177,11 @@ class textEditView(QTextEdit):
self.updateText() self.updateText()
def setupEditorForIndex(self, index): def setupEditorForIndex(self, index):
# In which model are we editing?
if type(index.model()) != outlineModel:
self._textFormat = "text"
return
# what type of text are we editing?
if self._column not in [Outline.text, Outline.notes]:
self._textFormat = "text"
else:
self._textFormat = "md"
# Setting highlighter # Setting highlighter
if self._highlighting: if self._highlighting:
item = index.internalPointer() self.highlighter = self._highlighterClass(self)
if self._column in [Outline.text, Outline.notes]:
self.highlighter = MMDHighlighter(self)
else:
self.highlighter = basicHighlighter(self)
self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat)
self.highlighter.updateColorScheme()
def loadFontSettings(self): def loadFontSettings(self):
if self._fromTheme or \ if self._fromTheme or \
@ -209,8 +193,10 @@ class textEditView(QTextEdit):
opt = settings.textEditor opt = settings.textEditor
f = QFont() f = QFont()
f.fromString(opt["font"]) f.fromString(opt["font"])
background = opt["background"] if not opt["backgroundTransparent"] else "transparent" background = (opt["background"] if not opt["backgroundTransparent"]
foreground = opt["fontColor"] if not opt["backgroundTransparent"] else S.text else "transparent")
foreground = opt["fontColor"] # if not opt["backgroundTransparent"]
# else S.text
# self.setFont(f) # self.setFont(f)
self.setStyleSheet("""QTextEdit{{ self.setStyleSheet("""QTextEdit{{
background: {bg}; background: {bg};
@ -230,6 +216,7 @@ class textEditView(QTextEdit):
maxWidth = "max-width: {}px;".format(opt["maxWidth"]) if opt["maxWidth"] else "", maxWidth = "max-width: {}px;".format(opt["maxWidth"]) if opt["maxWidth"] else "",
) )
) )
self._defaultFontSize = f.pointSize()
# We set the parent background to the editor's background in case # We set the parent background to the editor's background in case
# there are margins. We check that the parent class is a QWidget because # there are margins. We check that the parent class is a QWidget because
@ -266,6 +253,7 @@ class textEditView(QTextEdit):
self._defaultBlockFormat = bf self._defaultBlockFormat = bf
if self.highlighter: if self.highlighter:
self.highlighter.updateColorScheme()
self.highlighter.setMisspelledColor(QColor(opt["misspelled"])) self.highlighter.setMisspelledColor(QColor(opt["misspelled"]))
self.highlighter.setDefaultCharFormat(self._defaultCharFormat) self.highlighter.setDefaultCharFormat(self._defaultCharFormat)
self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat)
@ -415,7 +403,8 @@ class textEditView(QTextEdit):
self.sizeChange() self.sizeChange()
def sizeChange(self): def sizeChange(self):
docHeight = self.document().size().height() opt = settings.textEditor
docHeight = self.document().size().height() + 2 * opt["marginsTB"]
if self.heightMin <= docHeight <= self.heightMax: if self.heightMin <= docHeight <= self.heightMax:
self.setMinimumHeight(docHeight) self.setMinimumHeight(docHeight)
@ -461,6 +450,31 @@ class textEditView(QTextEdit):
Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
QTextEdit.mousePressEvent(self, event) QTextEdit.mousePressEvent(self, event)
def wheelEvent(self, event):
"""
We catch wheelEvent if key modifier is CTRL to change font size.
Note: this should be in a class specific for main textEditView (#TODO).
"""
if event.modifiers() & Qt.ControlModifier:
# Get the wheel angle.
d = event.angleDelta().y() / 120
# Update settings
f = QFont()
f.fromString(settings.textEditor["font"])
f.setPointSizeF(f.pointSizeF() + d)
settings.textEditor["font"] = f.toString()
# Update font to all textEditView. Drastically.
for w in F.mainWindow().findChildren(textEditView, QRegExp(".*")):
w.loadFontSettings()
# We tell the world that we accepted this event
event.accept()
return
QTextEdit.wheelEvent(self, event)
class SpellAction(QAction): class SpellAction(QAction):
"""A special QAction that returns the text in a signal. Used for spellckech.""" """A special QAction that returns the text in a signal. Used for spellckech."""
@ -560,32 +574,6 @@ class textEditView(QTextEdit):
QTextEdit.focusOutEvent(self, event) QTextEdit.focusOutEvent(self, event)
self.submit() self.submit()
def focusInEvent(self, event):
"""Finds textFormatter and attach them to that view."""
QTextEdit.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)
def applyFormat(self, _format):
if self._textFormat == "md":
if _format == "Bold":
MDFormatSelection(self, 0)
elif _format == "Italic":
MDFormatSelection(self, 1)
elif _format == "Code":
MDFormatSelection(self, 2)
elif _format == "Clear":
MDFormatSelection(self)
############################################################################### ###############################################################################
# KEYBOARD SHORTCUTS # KEYBOARD SHORTCUTS
############################################################################### ###############################################################################
@ -596,7 +584,7 @@ class textEditView(QTextEdit):
edit that has focus. So we can pass it the call for documents edit that has focus. So we can pass it the call for documents
edits like: duplicate, move up, etc. edits like: duplicate, move up, etc.
""" """
if self._index and self._column == Outline.text.value: if self._index and self._column == Outline.text:
function = getattr(F.mainWindow().treeRedacOutline, functionName) function = getattr(F.mainWindow().treeRedacOutline, functionName)
function() function()