mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-16 02:42:28 +12:00
41e59d71c1
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
422 lines
16 KiB
Python
422 lines
16 KiB
Python
#!/usr/bin/env python
|
||
# --!-- coding: utf8 --!--
|
||
import json
|
||
import os
|
||
|
||
from PyQt5.QtCore import Qt, QSize
|
||
from PyQt5.QtGui import QIcon, QFontMetrics, QFont
|
||
from PyQt5.QtWidgets import QWidget, QTableWidgetItem, QListWidgetItem, QTreeView
|
||
|
||
from manuskript.functions import mainWindow, writablePath
|
||
from manuskript.ui.exporters.manuskript.plainTextSettings_ui import Ui_exporterSettings
|
||
from manuskript.ui import style as S
|
||
|
||
|
||
class exporterSettings(QWidget, Ui_exporterSettings):
|
||
def __init__(self, _format, parent=None):
|
||
QWidget.__init__(self, parent)
|
||
self.setupUi(self)
|
||
self.toolBox.setStyleSheet(S.toolBoxSS())
|
||
|
||
self.mw = mainWindow()
|
||
self._format = _format
|
||
self.settings = {}
|
||
|
||
#################################################################
|
||
# Content
|
||
|
||
self.grpContentFilters.button.setChecked(False)
|
||
|
||
h = self.tblContent.horizontalHeader()
|
||
h.setSectionResizeMode(h.ResizeToContents)
|
||
h.setSectionResizeMode(0, h.Stretch)
|
||
|
||
self.contentUpdateTable()
|
||
self.chkContentMore.toggled.connect(self.contentTableToggle)
|
||
self.contentTableToggle(False)
|
||
|
||
# Labels
|
||
self.lstContentLabels.clear()
|
||
h = QFontMetrics(self.font()).height()
|
||
for i in range(0, self.mw.mdlLabels.rowCount()):
|
||
item = self.mw.mdlLabels.item(i, 0)
|
||
if item:
|
||
item = QListWidgetItem(item.icon(), item.text())
|
||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||
item.setCheckState(Qt.Checked)
|
||
item.setSizeHint(QSize(100, h))
|
||
self.lstContentLabels.addItem(item)
|
||
|
||
self.chkContentLabels.toggled.connect(self.lstContentLabels.setVisible)
|
||
self.chkContentLabels.toggled.connect(lambda: self.listWidgetAdjustToContent(self.lstContentLabels))
|
||
self.lstContentLabels.setVisible(False)
|
||
|
||
# Status
|
||
self.lstContentStatus.clear()
|
||
h = QFontMetrics(self.font()).height()
|
||
for i in range(0, self.mw.mdlStatus.rowCount()):
|
||
item = self.mw.mdlStatus.item(i, 0)
|
||
if item:
|
||
item = QListWidgetItem(item.icon(), item.text())
|
||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||
item.setCheckState(Qt.Checked)
|
||
item.setSizeHint(QSize(100, h))
|
||
self.lstContentStatus.addItem(item)
|
||
|
||
self.chkContentStatus.toggled.connect(self.lstContentStatus.setVisible)
|
||
self.chkContentStatus.toggled.connect(lambda: self.listWidgetAdjustToContent(self.lstContentStatus))
|
||
self.lstContentStatus.setVisible(False)
|
||
|
||
# Root item
|
||
self.cmbContentParent.setModel(self.mw.mdlOutline)
|
||
v = QTreeView()
|
||
self.cmbContentParent.setView(v)
|
||
v.setHeaderHidden(True)
|
||
for i in range(1, self.mw.mdlOutline.columnCount()):
|
||
v.hideColumn(i)
|
||
self.chkContentParent.toggled.connect(self.cmbContentParent.setVisible)
|
||
self.cmbContentParent.hide()
|
||
|
||
#################################################################
|
||
# Separations
|
||
|
||
for cmb in [self.cmbSepFF, self.cmbSepTT, self.cmbSepFT, self.cmbSepTF]:
|
||
cmb.clear()
|
||
|
||
cmb.addItem(self.tr("Empty line"), "empty")
|
||
cmb.addItem(self.tr("Custom"), "custom")
|
||
cmb.currentIndexChanged.connect(self.sepCmbChanged)
|
||
|
||
#################################################################
|
||
# Transformations
|
||
|
||
h = self.tblReplacements.horizontalHeader()
|
||
h.setSectionResizeMode(h.ResizeToContents)
|
||
h.setSectionResizeMode(1, h.Stretch)
|
||
h.setSectionResizeMode(2, h.Stretch)
|
||
|
||
# Cf. https://en.wikipedia.org/wiki/Quotation_mark
|
||
self.cmbTransDoubleQuotes.clear()
|
||
self.cmbTransDoubleQuotes.addItems(["”___“", "“___”", "«___»"])
|
||
self.cmbTransSingleQuote.clear()
|
||
self.cmbTransSingleQuote.addItems(["‘___’", "‹___›"])
|
||
|
||
for cmb in [self.cmbTransDoubleQuotes, self.cmbTransSingleQuote]:
|
||
cmb.addItem(self.tr("Custom"), "custom")
|
||
cmb.currentIndexChanged.connect(self.transCmbChanged)
|
||
cmb.currentIndexChanged.emit(0)
|
||
|
||
self.btnTransAdd.clicked.connect(lambda: self.transAddTableRow(checked=True))
|
||
self.btnTransRemove.clicked.connect(self.transRemoveTableRow)
|
||
self.tableWidgetAdjustToContent(self.tblReplacements)
|
||
|
||
#################################################################
|
||
# Preview
|
||
|
||
self.cmbPreviewFont.setCurrentFont(self.font())
|
||
self.spnPreviewSize.setValue(self.font().pointSize())
|
||
|
||
#################################################################
|
||
# Final stuff
|
||
|
||
self.toolBox.setCurrentIndex(0)
|
||
|
||
###################################################################################################################
|
||
# SETTINGS
|
||
###################################################################################################################
|
||
|
||
def loadSettings(self):
|
||
filename = self.getSettingsPath()
|
||
if os.path.exists(filename):
|
||
with open(filename, 'r', encoding="utf-8") as f:
|
||
self.settings = json.load(f)
|
||
self.updateFromSettings()
|
||
|
||
# Default values
|
||
else:
|
||
self.getSettings()
|
||
|
||
def writeSettings(self):
|
||
self.getSettings()
|
||
with open(self.getSettingsPath(), 'w', encoding="utf-8", newline="\n") as f:
|
||
# json.dumps(json.loads(json.dumps(allSettings)), indent=4, sort_keys=True)
|
||
json.dump(self.settings, f, indent=4, sort_keys=True)
|
||
|
||
def getSettingsPath(self):
|
||
return os.path.join(writablePath(), "exporter.ini")
|
||
|
||
def updateFromSettings(self):
|
||
settings = self.settings
|
||
|
||
# Content
|
||
s = settings["Content"]
|
||
self.chkContentMore.setChecked(s["More"])
|
||
|
||
if not s["More"]:
|
||
self.tblContent.item(0, 1).setCheckState(Qt.Checked if s["FolderTitle"] else Qt.Unchecked)
|
||
self.tblContent.item(1, 1).setCheckState(Qt.Checked if s["TextTitle"] else Qt.Unchecked)
|
||
self.tblContent.item(1, 2).setCheckState(Qt.Checked if s["TextText"] else Qt.Unchecked)
|
||
|
||
else:
|
||
nLevel = len(s["FolderTitle"])
|
||
for i in range(nLevel):
|
||
item = self.tblContent.item(i + 2, 1)
|
||
if item:
|
||
item.setCheckState(Qt.Checked if s["FolderTitle"][i] else Qt.Unchecked)
|
||
item = self.tblContent.item(i + 2 + nLevel, 1)
|
||
if item:
|
||
item.setCheckState(Qt.Checked if s["TextTitle"][i] else Qt.Unchecked)
|
||
item = self.tblContent.item(i + 2 + nLevel, 2)
|
||
if item:
|
||
item.setCheckState(Qt.Checked if s["TextText"][i] else Qt.Unchecked)
|
||
|
||
self.chkContentIgnoreCompile.setChecked(s["IgnoreCompile"])
|
||
self.chkContentParent.setChecked(s["Parent"])
|
||
self.chkContentLabels.setChecked(s["Labels"])
|
||
self.chkContentStatus.setChecked(s["Status"])
|
||
# FIXME: parent, labels, status
|
||
|
||
# Separations
|
||
s = settings["Separator"]
|
||
for val, cmb, txt in [
|
||
("FF", self.cmbSepFF, self.txtSepFF),
|
||
("TT", self.cmbSepTT, self.txtSepTT),
|
||
("FT", self.cmbSepFT, self.txtSepFT),
|
||
("TF", self.cmbSepTF, self.txtSepTF),
|
||
]:
|
||
if s[val] == "\n":
|
||
cmb.setCurrentIndex(0)
|
||
else:
|
||
cmb.setCurrentIndex(1)
|
||
txt.setText(self._format.escapes(s[val]))
|
||
|
||
# Transformations
|
||
s = settings["Transform"]
|
||
self.chkTransEllipse.setChecked(s["Ellipse"])
|
||
self.chkTransDash.setChecked(s["Dash"])
|
||
|
||
for val, chk, cmb, txtA, txtB in [
|
||
("DoubleQuotes", self.chkTransDoubleQuotes, self.cmbTransDoubleQuotes, self.txtTransDoubleQuotesA, self.txtTransDoubleQuotesB),
|
||
("SingleQuote", self.chkTransSingleQuote, self.cmbTransSingleQuote, self.txtTransSingleQuoteA, self.txtTransSingleQuoteB),
|
||
]:
|
||
chk.setChecked(s[val] != False)
|
||
if s[val]:
|
||
if cmb.findText(s[val]) != -1:
|
||
cmb.setCurrentText(s[val])
|
||
else:
|
||
cmb.setCurrentIndex(cmb.count() - 1)
|
||
txtA.setText(s[val].split("___")[0])
|
||
txtB.setText(s[val].split("___")[1])
|
||
|
||
self.chkTransSpaces.setChecked(s["Spaces"])
|
||
|
||
for i in s["Custom"]:
|
||
self.transAddTableRow(i[0], i[1], i[2], i[3])
|
||
|
||
# Preview
|
||
s = settings["Preview"]
|
||
f = QFont()
|
||
f.fromString(s["PreviewFont"])
|
||
self.cmbPreviewFont.setCurrentFont(f)
|
||
self.spnPreviewSize.setValue(f.pointSize())
|
||
|
||
def getSettings(self):
|
||
"""Updates settings from ui, and return."""
|
||
# Content
|
||
s = self.settings.get("Content", {})
|
||
s["More"] = self.chkContentMore.isChecked()
|
||
|
||
if not s["More"]:
|
||
s["FolderTitle"] = self.tblContent.item(0, 1).checkState() == Qt.Checked
|
||
s["TextTitle"] = self.tblContent.item(1, 1).checkState() == Qt.Checked
|
||
s["TextText"] = self.tblContent.item(1, 2).checkState() == Qt.Checked
|
||
|
||
else:
|
||
s["FolderTitle"] = []
|
||
s["TextTitle"] = []
|
||
s["TextText"] = []
|
||
nLevel = int((self.tblContent.rowCount() - 2) / 2)
|
||
for row in range(nLevel):
|
||
s["FolderTitle"].append(self.tblContent.item(2 + row, 1).checkState() == Qt.Checked)
|
||
s["TextTitle"].append(self.tblContent.item(2 + row + nLevel, 1).checkState() == Qt.Checked)
|
||
s["TextText"].append(self.tblContent.item(2 + row + nLevel, 2).checkState() == Qt.Checked)
|
||
|
||
s["IgnoreCompile"] = self.chkContentIgnoreCompile.isChecked()
|
||
s["Parent"] = self.chkContentParent.isChecked()
|
||
s["Labels"] = self.chkContentLabels.isChecked()
|
||
s["Status"] = self.chkContentStatus.isChecked()
|
||
self.settings["Content"] = s
|
||
# FIXME: parent, labels, status
|
||
|
||
# Separations
|
||
s = self.settings.get("Separator", {})
|
||
for val, cmb, txt in [
|
||
("FF", self.cmbSepFF, self.txtSepFF),
|
||
("TT", self.cmbSepTT, self.txtSepTT),
|
||
("FT", self.cmbSepFT, self.txtSepFT),
|
||
("TF", self.cmbSepTF, self.txtSepTF),
|
||
]:
|
||
if cmb.currentIndex() == 0:
|
||
s[val] = "\n"
|
||
|
||
else:
|
||
s[val] = self._format.descapes(txt.text())
|
||
self.settings["Separator"] = s
|
||
|
||
# Transformations
|
||
s = self.settings.get("Transform", {})
|
||
s["Ellipse"] = self.chkTransEllipse.isChecked()
|
||
s["Dash"] = self.chkTransDash.isChecked()
|
||
|
||
for val, chk, cmb, txtA, txtB in [
|
||
("DoubleQuotes", self.chkTransDoubleQuotes, self.cmbTransDoubleQuotes, self.txtTransDoubleQuotesA, self.txtTransDoubleQuotesB),
|
||
("SingleQuote", self.chkTransSingleQuote, self.cmbTransSingleQuote, self.txtTransSingleQuoteA, self.txtTransSingleQuoteB),
|
||
]:
|
||
if not chk.isChecked():
|
||
s[val] = False
|
||
else:
|
||
if cmb.currentData() == "custom":
|
||
s[val] = txtA.text() + "___" + txtB.text()
|
||
else:
|
||
s[val] = cmb.currentText()
|
||
|
||
s["Spaces"] = self.chkTransSpaces.isChecked()
|
||
|
||
s["Custom"] = []
|
||
for i in range(self.tblReplacements.rowCount()):
|
||
s["Custom"].append(self.getTableRowValues(self.tblReplacements, i))
|
||
self.settings["Transform"] = s
|
||
|
||
# Preview
|
||
s = self.settings.get("Preview", {})
|
||
f = self.cmbPreviewFont.currentFont()
|
||
f.setPointSize(self.spnPreviewSize.value())
|
||
s["PreviewFont"] = f.toString()
|
||
self.settings["Preview"] = s
|
||
|
||
return self.settings
|
||
|
||
def sepCmbChanged(self, index):
|
||
cmb = self.sender()
|
||
map = {
|
||
self.cmbSepFF: self.txtSepFF,
|
||
self.cmbSepTT: self.txtSepTT,
|
||
self.cmbSepFT: self.txtSepFT,
|
||
self.cmbSepTF: self.txtSepTF
|
||
}
|
||
map[cmb].setEnabled(cmb.currentData() == "custom")
|
||
|
||
def transCmbChanged(self, index):
|
||
cmb = self.sender()
|
||
map = {
|
||
self.cmbTransDoubleQuotes: (self.txtTransDoubleQuotesA, self.lblTransDoubleQuotes, self.txtTransDoubleQuotesB),
|
||
self.cmbTransSingleQuote: (self.txtTransSingleQuoteA, self.lblTransSingleQuote, self.txtTransSingleQuoteB),
|
||
}
|
||
for txt in map[cmb]:
|
||
txt.setVisible(cmb.currentData() == "custom")
|
||
|
||
def contentUpdateTable(self):
|
||
|
||
def addFolderRow(text=self.tr("Folder")):
|
||
self.tableWidgetAddRow(self.tblContent, [
|
||
self.tableWidgetMakeItem(text, "folder"),
|
||
self.tableWidgetMakeItem("", "", True, True),
|
||
])
|
||
|
||
def addTextRow(text=self.tr("Text")):
|
||
self.tableWidgetAddRow(self.tblContent, [
|
||
self.tableWidgetMakeItem(text, "text-x-generic"),
|
||
self.tableWidgetMakeItem("", "", True, False),
|
||
self.tableWidgetMakeItem("", "", True, True),
|
||
])
|
||
|
||
self.tblContent.setRowCount(0)
|
||
|
||
# Basic
|
||
addFolderRow()
|
||
addTextRow()
|
||
|
||
# Detailed
|
||
level = self.mw.mdlOutline.maxLevel()
|
||
|
||
for i in range(level):
|
||
addFolderRow(self.tr("{}Level {} folder").format(" " * i, i + 1))
|
||
|
||
for i in range(level):
|
||
addTextRow(self.tr("{}Level {} text").format(" " * i, i + 1))
|
||
|
||
self.tableWidgetAdjustToContent(self.tblContent)
|
||
|
||
def contentTableToggle(self, detailed):
|
||
for i in range(self.tblContent.rowCount()):
|
||
self.tblContent.setRowHidden(i, i in [0, 1] and detailed or (not i in [0, 1] and not detailed))
|
||
self.tableWidgetAdjustToContent(self.tblContent)
|
||
|
||
def getTableRowValues(self, table, row):
|
||
r = []
|
||
for col in range(table.columnCount()):
|
||
item = table.item(row, col)
|
||
|
||
if not item:
|
||
r.append(None)
|
||
elif item.flags() & Qt.ItemIsUserCheckable == Qt.ItemIsUserCheckable:
|
||
r.append(item.checkState() == Qt.Checked)
|
||
else:
|
||
r.append(item.text())
|
||
|
||
return r
|
||
|
||
def transAddTableRow(self, checked=True, A="", B="", regexp=False):
|
||
self.tableWidgetAddRow(self.tblReplacements, [
|
||
self.tableWidgetMakeItem("", "", True, checked),
|
||
self.tableWidgetMakeItem(A, "", False, False),
|
||
self.tableWidgetMakeItem(B, "", False, False),
|
||
self.tableWidgetMakeItem("", "", True, regexp),
|
||
])
|
||
self.tableWidgetAdjustToContent(self.tblReplacements)
|
||
|
||
def transRemoveTableRow(self):
|
||
self.tblReplacements.removeRow(self.tblReplacements.currentRow())
|
||
self.tableWidgetAdjustToContent(self.tblReplacements)
|
||
|
||
def tableWidgetMakeItem(self, text="", icon="", checkable=False, checked=False):
|
||
"""Creates a QTableWidgetItem with the given attributes."""
|
||
item = QTableWidgetItem(QIcon.fromTheme(icon), text)
|
||
if checkable:
|
||
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
|
||
item.setCheckState(Qt.Checked if checked else Qt.Unchecked)
|
||
else:
|
||
item.setFlags(item.flags() & ~Qt.ItemIsUserCheckable)
|
||
|
||
return item
|
||
|
||
def tableWidgetAddRow(self, table, items):
|
||
"""Appends the given items (list of QTableWidgetItems) to table."""
|
||
table.setRowCount(table.rowCount() + 1)
|
||
k = 0
|
||
for i in items:
|
||
table.setItem(table.rowCount() - 1, k, i)
|
||
k += 1
|
||
|
||
def tableWidgetAdjustToContent(self, table):
|
||
"""Set sizehint of QTableWidget table so that it matches content vertically."""
|
||
|
||
h = 0
|
||
|
||
h += table.horizontalHeader().height()
|
||
|
||
for i in range(table.rowCount()):
|
||
h += table.rowHeight(i)
|
||
|
||
table.setMinimumSize(QSize(0, h + 2))
|
||
table.setMaximumSize(QSize(16777215, h + 2))
|
||
|
||
def listWidgetAdjustToContent(self, lst):
|
||
"""Adjust listWidget to content."""
|
||
h = 0
|
||
for i in range(lst.count()):
|
||
h += lst.item(i).sizeHint().height()
|
||
|
||
lst.setMinimumSize(QSize(0, h+2))
|
||
lst.setMaximumSize(QSize(16777215, h+2))
|