mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-18 19:04:33 +12:00
Basic formatting and small corrections
This commit is contained in:
parent
546eb4d819
commit
ef1ba855e7
|
@ -448,6 +448,8 @@ class outlineItem():
|
|||
e = QTextEdit()
|
||||
e.setHtml(self._data[Outline.text])
|
||||
self._data[Outline.text] = e.toPlainText()
|
||||
elif oldType in ["txt", "t2t"] and data == "html":
|
||||
self._data[Outline.text] = self._data[Outline.text].replace("\n", "<br>")
|
||||
|
||||
# Setting data
|
||||
self._data[Outline(column)] = data
|
||||
|
|
|
@ -11,25 +11,26 @@ class basicHighlighter(QSyntaxHighlighter):
|
|||
|
||||
self.editor = editor
|
||||
self._misspelledColor = Qt.red
|
||||
self._defaultBlockFormat = QTextBlockFormat()
|
||||
self._defaultCharFormat = QTextCharFormat()
|
||||
|
||||
def setDefaultBlockFormat(self, bf):
|
||||
self._defaultBlockFormat = bf
|
||||
self.rehighlight()
|
||||
|
||||
def setDefaultCharFormat(self, cf):
|
||||
self._defaultCharFormat = cf
|
||||
self.rehighlight()
|
||||
|
||||
def setMisspelledColor(self, color):
|
||||
self._misspelledColor = color
|
||||
|
||||
def setStyle(self):
|
||||
"""t2tHighlighter needs to reupdates styles on some occasions (see themes.py).
|
||||
This lazy function allow to update without checking the type of highlighter.
|
||||
"""
|
||||
pass
|
||||
|
||||
def highlightBlock(self, text):
|
||||
"""Apply syntax highlighting to the given block of text.
|
||||
"""
|
||||
|
||||
QTextCursor(self.currentBlock()).setBlockFormat(self._defaultBlockFormat)
|
||||
#self.setFormat(0, len(text), self._defaultCharFormat)
|
||||
|
||||
# Spell checking
|
||||
# Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
|
||||
|
|
|
@ -2,7 +2,108 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from qt import *
|
||||
import re
|
||||
|
||||
def t2tFormatSelection(editor, style):
|
||||
"""
|
||||
Formats the current selection of ``editor`` in the format given by ``style``,
|
||||
style being:
|
||||
0: bold
|
||||
1: italic
|
||||
2: underline
|
||||
3: strike
|
||||
4: code
|
||||
5: tagged
|
||||
"""
|
||||
print("Formatting:", style)
|
||||
formatChar = "*/_-`'"[style]
|
||||
|
||||
# FIXME: doesn't work if selection spans over several blocks.
|
||||
|
||||
cursor = editor.textCursor()
|
||||
cursor.beginEditBlock()
|
||||
|
||||
if cursor.hasSelection():
|
||||
pass
|
||||
else:
|
||||
# If no selection, selects the word in which the cursor is now
|
||||
cursor.movePosition(QTextCursor.StartOfWord,
|
||||
QTextCursor.MoveAnchor)
|
||||
cursor.movePosition(QTextCursor.EndOfWord,
|
||||
QTextCursor.KeepAnchor)
|
||||
|
||||
if not cursor.hasSelection():
|
||||
# No selection means we are outside a word,
|
||||
# so we insert markup and put cursor in the middle
|
||||
cursor.insertText(formatChar * 4)
|
||||
cursor.setPosition(cursor.position() - 2)
|
||||
cursor.endEditBlock()
|
||||
editor.setTextCursor(cursor)
|
||||
# And we are done
|
||||
return
|
||||
|
||||
# Get start and end of selection
|
||||
start = cursor.selectionStart() - cursor.block().position()
|
||||
end = cursor.selectionEnd() - cursor.block().position()
|
||||
if start > end:
|
||||
start, end = end, start
|
||||
|
||||
# Whole block
|
||||
text = cursor.block().text()
|
||||
|
||||
# Adjusts selection to exclude the markup
|
||||
while text[start:start + 1] == formatChar:
|
||||
start += 1
|
||||
while text[end - 1:end] ==formatChar:
|
||||
end -= 1
|
||||
|
||||
# Get the text without formatting, and the array of format
|
||||
fText, fArray = textToFormatArrayNoMarkup(text)
|
||||
# Get the translated start and end of selection in the unformated text
|
||||
tStart, tEnd = translateSelectionToUnformattedText(text, start, end)
|
||||
|
||||
# We want only the array that contains the propper formatting
|
||||
propperArray = fArray[style]
|
||||
|
||||
if 0 in propperArray[tStart:tEnd]:
|
||||
# have some unformated text in the selection, so we format the
|
||||
# whole selection
|
||||
propperArray = propperArray[:tStart] + [1] * \
|
||||
(tEnd - tStart) + propperArray[tEnd:]
|
||||
else:
|
||||
# The whole selection is already formatted, so we remove the
|
||||
# formatting
|
||||
propperArray = propperArray[:tStart] + [0] * \
|
||||
(tEnd - tStart) + propperArray[tEnd:]
|
||||
|
||||
fArray = fArray[0:style] + [propperArray] + fArray[style + 1:]
|
||||
|
||||
text = reformatText(fText, fArray)
|
||||
|
||||
# Replaces the whole block
|
||||
cursor.movePosition(QTextCursor.StartOfBlock)
|
||||
cursor.movePosition(QTextCursor.EndOfBlock,
|
||||
QTextCursor.KeepAnchor)
|
||||
cursor.insertText(text)
|
||||
|
||||
cursor.setPosition(end + cursor.block().position())
|
||||
|
||||
cursor.endEditBlock()
|
||||
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
def t2tClearFormat(editor):
|
||||
"Clears format on ``editor``'s current selection."
|
||||
|
||||
cursor = editor.textCursor()
|
||||
cursor.beginEditBlock()
|
||||
|
||||
text = cursor.selectedText()
|
||||
t, a = textToFormatArrayNoMarkup(text)
|
||||
|
||||
cursor.insertText(t)
|
||||
cursor.endEditBlock()
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
def textToFormatArray(text):
|
||||
"""
|
||||
|
@ -131,24 +232,24 @@ def reformatText(text, markupArray):
|
|||
|
||||
for k in range(len(markupArray)):
|
||||
m = markupArray[k]
|
||||
open = False # Are we in an openned markup
|
||||
_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:
|
||||
if not _open and m[i] == 1:
|
||||
insert = True
|
||||
open = True
|
||||
_open = True
|
||||
|
||||
if open and m[i] == 0:
|
||||
if _open and m[i] == 0:
|
||||
insert = True
|
||||
open = False
|
||||
if open and m[i] > 1:
|
||||
_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
|
||||
_open = False
|
||||
alreadySeen.append(m[i])
|
||||
if insert:
|
||||
rText += markup[k]
|
||||
|
@ -161,7 +262,7 @@ def reformatText(text, markupArray):
|
|||
alreadySeen = []
|
||||
d += 2
|
||||
rText += text[i]
|
||||
if open:
|
||||
if _open:
|
||||
rText += markup[k]
|
||||
for j in range(len(markupArray)):
|
||||
# The other array still have the same length
|
||||
|
@ -175,12 +276,18 @@ def reformatText(text, markupArray):
|
|||
## 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")
|
||||
#r = QRegExp(r'(' + markup * 2 + ')(\s+)(.+)(' + markup * 2 + ')')
|
||||
#r.setMinimal(True)
|
||||
#text.replace(r, "\\2\\1\\3\\4")
|
||||
text = re.sub(r'(' + markup * 2 + ')(\s+?)(.+?)(' + markup * 2 + ')',
|
||||
"\\2\\1\\3\\4",
|
||||
text)
|
||||
#r = QRegExp(r'(' + markup * 2 + ')(.+)(\s+)(' + markup * 2 + ')')
|
||||
#r.setMinimal(True)
|
||||
#text.replace(r, "\\1\\2\\4\\3")
|
||||
text = re.sub(r'(' + markup * 2 + ')(.+?)(\s+?)(' + markup * 2 + ')',
|
||||
"\\1\\2\\4\\3",
|
||||
text)
|
||||
|
||||
return text
|
||||
|
||||
|
|
|
@ -27,9 +27,10 @@ class t2tHighlighter (QSyntaxHighlighter):
|
|||
# Stupid variable that fixes the loss of QTextBlockUserData.
|
||||
self.thisDocument = editor.document()
|
||||
|
||||
self.style = t2tHighlighterStyle(self.editor, style)
|
||||
self._defaultBlockFormat = QTextBlockFormat()
|
||||
self._defaultCharFormat = QTextCharFormat()
|
||||
self._misspelledColor = Qt.red
|
||||
self.style = t2tHighlighterStyle(self.editor, self._defaultCharFormat, style)
|
||||
|
||||
self.inDocRules = []
|
||||
|
||||
|
@ -65,6 +66,11 @@ class t2tHighlighter (QSyntaxHighlighter):
|
|||
def setDefaultBlockFormat(self, bf):
|
||||
self._defaultBlockFormat = bf
|
||||
self.rehighlight()
|
||||
|
||||
def setDefaultCharFormat(self, cf):
|
||||
self._defaultCharFormat = cf
|
||||
self.setStyle()
|
||||
self.rehighlight()
|
||||
|
||||
def setMisspelledColor(self, color):
|
||||
self._misspelledColor = color
|
||||
|
@ -95,7 +101,8 @@ class t2tHighlighter (QSyntaxHighlighter):
|
|||
|
||||
op = self.style.format(State.MARKUP)
|
||||
|
||||
self.setFormat(0, len(text), self.style.format(State.DEFAULT))
|
||||
#self.setFormat(0, len(text), self.style.format(State.DEFAULT))
|
||||
#self.setFormat(0, len(text), self._defaultCharFormat)
|
||||
|
||||
# InDocRules: is it a settings which might have a specific rule,
|
||||
# a comment which contains color infos, or a include conf?
|
||||
|
@ -341,13 +348,6 @@ class t2tHighlighter (QSyntaxHighlighter):
|
|||
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."""
|
||||
|
@ -490,7 +490,7 @@ class t2tHighlighter (QSyntaxHighlighter):
|
|||
|
||||
def setStyle(self, style="Default"):
|
||||
if style in t2tHighlighterStyle.validStyles:
|
||||
self.style = t2tHighlighterStyle(self.editor, style)
|
||||
self.style = t2tHighlighterStyle(self.editor, self._defaultCharFormat, style)
|
||||
else:
|
||||
self.style = None
|
||||
self.rehighlight()
|
||||
|
|
|
@ -14,13 +14,14 @@ class t2tHighlighterStyle ():
|
|||
|
||||
validStyles = ["Default", "Monospace"]
|
||||
|
||||
def __init__(self, editor, name="Default"):
|
||||
def __init__(self, editor, charFormat, name="Default"):
|
||||
|
||||
self.editor = editor
|
||||
self.name = name
|
||||
self._defaultCharFormat = charFormat
|
||||
|
||||
# Defaults
|
||||
self.defaultFontPointSize = self.editor.defaultFontPointSize
|
||||
#self.defaultFontPointSize = self.editor.defaultFontPointSize
|
||||
self.defaultFontFamily = qApp.font().family()
|
||||
self.tabStopWidth = 40
|
||||
|
||||
|
@ -36,7 +37,7 @@ class t2tHighlighterStyle ():
|
|||
f = self.styles[i]
|
||||
f.setFontFixedPitch(True)
|
||||
f.setFontFamily(self.defaultFontFamily)
|
||||
f.setFontPointSize(self.defaultFontPointSize)
|
||||
f.setFontPointSize(self._defaultCharFormat.font().pointSize())
|
||||
self.styles[i] = f
|
||||
|
||||
def setupEditor(self):
|
||||
|
@ -127,7 +128,7 @@ class t2tHighlighterStyle ():
|
|||
n = blockUserData.getUserData(block).leadingSpaces() + 1
|
||||
|
||||
f = QFontMetrics(QFont(self.defaultFontFamily,
|
||||
self.defaultFontPointSize))
|
||||
self._defaultCharFormat.font().pointSize()))
|
||||
fm = f.width(" " * n +
|
||||
blockUserData.getUserData(block).listSymbol())
|
||||
blockFormat.setTextIndent(-fm)
|
||||
|
@ -144,11 +145,10 @@ class t2tHighlighterStyle ():
|
|||
"""
|
||||
|
||||
_color = QColor()
|
||||
_format = QTextCharFormat()
|
||||
#size = self.defaultFontPointSize
|
||||
#_format.setFontFamily(self.defaultFontFamily)
|
||||
_format.setFont(self.editor.font())
|
||||
size = _format.fontPointSize()
|
||||
#_format = QTextCharFormat()
|
||||
#_format.setFont(self.editor.font())
|
||||
#size = _format.fontPointSize()
|
||||
_format = QTextCharFormat(self._defaultCharFormat)
|
||||
|
||||
# Base
|
||||
if base: _format = base
|
||||
|
@ -184,7 +184,7 @@ class t2tHighlighterStyle ():
|
|||
if preset in State.TITLES:
|
||||
style = "bold"
|
||||
color = "darkRed" if State.titleLevel(preset) % 2 == 1 else "blue"
|
||||
size = (self.defaultFontPointSize
|
||||
size = (self._defaultCharFormat.font().pointSize()
|
||||
+ 11 - 2 * State.titleLevel(preset))
|
||||
|
||||
if preset == State.TABLE_HEADER:
|
||||
|
|
|
@ -22,12 +22,14 @@ class textFormat(QWidget, Ui_textFormat):
|
|||
"Left": [self.btnLeft, "format-justify-left", self.tr("CTRL+L")],
|
||||
"Center": [self.btnCenter, "format-justify-center", self.tr("CTRL+E")],
|
||||
"Right": [self.btnRight, "format-justify-right", self.tr("CTRL+R")],
|
||||
"Justify": [self.btnJustify, "format-justify-fill", self.tr("CTRL+J")],
|
||||
}
|
||||
|
||||
for f in formats:
|
||||
val = formats[f]
|
||||
a = QAction(QIcon.fromTheme(val[1]), f, self)
|
||||
a.setShortcut(val[2])
|
||||
a.setToolTip("Format {} ({})".format(f, val[2]))
|
||||
a.triggered.connect(self.setFormat)
|
||||
val[0].setDefaultAction(a)
|
||||
|
||||
|
|
|
@ -70,6 +70,11 @@ class Ui_textFormat(object):
|
|||
self.btnRight.setIcon(icon)
|
||||
self.btnRight.setObjectName("btnRight")
|
||||
self.horizontalLayout_2.addWidget(self.btnRight)
|
||||
self.btnJustify = QtWidgets.QToolButton(self.align)
|
||||
self.btnJustify.setText("")
|
||||
self.btnJustify.setIcon(icon)
|
||||
self.btnJustify.setObjectName("btnJustify")
|
||||
self.horizontalLayout_2.addWidget(self.btnJustify)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem3)
|
||||
self.horizontalLayout_3.addWidget(self.align)
|
||||
|
|
|
@ -149,6 +149,18 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnJustify">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -212,12 +212,18 @@ def setThemeEditorDatas(editor, themeDatas, pixmap, screenRect):
|
|||
editor.setTabStopWidth(themeDatas["Spacings/TabWidth"])
|
||||
editor.document().setIndentWidth(themeDatas["Spacings/TabWidth"])
|
||||
|
||||
f = QFont()
|
||||
f.fromString(themeDatas["Text/Font"])
|
||||
editor.setFont(f)
|
||||
editor.highlighter.setMisspelledColor(QColor(themeDatas["Text/Misspelled"]))
|
||||
|
||||
editor.highlighter.setStyle() # Reupdates highlighter styles
|
||||
cf = QTextCharFormat()
|
||||
f = QFont()
|
||||
f.fromString(themeDatas["Text/Font"])
|
||||
cf.setFont(f)
|
||||
editor.highlighter.setDefaultCharFormat(cf)
|
||||
#f = QFont()
|
||||
#f.fromString(themeDatas["Text/Font"])
|
||||
editor.setFont(f)
|
||||
|
||||
|
||||
|
||||
def addThemePreviewText(pixmap, themeDatas, screenRect):
|
||||
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
from qt import *
|
||||
from enums import *
|
||||
from ui.editors.t2tHighlighter import *
|
||||
from ui.editors.t2tFunctions import *
|
||||
from ui.editors.basicHighlighter import *
|
||||
from ui.editors.textFormat import *
|
||||
from models.outlineModel import *
|
||||
from functions import *
|
||||
import re
|
||||
|
||||
try:
|
||||
import enchant
|
||||
|
@ -220,7 +222,8 @@ class textEditView(QTextEdit):
|
|||
if self._textFormat == "html":
|
||||
if self.toHtml() != toString(self._model.data(self._index)):
|
||||
#print(" Updating html")
|
||||
self.document().setHtml(toString(self._model.data(self._index)))
|
||||
html = self._model.data(self._index)
|
||||
self.document().setHtml(toString(html))
|
||||
else:
|
||||
if self.toPlainText() != toString(self._model.data(self._index)):
|
||||
#print(" Updating plaintext")
|
||||
|
@ -261,7 +264,11 @@ class textEditView(QTextEdit):
|
|||
if self.toHtml() != self._model.data(self._index):
|
||||
#print(" Submitting html")
|
||||
self._updating = True
|
||||
self._model.setData(self._index, self.toHtml())
|
||||
html = self.toHtml()
|
||||
# We don't store font settings
|
||||
html = re.sub(r"font-family:.*?;", "", html)
|
||||
html = re.sub(r"font-size:.*?;", "", html)
|
||||
self._model.setData(self._index, html)
|
||||
self._updating = False
|
||||
else:
|
||||
if self.toPlainText() != self._model.data(self._index):
|
||||
|
@ -405,6 +412,70 @@ class textEditView(QTextEdit):
|
|||
tF.setTextEdit(self)
|
||||
|
||||
def applyFormat(self, _format):
|
||||
#FIXME
|
||||
print(_format)
|
||||
|
||||
if self._textFormat == "html":
|
||||
|
||||
if _format == "Clear":
|
||||
|
||||
cursor = self.textCursor()
|
||||
|
||||
if _format == "Clear":
|
||||
fmt = QTextCharFormat()
|
||||
cursor.setCharFormat(fmt)
|
||||
bf = QTextBlockFormat()
|
||||
cursor.setBlockFormat(bf)
|
||||
|
||||
elif _format in ["Bold", "Italic", "Underline"]:
|
||||
|
||||
cursor = self.textCursor()
|
||||
|
||||
# If no selection, selects the word in which the cursor is now
|
||||
if not cursor.hasSelection():
|
||||
cursor.movePosition(QTextCursor.StartOfWord,
|
||||
QTextCursor.MoveAnchor)
|
||||
cursor.movePosition(QTextCursor.EndOfWord,
|
||||
QTextCursor.KeepAnchor)
|
||||
|
||||
fmt = cursor.charFormat()
|
||||
|
||||
if _format == "Bold":
|
||||
fmt.setFontWeight(QFont.Bold if fmt.fontWeight() != QFont.Bold else QFont.Normal)
|
||||
elif _format == "Italic":
|
||||
fmt.setFontItalic(not fmt.fontItalic())
|
||||
elif _format == "Underline":
|
||||
fmt.setFontUnderline(not fmt.fontUnderline())
|
||||
|
||||
fmt2 = QTextCharFormat()
|
||||
fmt2.setFontWeight(fmt.fontWeight())
|
||||
fmt2.setFontItalic(fmt.fontItalic())
|
||||
fmt2.setFontUnderline(fmt.fontUnderline())
|
||||
|
||||
cursor.mergeCharFormat(fmt2)
|
||||
|
||||
elif _format in ["Left", "Center", "Right", "Justify"]:
|
||||
|
||||
cursor = self.textCursor()
|
||||
|
||||
bf = cursor.blockFormat()
|
||||
bf.setAlignment(
|
||||
Qt.AlignLeft if _format == "Left" else
|
||||
Qt.AlignHCenter if _format == "Center" else
|
||||
Qt.AlignRight if _format == "Right" else
|
||||
Qt.AlignJustify)
|
||||
print(bf.alignment() == Qt.AlignLeft)
|
||||
|
||||
cursor.mergeBlockFormat(bf)
|
||||
self.setTextCursor(cursor)
|
||||
|
||||
elif self._textFormat == "t2t":
|
||||
if _format == "Bold":
|
||||
t2tFormatSelection(self, 0)
|
||||
elif _format == "Italic":
|
||||
t2tFormatSelection(self, 1)
|
||||
elif _format == "Underline":
|
||||
t2tFormatSelection(self, 2)
|
||||
elif _format == "Clear":
|
||||
t2tClearFormat(self)
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue