diff --git a/makefile b/makefile
index 1c82d523..18910059 100644
--- a/makefile
+++ b/makefile
@@ -1,4 +1,4 @@
-UI := $(wildcard src/ui/*.ui) $(wildcard src/ui/*.qrc)
+UI := $(wildcard src/ui/*.ui) $(wildcard src/ui/*/*.ui) $(wildcard src/ui/*.qrc)
UIs= $(UI:.ui=.py) $(UI:.qrc=_rc.py)
diff --git a/src/enums.py b/src/enums.py
index 40f5166b..42cdb299 100644
--- a/src/enums.py
+++ b/src/enums.py
@@ -41,3 +41,4 @@ class Outline(Enum):
goalPercentage = 12
setGoal = 13 # The goal set by the user, if any. Can be different from goal which can be computed
# (sum of all sub-items' goals)
+ textFormat = 14
diff --git a/src/ui/editors/__init__.py b/src/ui/editors/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/ui/editors/blockUserData.py b/src/ui/editors/blockUserData.py
new file mode 100644
index 00000000..c25b1c92
--- /dev/null
+++ b/src/ui/editors/blockUserData.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+from qt import *
+
+
+class blockUserData (QTextBlockUserData):
+
+ @staticmethod
+ def getUserData(block):
+ "Returns userData if it exists, or a blank one."
+ data = block.userData()
+ if data is None:
+ data = blockUserData()
+ return data
+
+ @staticmethod
+ def getUserState(block):
+ "Returns the block state."
+ state = block.userState()
+ while state >= 100:
+ state -= 100 # +100 means in a list
+ return state
+
+ def __init__(self):
+ QTextBlockUserData.__init__(self)
+ self._listLevel = 0
+ self._leadingSpaces = 0
+ self._emptyLinesBefore = 0
+ self._listSymbol = ""
+
+ def isList(self):
+ return self._listLevel > 0
+
+ def listLevel(self):
+ return self._listLevel
+
+ def setListLevel(self, level):
+ self._listLevel = level
+
+ def listSymbol(self):
+ return self._listSymbol
+
+ def setListSymbol(self, s):
+ self._listSymbol = s
+
+ def leadingSpaces(self):
+ return self._leadingSpaces
+
+ def setLeadingSpaces(self, n):
+ self._leadingSpaces = n
+
+ def emptyLinesBefore(self):
+ return self._emptyLinesBefore
+
+ def setEmptyLinesBefore(self, n):
+ self._emptyLinesBefore = n
+
+ def text(self):
+ return str(self.listLevel()) + "|" + str(self.leadingSpaces()) + "|" + str(self.emptyLinesBefore())
+
+ def __eq__(self, b):
+ return self._listLevel == b._listLevel and \
+ self._leadingSpaces == b._leadingSpaces and \
+ self._emptyLinesBefore == b._emptyLinesBefore
+
+ def __ne__(self, b):
+ return not self == b
diff --git a/src/ui/editors/customTextEdit.py b/src/ui/editors/customTextEdit.py
new file mode 100644
index 00000000..13b529ee
--- /dev/null
+++ b/src/ui/editors/customTextEdit.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+#--!-- coding: utf8 --!--
+
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from qt import *
+from enums import *
+from ui.editors.t2tHighlighter import *
+try:
+ import enchant
+except ImportError:
+ enchant = None
+
+class customTextEdit(QTextEdit):
+
+ def __init__(self, parent=None):
+ QTextEdit.__init__(self, parent)
+
+ self.defaultFontPointSize = 9
+ self.highlightWord = ""
+ self.highligtCS = False
+
+ self.highlighter = t2tHighlighter(self)
+
+ # Spellchecking
+ if enchant:
+ self.dict = enchant.Dict("fr_CH")
+ self.spellcheck = True
+ else:
+ self.spellcheck = False
\ No newline at end of file
diff --git a/src/ui/editorWidget.py b/src/ui/editors/editorWidget.py
similarity index 99%
rename from src/ui/editorWidget.py
rename to src/ui/editors/editorWidget.py
index 4ebafcd2..55defd02 100644
--- a/src/ui/editorWidget.py
+++ b/src/ui/editors/editorWidget.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
from qt import *
from enums import *
-from ui.editorWidget_ui import *
+from ui.editors.editorWidget_ui import *
class GrowingTextEdit(QTextEdit):
diff --git a/src/ui/editorWidget_ui.py b/src/ui/editors/editorWidget_ui.py
similarity index 93%
rename from src/ui/editorWidget_ui.py
rename to src/ui/editors/editorWidget_ui.py
index ca63579c..21c14ed3 100644
--- a/src/ui/editorWidget_ui.py
+++ b/src/ui/editors/editorWidget_ui.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'src/ui/editorWidget_ui.ui'
+# Form implementation generated from reading ui file 'src/ui/editors/editorWidget_ui.ui'
#
# Created by: PyQt5 UI code generator 5.4.1
#
@@ -22,7 +22,7 @@ class Ui_editorWidget_ui(object):
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.scene)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.txtRedacText = QtWidgets.QPlainTextEdit(self.scene)
+ self.txtRedacText = customTextEdit(self.scene)
self.txtRedacText.setObjectName("txtRedacText")
self.horizontalLayout_2.addWidget(self.txtRedacText)
self.stack.addWidget(self.scene)
@@ -45,10 +45,11 @@ class Ui_editorWidget_ui(object):
self.horizontalLayout.addWidget(self.stack)
self.retranslateUi(editorWidget_ui)
- self.stack.setCurrentIndex(1)
+ self.stack.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(editorWidget_ui)
def retranslateUi(self, editorWidget_ui):
_translate = QtCore.QCoreApplication.translate
editorWidget_ui.setWindowTitle(_translate("editorWidget_ui", "Form"))
+from ui.editors.customTextEdit import customTextEdit
diff --git a/src/ui/editorWidget_ui.ui b/src/ui/editors/editorWidget_ui.ui
similarity index 86%
rename from src/ui/editorWidget_ui.ui
rename to src/ui/editors/editorWidget_ui.ui
index 9528ceb9..ea72f10a 100644
--- a/src/ui/editorWidget_ui.ui
+++ b/src/ui/editors/editorWidget_ui.ui
@@ -20,7 +20,7 @@
-
- 1
+ 0
@@ -28,7 +28,7 @@
0
-
-
+
@@ -66,6 +66,13 @@
+
+
+ customTextEdit
+ QTextEdit
+ ui.editors.customTextEdit.h
+
+
diff --git a/src/ui/editors/t2tFunctions.py b/src/ui/editors/t2tFunctions.py
new file mode 100644
index 00000000..262bc36f
--- /dev/null
+++ b/src/ui/editors/t2tFunctions.py
@@ -0,0 +1,264 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from qt import *
+
+
+def textToFormatArray(text):
+ """
+ Take some text and returns an array of array containing informations
+ about how the text is formatted:
+ r = [ [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
+ [0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
+ ...
+ ]
+ Each sub-array is for one of the beautifier:
+ 0: bold
+ 1: italic
+ 2: underline
+ 3: strike
+ 4: code
+ 5: tagged
+
+ Each sub-array contains an element for each character of the text, with the
+ value 1 if it is formatted in the specific format, -1 if it is markup, and
+ 0 otherwise.
+
+ removeMarks returns a both the array and a string, in which all of the
+ formatting marks have been removed.
+ """
+
+ result = []
+
+ for markup in ["\*", "/", "_", "-", "`", "\'"]:
+
+ rList = []
+
+ r = QRegExp(r'(' + markup * 2 + ')(.+)(' + markup * 2 + ')')
+ r.setMinimal(True)
+ pos = r.indexIn(text, 0)
+ lastPos = 0
+ while pos >= 0:
+ #We have a winner
+ rList += [0] * (pos - lastPos)
+ rList += [2] * 2
+ rList += [1] * len(r.cap(2))
+ rList += [2] * 2
+ lastPos = pos + len(r.cap(0))
+ pos = r.indexIn(text, len(rList))
+
+ if len(rList) < len(text):
+ rList += [0] * (len(text) - len(rList))
+
+ result.append(rList)
+
+ return result
+
+
+def textToFormatArrayNoMarkup(text):
+ """
+ Same as textToFormatArray, except that it removes all the markup from the
+ text and returns two elements:
+ the array
+ the text without markup
+ """
+
+ r = textToFormatArray(text)
+ result = [[], [], [], [], [], []]
+ rText = ""
+
+ for i in range(len(text)):
+ t = max([k[i] for k in r]) # kind of flattens all the format array
+ if t != 2:
+ rText += text[i]
+ [result[k].append(r[k][i]) for k in range(len(r))]
+
+ return rText, result
+
+
+def translateSelectionToUnformattedText(text, start, end):
+ """
+ Translate the start / end of selection from a formatted text to an
+ unformatted one.
+ """
+ r = textToFormatArray(text)
+
+ rStart, rEnd = start, end
+
+ for i in range(len(text)):
+ t = max([k[i] for k in r]) # kind of flattens all the format array
+ if t == 2: # t == 2 means this character is markup
+ if i <= start: rStart -= 1
+ if i < end: rEnd -= 1
+
+ return rStart, rEnd
+
+
+def translateSelectionToFormattedText(text, start, end):
+ """
+ Translate the start / end of selection from a formatted text to an
+ unformatted one.
+ """
+ r = textToFormatArray(text)
+
+ rStart, rEnd = start, end
+
+ for i in range(len(text)):
+ t = max([k[i] for k in r]) # kind of flattens all the format array
+ if t == 2: # t == 2 means this character is markup
+ if i <= start: rStart -= 1
+ if i < end: rEnd -= 1
+
+ return rStart, rEnd
+
+
+def printArray(array):
+ print("".join([str(j) for j in array]))
+
+
+def printArrays(arrays):
+ for i in arrays: printArray(i)
+
+
+def reformatText(text, markupArray):
+ """
+ Takes a text without formatting markup, and an array generated by
+ textToFormatArray, and adds the propper markup.
+ """
+
+ rText = ""
+ markup = ["**", "//", "__", "--", "``", "''"]
+
+ for k in range(len(markupArray)):
+ m = markupArray[k]
+ open = False # Are we in an openned markup
+ d = 0
+ alreadySeen = []
+ for i in range(len(text)):
+ insert = False
+ if not open and m[i] == 1:
+ insert = True
+ open = True
+
+ if open and m[i] == 0:
+ insert = True
+ open = False
+ if open and m[i] > 1:
+ z = i
+ while m[z] == m[i]: z += 1
+ if m[z] != 1 and not m[i] in alreadySeen:
+ insert = True
+ open = False
+ alreadySeen.append(m[i])
+ if insert:
+ rText += markup[k]
+ for j in range(len(markupArray)):
+ # The other array still have the same length
+ if j > k:
+ #Insert 2 for bold, 3 for italic, etc.
+ markupArray[j].insert(i + d, k + 2)
+ markupArray[j].insert(i + d, k + 2)
+ alreadySeen = []
+ d += 2
+ rText += text[i]
+ if open:
+ rText += markup[k]
+ for j in range(len(markupArray)):
+ # The other array still have the same length
+ if j > k:
+ #Insert 2 for bold, 3 for italic, etc.
+ markupArray[j].insert(i + d, k + 2)
+ markupArray[j].insert(i + d, k + 2)
+ text = rText
+ rText = ""
+
+ ## Clean up
+ # Exclude first and last space of the markup
+ for markup in ["\*", "/", "_", "-", "`", "\'"]:
+ r = QRegExp(r'(' + markup * 2 + ')(\s+)(.+)(' + markup * 2 + ')')
+ r.setMinimal(True)
+ text.replace(r, "\\2\\1\\3\\4")
+ r = QRegExp(r'(' + markup * 2 + ')(.+)(\s+)(' + markup * 2 + ')')
+ r.setMinimal(True)
+ text.replace(r, "\\1\\2\\4\\3")
+
+ return text
+
+
+def cleanFormat(text):
+ "Makes markup clean (removes doubles, etc.)"
+ t, a = textToFormatArrayNoMarkup(text)
+ return reformatText(t, a)
+
+
+class State:
+ NORMAL = 0
+ TITLE_1 = 1
+ TITLE_2 = 2
+ TITLE_3 = 3
+ TITLE_4 = 4
+ TITLE_5 = 5
+ NUMBERED_TITLE_1 = 6
+ NUMBERED_TITLE_2 = 7
+ NUMBERED_TITLE_3 = 8
+ NUMBERED_TITLE_4 = 9
+ NUMBERED_TITLE_5 = 10
+ TITLES = [TITLE_1, TITLE_2, TITLE_3, TITLE_4, TITLE_5, NUMBERED_TITLE_1,
+ NUMBERED_TITLE_2, NUMBERED_TITLE_3, NUMBERED_TITLE_4,
+ NUMBERED_TITLE_5]
+ # AREA
+ COMMENT_AREA = 11
+ CODE_AREA = 12
+ RAW_AREA = 13
+ TAGGED_AREA = 14
+ # AREA MARKUP
+ COMMENT_AREA_BEGINS = 15
+ COMMENT_AREA_ENDS = 16
+ CODE_AREA_BEGINS = 17
+ CODE_AREA_ENDS = 18
+ RAW_AREA_BEGINS = 19
+ RAW_AREA_ENDS = 20
+ TAGGED_AREA_BEGINS = 21
+ TAGGED_AREA_ENDS = 22
+ #LINE
+ COMMENT_LINE = 30
+ CODE_LINE = 31
+ RAW_LINE = 32
+ TAGGED_LINE = 33
+ SETTINGS_LINE = 34
+ BLOCKQUOTE_LINE = 35
+ HORIZONTAL_LINE = 36
+ HEADER_LINE = 37
+ # LIST
+ LIST_BEGINS = 40
+ LIST_ENDS = 41
+ LIST_EMPTY = 42
+ LIST_BULLET = 43
+ LIST_BULLET_ENDS = 44
+ LIST = [40, 41, 42] + range(100, 201)
+ # TABLE
+ TABLE_LINE = 50
+ TABLE_HEADER = 51
+ #OTHER
+ MARKUP = 60
+ LINKS = 61
+ MACRO = 62
+ DEFAULT = 63
+
+ @staticmethod
+ def titleLevel(state):
+ """
+ Returns the level of the title, from the block state.
+ """
+ return {
+ State.TITLE_1: 1,
+ State.TITLE_2: 2,
+ State.TITLE_3: 3,
+ State.TITLE_4: 4,
+ State.TITLE_5: 5,
+ State.NUMBERED_TITLE_1: 1,
+ State.NUMBERED_TITLE_2: 2,
+ State.NUMBERED_TITLE_3: 3,
+ State.NUMBERED_TITLE_4: 4,
+ State.NUMBERED_TITLE_5: 5,
+ }.get(state, -1)
\ No newline at end of file
diff --git a/src/ui/editors/t2tHighlighter.py b/src/ui/editors/t2tHighlighter.py
new file mode 100644
index 00000000..50471677
--- /dev/null
+++ b/src/ui/editors/t2tHighlighter.py
@@ -0,0 +1,553 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+from qt import *
+from ui.editors.t2tFunctions import *
+from ui.editors.blockUserData import blockUserData
+from ui.editors.t2tHighlighterStyle import t2tHighlighterStyle
+import re
+
+# This is aiming at implementing every rule from www.txt2tags.org/rules.html
+# But we're not there yet.
+
+#FIXME: macro words not hilighted properly if at the begining of a line.
+
+#TODO: parse %!postproc et !%preproc, et si la ligne se termine par une couleur en commentaire (%#FF00FF), utiliser cette couleur pour highlighter. Permet des règles customisées par document, facilement.
+
+
+class t2tHighlighter (QSyntaxHighlighter):
+ """Syntax highlighter for the Txt2Tags language.
+ """
+
+ def __init__(self, editor, style="Default"):
+ QSyntaxHighlighter.__init__(self, editor.document())
+
+ self.editor = editor
+
+ # Stupid variable that fixes the loss of QTextBlockUserData.
+ self.thisDocument = editor.document()
+ self.style = t2tHighlighterStyle(self.editor, style)
+
+ self.inDocRules = []
+
+ rules = [
+ (r'^\s*[-=_]{20,}\s*$', State.HORIZONTAL_LINE),
+ (r'^\s*(\+{1})([^\+].*[^\+])(\+{1})(\[[A-Za-z0-9_-]*\])?\s*$', State.NUMBERED_TITLE_1),
+ (r'^\s*(\+{2})([^\+].*[^\+])(\+{2})(\[[A-Za-z0-9_-]*\])?\s*$', State.NUMBERED_TITLE_2),
+ (r'^\s*(\+{3})([^\+].*[^\+])(\+{3})(\[[A-Za-z0-9_-]*\])?\s*$', State.NUMBERED_TITLE_3),
+ (r'^\s*(\+{4})([^\+].*[^\+])(\+{4})(\[[A-Za-z0-9_-]*\])?\s*$', State.NUMBERED_TITLE_4),
+ (r'^\s*(\+{5})([^\+].*[^\+])(\+{5})(\[[A-Za-z0-9_-]*\])?\s*$', State.NUMBERED_TITLE_5),
+ (r'^\s*(={1})([^=].*[^=])(={1})(\[[A-Za-z0-9_-]*\])?\s*$', State.TITLE_1),
+ (r'^\s*(={2})([^=].*[^=])(={2})(\[[A-Za-z0-9_-]*\])?\s*$', State.TITLE_2),
+ (r'^\s*(={3})([^=].*[^=])(={3})(\[[A-Za-z0-9_-]*\])?\s*$', State.TITLE_3),
+ (r'^\s*(={4})([^=].*[^=])(={4})(\[[A-Za-z0-9_-]*\])?\s*$', State.TITLE_4),
+ (r'^\s*(={5})([^=].*[^=])(={5})(\[[A-Za-z0-9_-]*\])?\s*$', State.TITLE_5),
+ (r'^%!.*$', State.SETTINGS_LINE),
+ (r'^%[^!]?.*$', State.COMMENT_LINE),
+ (r'^\t.+$', State.BLOCKQUOTE_LINE),
+ (r'^(```)(.+)$', State.CODE_LINE),
+ (r'^(""")(.+)$', State.RAW_LINE),
+ (r'^(\'\'\')(.+)$', State.TAGGED_LINE),
+ (r'^\s*[-+:] [^ ].*$', State.LIST_BEGINS),
+ (r'^\s*[-+:]\s*$', State.LIST_ENDS),
+ (r'^ *\|\| .*$', State.TABLE_HEADER),
+ (r'^ *\| .*$', State.TABLE_LINE)
+ ]
+
+ # Generate rules to identify blocks
+ State.Rules = [(QRegExp(pattern), state)
+ for (pattern, state) in rules]
+ State.Recursion = 0
+
+ def highlightBlock(self, text):
+ """Apply syntax highlighting to the given block of text.
+ """
+
+ # Check if syntax highlighting is enabled
+ if self.style is None:
+ default = QTextBlockFormat()
+ QTextCursor(self.currentBlock()).setBlockFormat(default)
+ return
+
+ block = self.currentBlock()
+ oldState = blockUserData.getUserState(block)
+ self.identifyBlock(block)
+ # formatBlock prevent undo/redo from working
+ # TODO: find a todo/undo compatible way of formatting block
+ #self.formatBlock(block)
+
+ state = blockUserData.getUserState(block)
+ data = blockUserData.getUserData(block)
+ inList = self.isList(block)
+
+ op = self.style.format(State.MARKUP)
+
+ self.setFormat(0, len(text), self.style.format(State.DEFAULT))
+
+ # InDocRules: is it a settings which might have a specific rule,
+ # a comment which contains color infos, or a include conf?
+ # r'^%!p[or][se]t?proc[^\s]*\s*:\s*\'(.*)\'\s*\'.*\''
+ rlist = [QRegExp(r'^%!p[or][se]t?proc[^\s]*\s*:\s*((\'[^\']*\'|\"[^\"]*\")\s*(\'[^\']*\'|\"[^\"]*\"))'), # pre/postproc
+ QRegExp(r'^%.*\s\((.*)\)'), # comment
+ QRegExp(r'^%!includeconf:\s*([^\s]*)\s*')] # includeconf
+ for r in rlist:
+ if r.indexIn(text) != -1:
+ self.parseInDocRules()
+
+ # Format the whole line:
+ for lineState in [
+ State.BLOCKQUOTE_LINE,
+ State.HORIZONTAL_LINE,
+ State.HEADER_LINE,
+ ]:
+ if not inList and state == lineState:
+ self.setFormat(0, len(text), self.style.format(lineState))
+
+ for (lineState, marker) in [
+ (State.COMMENT_LINE, "%"),
+ (State.CODE_LINE, "```"),
+ (State.RAW_LINE, "\"\"\""),
+ (State.TAGGED_LINE, "'''"),
+ (State.SETTINGS_LINE, "%!")
+ ]:
+ if state == lineState and \
+ not (inList and state == State.SETTINGS_LINE):
+ n = 0
+ # If it's a comment, we want to highlight all '%'.
+ if state == State.COMMENT_LINE:
+ while text[n:n + 1] == "%":
+ n += 1
+ n -= 1
+
+ # Apply Format
+ self.setFormat(0, len(marker) + n, op)
+ self.setFormat(len(marker) + n,
+ len(text) - len(marker) - n,
+ self.style.format(lineState))
+
+ # If it's a setting, we might do something
+ if state == State.SETTINGS_LINE:
+ # Target
+ r = QRegExp(r'^%!([^\s]+)\s*:\s*(\b\w*\b)$')
+ if r.indexIn(text) != -1:
+ setting = r.cap(1)
+ val = r.cap(2)
+ if setting == "target" and \
+ val in self.editor.main.targetsNames:
+ self.editor.fileWidget.preview.setPreferredTarget(val)
+
+ # Pre/postproc
+ r = QRegExp(r'^%!p[or][se]t?proc[^\s]*\s*:\s*((\'[^\']*\'|\"[^\"]*\")\s*(\'[^\']*\'|\"[^\"]*\"))')
+ if r.indexIn(text) != -1:
+ p = r.pos(1)
+ length = len(r.cap(1))
+ self.setFormat(p, length, self.style.makeFormat(base=self.format(p),
+ fixedPitch=True))
+
+ # Tables
+ for lineState in [State.TABLE_LINE, State.TABLE_HEADER]:
+ if state == lineState:
+ for i in range(len(text)):
+ if text[i] == "|":
+ self.setFormat(i, 1, op)
+ else:
+ self.setFormat(i, 1, self.style.format(lineState))
+
+ # Lists
+ #if text == " p": print(data.isList())
+ if data.isList():
+ r = QRegExp(r'^\s*[\+\-\:]? ?')
+ r.indexIn(text)
+ self.setFormat(0, r.matchedLength(), self.style.format(State.LIST_BULLET))
+ #if state == State.LIST_BEGINS:
+ #r = QRegExp(r'^\s*[+-:] ')
+ #r.indexIn(text)
+ #self.setFormat(0, r.matchedLength(), self.style.format(State.LIST_BULLET))
+
+ if state == State.LIST_ENDS:
+ self.setFormat(0, len(text), self.style.format(State.LIST_BULLET_ENDS))
+
+ # Titles
+ if not inList and state in State.TITLES:
+ r = [i for (i, s) in State.Rules if s == state][0]
+ pos = r.indexIn(text)
+ if pos >= 0:
+ f = self.style.format(state)
+ # Uncomment for markup to be same size as title
+ #op = self.formats(preset="markup",
+ #base=self.formats(preset=state))
+ self.setFormat(r.pos(2), r.cap(2).length(), f)
+ self.setFormat(r.pos(1), r.cap(1).length(), op)
+ self.setFormat(r.pos(3), r.cap(3).length(), op)
+
+ # Areas: comment, code, raw tagged
+ for (begins, middle, ends) in [
+ (State.COMMENT_AREA_BEGINS, State.COMMENT_AREA, State.COMMENT_AREA_ENDS),
+ (State.CODE_AREA_BEGINS, State.CODE_AREA, State.CODE_AREA_ENDS),
+ (State.RAW_AREA_BEGINS, State.RAW_AREA, State.RAW_AREA_ENDS),
+ (State.TAGGED_AREA_BEGINS, State.TAGGED_AREA, State.TAGGED_AREA_ENDS),
+ ]:
+
+ if state == middle:
+ self.setFormat(0, len(text), self.style.format(middle))
+ elif state in [begins, ends]:
+ self.setFormat(0, len(text), op)
+
+ # Inline formatting
+ if state not in [
+ #State.COMMENT_AREA,
+ #State.COMMENT_LINE,
+ State.RAW_AREA,
+ State.RAW_LINE,
+ State.CODE_AREA,
+ State.CODE_LINE,
+ State.TAGGED_AREA,
+ State.TAGGED_LINE,
+ State.SETTINGS_LINE,
+ State.HORIZONTAL_LINE,
+ ] and state not in State.TITLES:
+ formatArray = textToFormatArray(text)
+
+ # InDocRules
+ for (r, c) in self.inDocRules:
+ i = re.finditer(r.decode('utf8'), text, re.UNICODE)
+ for m in i:
+ f = self.format(m.start())
+ l = m.end() - m.start()
+ if "," in c:
+ c1, c2 = c.split(",")
+ self.setFormat(m.start(), l,
+ self.style.makeFormat(color=c1, bgcolor=c2, base=f))
+ else:
+ self.setFormat(m.start(), l,
+ self.style.makeFormat(color=c, base=f))
+
+ # Links
+ if state not in [State.COMMENT_LINE, State.COMMENT_AREA]:
+ r = QRegExp(r'\[(\[[^\]]*\])?[^\]]*\s*([^\s]+)\]')
+ r.setMinimal(False)
+ pos = r.indexIn(text)
+ links = []
+ while pos >= 0:
+ #TODO: The text should not be formatted if [**not bold**]
+ #if max([k[pos] for k in formatArray]) == 0 or 1 == 1:
+ self.setFormat(pos, 1,
+ self.style.format(State.MARKUP))
+ self.setFormat(pos + 1, r.cap(0).length() - 1,
+ self.style.format(State.LINKS))
+ self.setFormat(pos + r.cap(0).length() - 1, 1,
+ self.style.format(State.MARKUP))
+ if r.pos(2) > 0:
+ _f = QTextCharFormat(self.style.format(State.LINKS))
+ _f.setForeground(QBrush(_f.foreground()
+ .color().lighter()))
+ _f.setFontUnderline(True)
+ self.setFormat(r.pos(2), r.cap(2).length(), _f)
+
+ links.append([pos, r.cap(0).length()]) # To remember for the next highlighter (single links)
+ pos = r.indexIn(text, pos + 1)
+
+ # Links like www.theologeek.ch, http://www.fsf.org, ...
+ # FIXME: - "http://adresse et http://adresse" is detected also as italic
+ # - some error, like "http://adress.htm." also color the final "."
+ # - also: adresse@email.com, ftp://, www2, www3, etc.
+ # - But for now, does the job
+ r = QRegExp(r'http://[^\s]*|www\.[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+[^\s]*')
+ #r.setMinimal(True)
+ pos = r.indexIn(text)
+ while pos >= 0:
+ for k in links:
+ #print pos, k[0], k[1]
+ if pos > k[0] and pos < k[0] + k[1]: # already highlighted
+ break
+ else:
+ self.setFormat(pos, r.cap(0).length(), self.style.format(State.LINKS))
+
+ pos = r.indexIn(text, pos + 1)
+
+ # Bold, Italic, Underline, Code, Tagged, Strikeout
+ for i in range(len(text)):
+ f = self.format(i)
+ beautifiers = [k[i] for k in formatArray]
+ self.setFormat(i, 1, self.style.beautifyFormat(f, beautifiers))
+
+ # Macro words
+ for r in [r'(%%)\b\w+\b', r'(%%)\b\w+\b\(.+\)']:
+ r = QRegExp(r)
+ r.setMinimal(True)
+ pos = r.indexIn(text)
+ while pos >= 0:
+ if max([k[pos] for k in formatArray]) == 0:
+ self.setFormat(pos, r.cap(0).length(),
+ self.style.format(State.MACRO))
+ pos = r.indexIn(text, pos + 1)
+
+ # Highlighted word (for search)
+ if self.editor.highlightWord:
+ if self.editor.highligtCS and self.editor.highlightWord in text or \
+ not self.editor.highlightCs and self.editor.highlightWord.lower() in text.lower():
+ #if self.editor.highlightCS:
+ #s = self.editor.highlightWord
+ #else:
+ #s = self.editor.highlightWord.toLower()
+ #print(s)
+ p = text.indexOf(self.editor.highlightWord, cs=self.editor.highlightCS)
+ while p >= 0:
+ self.setFormat(p, len(self.editor.highlightWord),
+ self.style.makeFormat(preset="higlighted", base=self.format(p)))
+ p = text.indexOf(self.editor.highlightWord, p + 1, cs=self.editor.highlightCS)
+
+
+ ### Highlight Selection
+ ### TODO: way to slow, find another way.
+ ##sel = self.editor.textCursor().selectedText()
+ ##if len(sel) > 5: self.keywordRules.append((QRegExp(sel), "selected"))
+
+ ## Do keyword formatting
+ #for expression, style in self.keywordRules:
+ #expression.setMinimal( True )
+ #index = expression.indexIn(text, 0)
+
+ ## There might be more than one on the same line
+ #while index >= 0:
+ #length = expression.cap(0).length()
+ #f = self.formats(preset=style, base=self.formats(index))
+ #self.setFormat(index, length, f)
+ #index = expression.indexIn(text, index + length)
+
+ # Spell checking
+ # Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
+ WORDS = u'(?iu)[\w\']+'
+ if state not in [State.SETTINGS_LINE]:
+ if self.editor.spellcheck:
+ for word_object in re.finditer(WORDS, text):
+ if not self.editor.dict.check(word_object.group()):
+ format = self.format(word_object.start())
+ format.setUnderlineColor(Qt.red)
+ format.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
+ self.setFormat(word_object.start(),
+ word_object.end() - word_object.start(), format)
+
+ # If a title was changed, we emit the corresponding signal
+ if oldState in State.TITLES or \
+ self.currentBlockState() in State.TITLES:
+ self.editor.structureChanged.emit()
+ #FIXME: si du texte est supprimé et qu'il y a un titre dedans,
+ # cela n'est pas détecté et le signal pas émis.
+
+ def identifyBlock(self, block):
+ """Identifies what block type it is, and set userState and userData
+ accordingly."""
+
+ text = block.text()
+ data = blockUserData.getUserData(block)
+
+ # Header Lines
+ if block.blockNumber() == 0:
+ block.setUserState(State.HEADER_LINE)
+ return
+ elif block.blockNumber() in [1, 2] and \
+ self.document().findBlockByNumber(0).text():
+ block.setUserState(State.HEADER_LINE)
+ return
+
+ state = 0
+ inList = False
+ blankLinesBefore = 0
+
+ #if text.contains(QRegExp(r'^\s*[-+:] [^ ].*[^-+]{1}\s*$')):
+ if QRegExp(r'^\s*[-+:] [^ ].*[^-+]{1}\s*$').indexIn(text) <> -1:
+ state = State.LIST_BEGINS
+
+ # List stuff
+ if self.isList(block.previous()) or state == State.LIST_BEGINS:
+ inList = True
+
+ # listLevel and leadingSpaces
+ #FIXME: not behaving exactly correctly...
+ lastData = blockUserData.getUserData(block.previous())
+ if state == State.LIST_BEGINS:
+ leadingSpaces = QRegExp(r'[-+:]').indexIn(text, 0)
+ data.setLeadingSpaces(leadingSpaces)
+
+ data.setListSymbol(text[leadingSpaces])
+ if self.isList(block.previous()):
+ # The last block was also a list.
+ # We need to check if this is the same level, or a sublist
+ if leadingSpaces > lastData.leadingSpaces():
+ # This is a sublevel list
+ data.setListLevel(lastData.listLevel() + 1)
+ else:
+ # This is same level
+ data.setListLevel(lastData.listLevel())
+ else:
+ data.setListLevel(1)
+ else:
+ data.setListLevel(lastData.listLevel())
+ data.setLeadingSpaces(lastData.leadingSpaces())
+ data.setListSymbol(lastData.listSymbol())
+
+ # Blank lines before (two = end of list)
+ blankLinesBefore = self.getBlankLines(block.previous())
+ if not QRegExp(r'^\s*$').indexIn(block.previous().text()) <> -1 and \
+ not blockUserData.getUserState(block.previous()) in [State.COMMENT_LINE,
+ State.COMMENT_AREA, State.COMMENT_AREA_BEGINS,
+ State.COMMENT_AREA_ENDS]:
+ blankLinesBefore = 0
+ elif not blockUserData.getUserState(block.previous()) in \
+ [State.COMMENT_LINE, State.COMMENT_AREA,
+ State.COMMENT_AREA_BEGINS, State.COMMENT_AREA_ENDS]:
+ blankLinesBefore += 1
+ if blankLinesBefore == 2:
+ # End of list.
+ blankLinesBefore = 0
+ inList = False
+ if inList and QRegExp(r'^\s*$').indexIn(text) <> -1:
+ state = State.LIST_EMPTY
+
+ # Areas
+ for (begins, middle, ends, marker) in [
+ (State.COMMENT_AREA_BEGINS, State.COMMENT_AREA, State.COMMENT_AREA_ENDS, "^%%%\s*$"),
+ (State.CODE_AREA_BEGINS, State.CODE_AREA, State.CODE_AREA_ENDS, "^```\s*$"),
+ (State.RAW_AREA_BEGINS, State.RAW_AREA, State.RAW_AREA_ENDS, "^\"\"\"\s*$"),
+ (State.TAGGED_AREA_BEGINS, State.TAGGED_AREA, State.TAGGED_AREA_ENDS, '^\'\'\'\s*$'),
+ ]:
+
+ if QRegExp(marker).indexIn(text) <> -1:
+ if blockUserData.getUserState(block.previous()) in [begins, middle]:
+ state = ends
+ break
+ else:
+ state = begins
+ break
+ if blockUserData.getUserState(block.previous()) in [middle, begins]:
+ state = middle
+ break
+
+ # Patterns (for lines)
+ if not state:
+ for (pattern, lineState) in State.Rules:
+ pos = pattern.indexIn(text)
+ if pos >= 0:
+ state = lineState
+ break
+
+ if state in [State.BLOCKQUOTE_LINE, State.LIST_ENDS]:
+ #FIXME: doesn't work exactly. Closes only the current level, not
+ #FIXME: the whole list.
+ inList = False
+
+ if inList and not state == State.LIST_BEGINS:
+ state += 100
+ if blankLinesBefore:
+ state += 100
+
+ block.setUserState(state)
+ block.setUserData(data)
+
+ def formatBlock(self, block):
+ """
+ Formats the block according to its state.
+ """
+ #TODO: Use QTextDocument format presets, and QTextBlock's
+ #TODO: blockFormatIndex. And move that in t2tHighlighterStyle.
+ state = block.userState()
+ blockFormat = QTextBlockFormat()
+
+ if state in [State.BLOCKQUOTE_LINE,
+ State.HEADER_LINE] + State.LIST:
+ blockFormat = self.style.formatBlock(block, state)
+
+ QTextCursor(block).setBlockFormat(blockFormat)
+
+ def getBlankLines(self, block):
+ "Returns if there is a blank line before in the list."
+ state = block.userState()
+ if state >= 200:
+ return 1
+ else:
+ return 0
+
+ def isList(self, block):
+ "Returns TRUE if the block is in a list."
+ if block.userState() == State.LIST_BEGINS or\
+ block.userState() >= 100:
+ return True
+
+ def setStyle(self, style):
+ if style in t2tHighlighterStyle.validStyles:
+ self.style = t2tHighlighterStyle(self.editor, style)
+ else:
+ self.style = None
+ self.rehighlight()
+
+ def setFontPointSize(self, size):
+ self.defaultFontPointSize = size
+ self.style = t2tHighlighterStyle(self.editor, self.style.name)
+ self.rehighlight()
+
+ def parseInDocRules(self):
+ oldRules = self.inDocRules
+ self.inDocRules = []
+
+ t = self.thisDocument.toPlainText()
+
+ # Get all conf files
+ confs = []
+ lines = t.split("\n")
+ for l in lines:
+ r = QRegExp(r'^%!includeconf:\s*([^\s]*)\s*')
+ if r.indexIn(l) != -1:
+ confs.append(r.cap(1))
+
+ # Try to load conf files
+ for c in confs:
+ try:
+ import codecs
+ f = self.editor.fileWidget.file
+ d = QDir.cleanPath(QFileInfo(f).absoluteDir().absolutePath()+"/"+c)
+ file = codecs.open(d, 'r', "utf-8")
+ except:
+ print("Error: cannot open {}.".format(c))
+ continue
+ # We add the content to the current lines of the current document
+ lines += file.readlines() #lines.extend(file.readlines())
+
+ #b = self.thisDocument.firstBlock()
+ lastColor = ""
+
+ #while b.isValid():
+ for l in lines:
+ text = l #b.text()
+ r = QRegExp(ur'^%!p[or][se]t?proc[^\s]*\s*:\s*(\'[^\']*\'|\"[^\"]*\")\s*(\'[^\']*\'|\"[^\"]*\")')
+ if r.indexIn(text) != -1:
+ rule = r.cap(1)[1:-1]
+ # Check if there was a color-comment above that post/preproc bloc
+ if lastColor:
+ self.inDocRules.append((str(rule), lastColor))
+ # Check if previous block is a comment like it should
+ else:
+ previousText = lines[lines.indexOf(l)-1] #b.previous().text()
+ r = QRegExp(r'^%.*\s\((.*)\)')
+ if r.indexIn(previousText) != -1:
+ lastColor = r.cap(1)
+ self.inDocRules.append((str(rule), lastColor))
+ else:
+ lastColor = ""
+ #b = b.next()
+
+ if oldRules != self.inDocRules:
+ #Rules have changed, we need to rehighlight
+ #print("Rules have changed.", len(self.inDocRules))
+ #self.rehighlight() # Doesn't work (seg fault), why?
+ pass
+ #b = self.thisDocument.firstBlock()
+ #while b.isValid():
+ #for (r, c) in self.inDocRules:
+ #r = QRegExp(r)
+ #pos = r.indexIn(b.text())
+ #if pos >= 0:
+ #print("rehighlighting:", b.text())
+ #self.rehighlightBlock(b)
+ #break
+ #b = b.next()
diff --git a/src/ui/editors/t2tHighlighterStyle.py b/src/ui/editors/t2tHighlighterStyle.py
new file mode 100644
index 00000000..3b3c4eab
--- /dev/null
+++ b/src/ui/editors/t2tHighlighterStyle.py
@@ -0,0 +1,245 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+from qt import *
+from ui.editors.t2tFunctions import *
+from ui.editors.blockUserData import blockUserData
+
+#TODO: creates a general way to generate styles (and edit/import/export)
+
+
+class t2tHighlighterStyle ():
+ """Style for the Syntax highlighter for the Txt2Tags language.
+ """
+
+ validStyles = ["Default", "Monospace"]
+
+ def __init__(self, editor, name="Default"):
+
+ self.editor = editor
+ self.name = name
+
+ # Defaults
+ self.defaultFontPointSize = self.editor.defaultFontPointSize
+ self.defaultFontFamily = ""
+ self.tabStopWidth = 40
+
+ self.setupEditor()
+
+ if self.name == "Default":
+ self.initDefaults()
+ #Temporary other theme
+ elif self.name == "Monospace":
+ self.defaultFontFamily = "Monospace"
+ self.initDefaults()
+ for i in self.styles:
+ f = self.styles[i]
+ f.setFontFixedPitch(True)
+ f.setFontFamily(self.defaultFontFamily)
+ f.setFontPointSize(self.defaultFontPointSize)
+ self.styles[i] = f
+
+ def setupEditor(self):
+ self.editor.setTabStopWidth(self.tabStopWidth)
+
+ def initDefaults(self):
+ self.styles = {}
+ for i in [State.CODE_AREA,
+ State.CODE_LINE,
+ State.COMMENT_AREA,
+ State.COMMENT_LINE,
+ State.SETTINGS_LINE,
+ State.BLOCKQUOTE_LINE,
+ State.RAW_AREA,
+ State.RAW_LINE,
+ State.TAGGED_AREA,
+ State.TAGGED_LINE,
+ State.TITLE_1,
+ State.TITLE_2,
+ State.TITLE_3,
+ State.TITLE_4,
+ State.TITLE_5,
+ State.NUMBERED_TITLE_1,
+ State.NUMBERED_TITLE_2,
+ State.NUMBERED_TITLE_3,
+ State.NUMBERED_TITLE_4,
+ State.NUMBERED_TITLE_5,
+ State.TABLE_HEADER,
+ State.TABLE_LINE,
+ State.HORIZONTAL_LINE,
+ State.MARKUP,
+ State.LIST_BULLET,
+ State.LIST_BULLET_ENDS,
+ State.LINKS,
+ State.MACRO,
+ State.DEFAULT,
+ State.HEADER_LINE]:
+ self.styles[i] = self.makeFormat(preset=i)
+
+ def format(self, state):
+ return self.styles[state]
+
+ def beautifyFormat(self, base, beautifiers):
+ "Apply beautifiers given in beautifiers array to format"
+ if max(beautifiers) == 2:
+ return self.makeFormat(preset=State.MARKUP, base=base)
+ else:
+ if beautifiers[0]: # bold
+ base.setFontWeight(QFont.Bold)
+ if beautifiers[1]: # italic
+ base.setFontItalic(True)
+ if beautifiers[2]: # underline
+ base.setFontUnderline(True)
+ if beautifiers[3]: # strikeout
+ base.setFontStrikeOut(True)
+ if beautifiers[4]: # code
+ base = self.makeFormat(base=base, preset=State.CODE_LINE)
+ if beautifiers[5]: # tagged
+ base = self.makeFormat(base=base, preset=State.TAGGED_LINE)
+ return base
+
+ def formatBlock(self, block, state):
+ "Apply transformation to given block."
+ blockFormat = QTextBlockFormat()
+
+ if state == State.BLOCKQUOTE_LINE:
+ # Number of tabs
+ n = block.text().indexOf(QRegExp(r'[^\t]'), 0)
+ blockFormat.setIndent(0)
+ blockFormat.setTextIndent(-self.tabStopWidth * n)
+ blockFormat.setLeftMargin(self.tabStopWidth * n)
+ #blockFormat.setRightMargin(self.editor.contentsRect().width()
+ # - self.editor.lineNumberAreaWidth()
+ # - fm.width("X") * self.editor.LimitLine
+ #+ self.editor.tabStopWidth())
+ blockFormat.setAlignment(Qt.AlignJustify)
+ if self.name == "Default" :
+ blockFormat.setTopMargin(5)
+ blockFormat.setBottomMargin(5)
+ elif state == State.HEADER_LINE:
+ blockFormat.setBackground(QColor("#EEEEEE"))
+ elif state in State.LIST:
+ data = blockUserData.getUserData(block)
+ if str(data.listSymbol()) in "+-":
+ blockFormat.setBackground(QColor("#EEFFEE"))
+ else:
+ blockFormat.setBackground(QColor("#EEEEFA"))
+ n = blockUserData.getUserData(block).leadingSpaces() + 1
+ f = QFontMetrics(QFont(self.defaultFontFamily,
+ self.defaultFontPointSize))
+ fm = f.width(" " * n +
+ blockUserData.getUserData(block).listSymbol())
+ blockFormat.setTextIndent(-fm)
+ blockFormat.setLeftMargin(fm)
+ if blockUserData.getUserState(block) == State.LIST_BEGINS and\
+ self.name == "Default":
+ blockFormat.setTopMargin(5)
+ return blockFormat
+
+ def makeFormat(self, color='', style='', size='', base='', fixedPitch='',
+ preset='', title_level='', bgcolor=''):
+ """
+ Returns a QTextCharFormat with the given attributes, using presets.
+ """
+
+ _color = QColor()
+ _format = QTextCharFormat()
+ size = self.defaultFontPointSize
+ _format.setFontFamily(self.defaultFontFamily)
+
+ # Base
+ if base: _format = base
+
+ # Presets
+ if preset in [State.CODE_AREA, State.CODE_LINE, "code"]:
+ style = "bold"
+ color = "black"
+ fixedPitch = True
+ _format.setBackground(QColor("#EEEEEE"))
+
+ if preset in [State.COMMENT_AREA, State.COMMENT_LINE, "comment"]:
+ style = "italic"
+ color = "darkGreen"
+
+ if preset in [State.SETTINGS_LINE, "setting", State.MACRO]:
+ #style = "italic"
+ color = "magenta"
+
+ if preset in [State.BLOCKQUOTE_LINE]:
+ color = "red"
+
+ if preset in [State.HEADER_LINE]:
+ size = size * 2
+ print size
+
+ if preset in [State.RAW_AREA, State.RAW_LINE, "raw"]:
+ color = "blue"
+
+ if preset in [State.TAGGED_AREA, State.TAGGED_LINE, "tagged"]:
+ color = "purple"
+
+ if preset in State.TITLES:
+ style = "bold"
+ color = "darkRed" if State.titleLevel(preset) % 2 == 1 else "blue"
+ size = (self.defaultFontPointSize
+ + 11 - 2 * State.titleLevel(preset))
+
+ if preset == State.TABLE_HEADER:
+ style = "bold"
+ color = "darkMagenta"
+
+ if preset == State.TABLE_LINE:
+ color = "darkMagenta"
+
+ if preset == State.LIST_BULLET:
+ color = "red"
+ style = "bold"
+ fixedPitch = True
+
+ if preset == State.LIST_BULLET_ENDS:
+ color = "darkGray"
+ fixedPitch = True
+
+ if preset in [State.MARKUP, "markup"]:
+ color = "darkGray"
+
+ if preset in [State.HORIZONTAL_LINE]:
+ color = "cyan"
+ fixedPitch = True
+
+ if preset == State.LINKS:
+ color="blue"
+ #style="underline"
+
+ if preset == "selected":
+ _format.setBackground(QColor("yellow"))
+
+ if preset == "higlighted":
+ bgcolor = "yellow"
+
+ if preset == State.DEFAULT:
+ size = self.defaultFontPointSize
+ _format.setFontFamily(self.defaultFontFamily)
+
+ # Manual formatting
+ if color:
+ _color.setNamedColor(color)
+ _format.setForeground(_color)
+ if bgcolor:
+ _color.setNamedColor(bgcolor)
+ _format.setBackground(_color)
+
+ if 'bold' in style:
+ _format.setFontWeight(QFont.Bold)
+ if 'italic' in style:
+ _format.setFontItalic(True)
+ if 'strike' in style:
+ _format.setFontStrikeOut(True)
+ if 'underline' in style:
+ _format.setFontUnderline(True)
+ if size:
+ _format.setFontPointSize(size)
+ if fixedPitch:
+ _format.setFontFixedPitch(True)
+
+ return _format
diff --git a/src/ui/mainWindow.py b/src/ui/mainWindow.py
index 8df07adf..34460344 100644
--- a/src/ui/mainWindow.py
+++ b/src/ui/mainWindow.py
@@ -1103,7 +1103,7 @@ class Ui_MainWindow(object):
self.menubar.addAction(self.menu_Aide.menuAction())
self.retranslateUi(MainWindow)
- self.tabMain.setCurrentIndex(5)
+ self.tabMain.setCurrentIndex(6)
self.tabSummary.setCurrentIndex(0)
self.tabPersos.setCurrentIndex(0)
self.tabPlot.setCurrentIndex(0)
@@ -1273,9 +1273,9 @@ class Ui_MainWindow(object):
self.actShowHelp.setText(_translate("MainWindow", "Afficher les &bulles d\'aide"))
self.actShowHelp.setShortcut(_translate("MainWindow", "Ctrl+Shift+B"))
-from ui.collapsibleGroupBox2 import collapsibleGroupBox2
-from ui.cmbOutlinePersoChoser import cmbOutlinePersoChoser
-from ui.sldImportance import sldImportance
from ui.cmbOutlineStatusChoser import cmbOutlineStatusChoser
+from ui.cmbOutlinePersoChoser import cmbOutlinePersoChoser
+from ui.collapsibleGroupBox2 import collapsibleGroupBox2
from ui.chkOutlineCompile import chkOutlineCompile
-from ui.editorWidget import editorWidget
+from ui.sldImportance import sldImportance
+from ui.editors.editorWidget import editorWidget
diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui
index 6f888868..b328e988 100644
--- a/src/ui/mainWindow.ui
+++ b/src/ui/mainWindow.ui
@@ -18,7 +18,7 @@
-
- 5
+ 6
true
@@ -2185,7 +2185,7 @@
editorWidget
QWidget
-
+ ui.editors.editorWidget.h
1
diff --git a/test_project/outline.xml b/test_project/outline.xml
index 9eb5373a..fb53a2da 100644
--- a/test_project/outline.xml
+++ b/test_project/outline.xml
@@ -1,9 +1,9 @@
-
+
-
+
@@ -14,12 +14,12 @@
-
+
-
+