Improve build settings dialog (#1499)
This commit is contained in:
@@ -21,7 +21,7 @@ backward = typ_chevron-left.svg
|
||||
bookmark = typ_bookmark.svg
|
||||
browse = typ_folder-open.svg
|
||||
build_excluded = typ_cancel.svg
|
||||
build_filtered = typ_filter.svg
|
||||
build_filtered = typ_arrow-forward.svg
|
||||
build_included = typ_pin.svg
|
||||
bullet-off = typ_media-record-outline.svg
|
||||
bullet-on = typ_media-record.svg
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m13.25 3.5625c-0.32 0-0.64 0.12125-0.88375 0.365-0.24375 0.245-0.36625 0.565-0.36625 0.885v3.1988c-5.625 0.6225-10 5.3862-10 11.176v1.25c2.8062-4.2788 6.5625-4.9 10-4.9862v3.1112c0 0.31875 0.1225 0.64 0.36625 0.88375s0.56375 0.36625 0.88375 0.36625 0.64-0.1225 0.88375-0.36625l7.8662-7.7588-7.8662-7.76c-0.24375-0.24375-0.56375-0.365-0.88375-0.365z" fill="#9c9" stroke-width="1.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 538 B |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m20.694 2h-17.387c-1.3661 0-1.7387 0.85714-0.74516 2l5.2161 6c0.99354 1.1429 1.7387 3.2857 1.7387 4.8571v7.1429l4.9677-2.8571v-5c0-1.1429 0.74516-3 1.7387-4.1429l5.2161-6c0.99354-1.1429 0.62096-2-0.74516-2z" fill="#f99157" stroke-width="1.332"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 398 B |
@@ -21,7 +21,7 @@ backward = typ_chevron-left.svg
|
||||
bookmark = typ_bookmark.svg
|
||||
browse = typ_folder-open.svg
|
||||
build_excluded = typ_cancel.svg
|
||||
build_filtered = typ_filter.svg
|
||||
build_filtered = typ_arrow-forward.svg
|
||||
build_included = typ_pin.svg
|
||||
bullet-off = typ_media-record-outline.svg
|
||||
bullet-on = typ_media-record.svg
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m13.25 3.5625c-0.32 0-0.64 0.12125-0.88375 0.365-0.24375 0.245-0.36625 0.565-0.36625 0.885v3.1988c-5.625 0.6225-10 5.3862-10 11.176v1.25c2.8062-4.2788 6.5625-4.9 10-4.9862v3.1112c0 0.31875 0.1225 0.64 0.36625 0.88375s0.56375 0.36625 0.88375 0.36625 0.64-0.1225 0.88375-0.36625l7.8662-7.7588-7.8662-7.76c-0.24375-0.24375-0.56375-0.365-0.88375-0.365z" fill="#718c00" stroke-width="1.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 541 B |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m20.694 2h-17.387c-1.3661 0-1.7387 0.85714-0.74516 2l5.2161 6c0.99354 1.1429 1.7387 3.2857 1.7387 4.8571v7.1429l4.9677-2.8571v-5c0-1.1429 0.74516-3 1.7387-4.1429l5.2161-6c0.99354-1.1429 0.62096-2-0.74516-2z" fill="#f5871f" stroke-width="1.332"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 398 B |
@@ -257,6 +257,7 @@ class nwLabels:
|
||||
|
||||
class nwHeadFmt:
|
||||
|
||||
BR = "{BR}"
|
||||
TITLE = "{Title}"
|
||||
CH_NUM = "{Chapter}"
|
||||
CH_WORD = "{Chapter:Word}"
|
||||
|
||||
@@ -84,7 +84,7 @@ SETTINGS_TEMPLATE = {
|
||||
}
|
||||
|
||||
SETTINGS_LABELS = {
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Types"),
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
|
||||
"filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
|
||||
"filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
|
||||
"filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
|
||||
@@ -125,10 +125,10 @@ SETTINGS_LABELS = {
|
||||
"format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
|
||||
"format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
|
||||
|
||||
"odt": QT_TRANSLATE_NOOP("Builds", "Open Document"),
|
||||
"odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
|
||||
"odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
|
||||
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML"),
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
|
||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ from pathlib import Path
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwKeyWords, nwLabels, nwHtmlUnicode
|
||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer, stripEscape
|
||||
|
||||
@@ -244,27 +244,27 @@ class ToHtml(Tokenizer):
|
||||
parStyle = None
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
|
||||
|
||||
elif tType == self.T_UNNUM:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
|
||||
|
||||
elif tType == self.T_HEAD1:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
|
||||
|
||||
elif tType == self.T_HEAD2:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
|
||||
|
||||
elif tType == self.T_HEAD3:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
|
||||
|
||||
elif tType == self.T_HEAD4:
|
||||
tHead = tText.replace(r"\\", "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tmpResult.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
|
||||
@@ -27,7 +27,7 @@ import logging
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.constants import nwHeadFmt, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer
|
||||
|
||||
@@ -122,27 +122,27 @@ class ToMarkdown(Tokenizer):
|
||||
thisPar = []
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"# {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_UNNUM:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"## {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_HEAD1:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"# {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_HEAD2:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"## {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_HEAD3:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"### {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_HEAD4:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
tmpResult.append(f"#### {tHead}\n\n")
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
|
||||
@@ -36,7 +36,7 @@ from datetime import datetime
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import xmlIndent
|
||||
from novelwriter.constants import nwKeyWords, nwLabels
|
||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer, stripEscape
|
||||
|
||||
@@ -445,27 +445,27 @@ class ToOdt(Tokenizer):
|
||||
parStyle = None
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Title", oStyle, tHead, isHead=False) # Title must be text:p
|
||||
|
||||
elif tType == self.T_UNNUM:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2")
|
||||
|
||||
elif tType == self.T_HEAD1:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_1", oStyle, tHead, isHead=True, oLevel="1")
|
||||
|
||||
elif tType == self.T_HEAD2:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2")
|
||||
|
||||
elif tType == self.T_HEAD3:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_3", oStyle, tHead, isHead=True, oLevel="3")
|
||||
|
||||
elif tType == self.T_HEAD4:
|
||||
tHead = tText.replace(r"\\", "\n")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_4", oStyle, tHead, isHead=True, oLevel="4")
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Custom Widget: Paged SideBar
|
||||
==========================================
|
||||
A custom widget for making a sidebar for flipping through pages
|
||||
|
||||
File History:
|
||||
Created: 2023-02-21 [2.1b1] NPagedSideBar
|
||||
@@ -24,20 +23,26 @@ General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QColor, QPainter
|
||||
from PyQt5.QtCore import QRectF, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QColor, QPaintEvent, QPainter, QPolygon
|
||||
from PyQt5.QtCore import QPoint, QRectF, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QButtonGroup, QLabel, QSizePolicy, QStyle, QStyleOptionToolButton, QToolBar,
|
||||
QToolButton, QWidget
|
||||
QAbstractButton, QAction, QButtonGroup, QLabel, QSizePolicy, QStyle,
|
||||
QStyleOptionToolButton, QToolBar, QToolButton, QWidget
|
||||
)
|
||||
|
||||
|
||||
class NPagedSideBar(QToolBar):
|
||||
"""Extensions: Paged Side Bar
|
||||
|
||||
A side bar widget that holds buttons that mimic tabs. It is designed
|
||||
to be used in combination with a QStackedWidget for options panels.
|
||||
"""
|
||||
|
||||
buttonClicked = pyqtSignal(int)
|
||||
|
||||
def __init__(self, parent):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self._buttons = []
|
||||
@@ -58,7 +63,7 @@ class NPagedSideBar(QToolBar):
|
||||
|
||||
return
|
||||
|
||||
def setLabelColor(self, color):
|
||||
def setLabelColor(self, color: list | QColor) -> None:
|
||||
"""Set the text color for the labels."""
|
||||
if isinstance(color, list):
|
||||
self._labelCol = QColor(*color)
|
||||
@@ -66,7 +71,7 @@ class NPagedSideBar(QToolBar):
|
||||
self._labelCol = color
|
||||
return
|
||||
|
||||
def addSeparator(self):
|
||||
def addSeparator(self) -> None:
|
||||
"""Add a spacer widget."""
|
||||
spacer = QWidget(self)
|
||||
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
@@ -74,16 +79,16 @@ class NPagedSideBar(QToolBar):
|
||||
self.insertWidget(self._stretchAction, spacer)
|
||||
return
|
||||
|
||||
def addLabel(self, text):
|
||||
def addLabel(self, text: str) -> None:
|
||||
"""Add a new label to the toolbar."""
|
||||
label = NPagedToolLabel(self, self._labelCol)
|
||||
label = _NPagedToolLabel(self, self._labelCol)
|
||||
label.setText(text)
|
||||
self.insertWidget(self._stretchAction, label)
|
||||
return
|
||||
|
||||
def addButton(self, text, buttonId=-1):
|
||||
def addButton(self, text: str, buttonId: int = -1) -> QAction:
|
||||
"""Add a new button to the toolbar."""
|
||||
button = NPagedToolButton(self)
|
||||
button = _NPagedToolButton(self)
|
||||
button.setText(text)
|
||||
|
||||
action = self.insertWidget(self._stretchAction, button)
|
||||
@@ -94,7 +99,7 @@ class NPagedSideBar(QToolBar):
|
||||
|
||||
return action
|
||||
|
||||
def setSelected(self, buttonId):
|
||||
def setSelected(self, buttonId: int) -> None:
|
||||
"""Set the selected button."""
|
||||
self._group.button(buttonId).setChecked(True)
|
||||
return
|
||||
@@ -104,7 +109,7 @@ class NPagedSideBar(QToolBar):
|
||||
##
|
||||
|
||||
@pyqtSlot("QAbstractButton*")
|
||||
def _buttonClicked(self, button):
|
||||
def _buttonClicked(self, button: QAbstractButton) -> None:
|
||||
"""A button was clicked in the group, emit its id."""
|
||||
buttonId = self._group.id(button)
|
||||
if buttonId != -1:
|
||||
@@ -114,11 +119,11 @@ class NPagedSideBar(QToolBar):
|
||||
# END Class NPagedSideBar
|
||||
|
||||
|
||||
class NPagedToolButton(QToolButton):
|
||||
class _NPagedToolButton(QToolButton):
|
||||
|
||||
__slots__ = ("_bH", "_tM", "_lM", "_cR")
|
||||
__slots__ = ("_bH", "_tM", "_lM", "_cR", "_aH")
|
||||
|
||||
def __init__(self, parent):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
@@ -126,14 +131,15 @@ class NPagedToolButton(QToolButton):
|
||||
|
||||
fH = self.fontMetrics().height()
|
||||
self._bH = round(fH * 1.7)
|
||||
self._tM = (self._bH - fH) // 2
|
||||
self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)
|
||||
self._cR = self._lM // 2
|
||||
self._tM = (self._bH - fH)//2
|
||||
self._lM = 3*self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
|
||||
self._cR = self._lM//2
|
||||
self._aH = 2*fH//7
|
||||
self.setFixedHeight(self._bH)
|
||||
|
||||
return
|
||||
|
||||
def paintEvent(self, event):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Overload the paint event to draw a simple, left aligned text
|
||||
label, with a highlight when selected and a transparent base
|
||||
colour when hovered.
|
||||
@@ -144,6 +150,7 @@ class NPagedToolButton(QToolButton):
|
||||
paint = QPainter(self)
|
||||
paint.setRenderHint(QPainter.Antialiasing, True)
|
||||
paint.setPen(Qt.NoPen)
|
||||
paint.setBrush(Qt.NoBrush)
|
||||
|
||||
width = self.width()
|
||||
height = self.height()
|
||||
@@ -171,31 +178,41 @@ class NPagedToolButton(QToolButton):
|
||||
paint.setOpacity(1.0)
|
||||
paint.drawText(QRectF(self._lM, self._tM, tW, tH), Qt.AlignLeft, self.text())
|
||||
|
||||
tC = self.height()//2
|
||||
tW = self.width() - self._aH - self._lM
|
||||
if self.isChecked():
|
||||
paint.setBrush(textCol)
|
||||
paint.drawPolygon(QPolygon([
|
||||
QPoint(tW, tC - self._aH),
|
||||
QPoint(tW + self._aH, tC),
|
||||
QPoint(tW, tC + self._aH),
|
||||
]))
|
||||
|
||||
return
|
||||
|
||||
# END Class NPagedToolButton
|
||||
# END Class _NPagedToolButton
|
||||
|
||||
|
||||
class NPagedToolLabel(QLabel):
|
||||
class _NPagedToolLabel(QLabel):
|
||||
|
||||
__slots__ = ("_bH", "_tM", "_lM", "_textCol")
|
||||
|
||||
def __init__(self, parent, textColor=None):
|
||||
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
|
||||
fH = self.fontMetrics().height()
|
||||
self._bH = round(fH * 1.7)
|
||||
self._tM = (self._bH - fH) // 2
|
||||
self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)
|
||||
self._tM = (self._bH - fH)//2
|
||||
self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)//2
|
||||
self.setFixedHeight(self._bH)
|
||||
|
||||
self._textCol = textColor or self.palette().text().color()
|
||||
|
||||
return
|
||||
|
||||
def paintEvent(self, event):
|
||||
def paintEvent(self, event: QPaintEvent) -> None:
|
||||
"""Overload the paint event to draw a simple, left aligned text
|
||||
label that matches the button style.
|
||||
"""
|
||||
@@ -215,4 +232,4 @@ class NPagedToolLabel(QLabel):
|
||||
|
||||
return
|
||||
|
||||
# END Class NPagedToolLabel
|
||||
# END Class _NPagedToolLabel
|
||||
|
||||
@@ -1202,6 +1202,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
open a context menu in-place.
|
||||
"""
|
||||
tItem = None
|
||||
tHandle = None
|
||||
hasChild = False
|
||||
selItem = self.itemAt(clickPos)
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
@@ -1209,7 +1210,7 @@ class GuiProjectTree(QTreeWidget):
|
||||
tItem = self.theProject.tree[tHandle]
|
||||
hasChild = selItem.childCount() > 0
|
||||
|
||||
if tItem is None:
|
||||
if tItem is None or tHandle is None:
|
||||
logger.debug("No item found")
|
||||
return False
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5.QtGui import QColor, QCursor, QFont, QPalette, QResizeEvent
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
|
||||
from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QGridLayout, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
|
||||
@@ -231,13 +231,13 @@ class GuiManuscript(QDialog):
|
||||
# Events
|
||||
##
|
||||
|
||||
def closeEvent(self, event):
|
||||
def closeEvent(self, event: QCloseEvent):
|
||||
"""Capture the user closing the window so we can save GUI
|
||||
settings. We also check that we don't have a build settings
|
||||
dialog open.
|
||||
"""
|
||||
self._saveSettings()
|
||||
for obj in self.children():
|
||||
for obj in self.mainGui.children():
|
||||
# Make sure we don't have any settings windows open
|
||||
if isinstance(obj, GuiBuildSettings) and obj.isVisible():
|
||||
obj.close()
|
||||
@@ -330,15 +330,13 @@ class GuiManuscript(QDialog):
|
||||
def _buildManuscript(self):
|
||||
"""Open the build dialog and build the manuscript."""
|
||||
build = self._getSelectedBuild()
|
||||
if build is None:
|
||||
return
|
||||
if isinstance(build, BuildSettings):
|
||||
dlgBuild = GuiManuscriptBuild(self, self.mainGui, build)
|
||||
dlgBuild.exec_()
|
||||
|
||||
dlgBuild = GuiManuscriptBuild(self, self.mainGui, build)
|
||||
dlgBuild.exec_()
|
||||
|
||||
# After the build is done, save build settings changes
|
||||
if build.changed:
|
||||
self._builds.setBuild(build)
|
||||
# After the build is done, save build settings changes
|
||||
if build.changed:
|
||||
self._builds.setBuild(build)
|
||||
|
||||
return
|
||||
|
||||
@@ -376,10 +374,13 @@ class GuiManuscript(QDialog):
|
||||
return
|
||||
|
||||
def _getSelectedBuild(self) -> BuildSettings | None:
|
||||
"""Get the currently selected build."""
|
||||
bItems = self.buildList.selectedItems()
|
||||
if bItems:
|
||||
build = self._builds.getBuild(bItems[0].data(self.D_KEY))
|
||||
"""Get the currently selected build. If none are selected,
|
||||
automatically select the first one.
|
||||
"""
|
||||
items = self.buildList.selectedItems()
|
||||
item = items[0] if items else self.buildList.item(0)
|
||||
if item:
|
||||
build = self._builds.getBuild(item.data(self.D_KEY))
|
||||
if isinstance(build, BuildSettings):
|
||||
return build
|
||||
return None
|
||||
@@ -406,13 +407,23 @@ class GuiManuscript(QDialog):
|
||||
|
||||
def _openSettingsDialog(self, build: BuildSettings):
|
||||
"""Open the build settings dialog."""
|
||||
dlgSettings = GuiBuildSettings(self, self.mainGui, build)
|
||||
for obj in self.mainGui.children():
|
||||
# Don't open a second dialog if one exists
|
||||
if isinstance(obj, GuiBuildSettings):
|
||||
if obj.buildID == build.buildID:
|
||||
logger.debug("Found instance of GuiBuildSettings")
|
||||
obj.show()
|
||||
obj.raise_()
|
||||
return
|
||||
|
||||
dlgSettings = GuiBuildSettings(self.mainGui, build)
|
||||
dlgSettings.setModal(False)
|
||||
dlgSettings.show()
|
||||
dlgSettings.raise_()
|
||||
qApp.processEvents()
|
||||
dlgSettings.loadContent()
|
||||
dlgSettings.newSettingsReady.connect(self._processNewSettings)
|
||||
|
||||
return
|
||||
|
||||
def _updateBuildsList(self):
|
||||
@@ -634,7 +645,7 @@ class _PreviewWidget(QTextBrowser):
|
||||
)
|
||||
else:
|
||||
strBuildTime = self.tr("Unknown")
|
||||
text = "{0} {1}".format(self.tr("Built"), strBuildTime)
|
||||
text = "{0}: {1}".format(self.tr("Built"), strBuildTime)
|
||||
if self._buildName:
|
||||
text = "<b>{0}</b><br>{1}".format(self._buildName, text)
|
||||
self.ageLabel.setText(text)
|
||||
|
||||
@@ -69,8 +69,8 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
newSettingsReady = pyqtSignal(BuildSettings)
|
||||
|
||||
def __init__(self, parent: QWidget, mainGui: GuiMain, build: BuildSettings):
|
||||
super().__init__(parent=parent)
|
||||
def __init__(self, mainGui: GuiMain, build: BuildSettings) -> None:
|
||||
super().__init__(parent=mainGui)
|
||||
|
||||
logger.debug("Create: GuiBuildSettings")
|
||||
self.setObjectName("GuiBuildSettings")
|
||||
@@ -106,7 +106,7 @@ class GuiBuildSettings(QDialog):
|
||||
self.optSideBar.setLabelColor(self.mainTheme.helpText)
|
||||
|
||||
self.optSideBar.addLabel(self.tr("Options"))
|
||||
self.optSideBar.addButton(self.tr("Filters"), self.OPT_FILTERS)
|
||||
self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS)
|
||||
self.optSideBar.addButton(self.tr("Headings"), self.OPT_HEADINGS)
|
||||
self.optSideBar.addButton(self.tr("Content"), self.OPT_CONTENT)
|
||||
self.optSideBar.addButton(self.tr("Format"), self.OPT_FORMAT)
|
||||
@@ -169,10 +169,11 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def __del__(self): # pragma: no cover
|
||||
def __del__(self) -> None: # pragma: no cover
|
||||
logger.debug("Delete: GuiBuildSettings")
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the child widgets."""
|
||||
self.editBuildName.setText(self._build.name)
|
||||
self.optTabSelect.loadContent()
|
||||
@@ -182,12 +183,21 @@ class GuiBuildSettings(QDialog):
|
||||
self.optTabOutput.loadContent()
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def buildID(self) -> str:
|
||||
"""The build ID of the build of the dialog."""
|
||||
return self._build.buildID
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _stackPageSelected(self, pageId: int):
|
||||
def _stackPageSelected(self, pageId: int) -> None:
|
||||
"""Process a user request to switch page."""
|
||||
if pageId == self.OPT_FILTERS:
|
||||
self.toolStack.setCurrentWidget(self.optTabSelect)
|
||||
@@ -202,7 +212,7 @@ class GuiBuildSettings(QDialog):
|
||||
return
|
||||
|
||||
@pyqtSlot("QAbstractButton*")
|
||||
def _dialogButtonClicked(self, button: QAbstractButton):
|
||||
def _dialogButtonClicked(self, button: QAbstractButton) -> None:
|
||||
"""Handle button clicks from the dialog button box."""
|
||||
role = self.dlgButtons.buttonRole(button)
|
||||
if role == QDialogButtonBox.ApplyRole:
|
||||
@@ -218,7 +228,7 @@ class GuiBuildSettings(QDialog):
|
||||
# Events
|
||||
##
|
||||
|
||||
def closeEvent(self, event: QEvent):
|
||||
def closeEvent(self, event: QEvent) -> None:
|
||||
"""Capture the user closing the window so we can save
|
||||
settings.
|
||||
"""
|
||||
@@ -233,7 +243,7 @@ class GuiBuildSettings(QDialog):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _askToSaveBuild(self):
|
||||
def _askToSaveBuild(self) -> None:
|
||||
"""Check if there are unsaved changes, and if there are, ask if
|
||||
it's ok to reject them.
|
||||
"""
|
||||
@@ -247,7 +257,7 @@ class GuiBuildSettings(QDialog):
|
||||
self._build.resetChangedState()
|
||||
return
|
||||
|
||||
def _saveSettings(self):
|
||||
def _saveSettings(self) -> None:
|
||||
"""Save the various user settings."""
|
||||
logger.debug("Saving GuiBuildSettings settings")
|
||||
|
||||
@@ -265,7 +275,7 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def _emitBuildData(self):
|
||||
def _emitBuildData(self) -> None:
|
||||
"""Assemble the build data and emit the signal."""
|
||||
self._build.setName(self.editBuildName.text())
|
||||
self.optTabHeadings.saveContent()
|
||||
@@ -294,23 +304,26 @@ class _FilterTab(QWidget):
|
||||
F_INCLUDED = 2
|
||||
F_EXCLUDED = 3
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
self.mainTheme = buildMain.mainGui.mainTheme
|
||||
self.theProject = buildMain.mainGui.theProject
|
||||
|
||||
self._treeMap = {}
|
||||
self._treeMap: dict[str, QTreeWidgetItem] = {}
|
||||
self._build = build
|
||||
|
||||
self._statusFlags = {
|
||||
self.F_NONE: ("", QIcon()),
|
||||
self.F_FILTERED: (self.tr("Filtered"), self.mainTheme.getIcon("build_filtered")),
|
||||
self.F_INCLUDED: (self.tr("Included"), self.mainTheme.getIcon("build_included")),
|
||||
self.F_EXCLUDED: (self.tr("Excluded"), self.mainTheme.getIcon("build_excluded")),
|
||||
self._statusFlags: dict[int, QIcon] = {
|
||||
self.F_NONE: QIcon(),
|
||||
self.F_FILTERED: self.mainTheme.getIcon("build_filtered"),
|
||||
self.F_INCLUDED: self.mainTheme.getIcon("build_included"),
|
||||
self.F_EXCLUDED: self.mainTheme.getIcon("build_excluded"),
|
||||
}
|
||||
|
||||
self._trIncluded = self.tr("Included in manuscript")
|
||||
self._trExcluded = self.tr("Excluded from manuscript")
|
||||
|
||||
# Project Tree
|
||||
# ============
|
||||
|
||||
@@ -341,27 +354,28 @@ class _FilterTab(QWidget):
|
||||
# Filters
|
||||
# =======
|
||||
|
||||
self.filteredButton = QToolButton(self)
|
||||
self.filteredButton.setToolTip(self._statusFlags[self.F_FILTERED][0])
|
||||
self.filteredButton.setIcon(self._statusFlags[self.F_FILTERED][1])
|
||||
self.filteredButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED))
|
||||
|
||||
self.includedButton = QToolButton(self)
|
||||
self.includedButton.setToolTip(self._statusFlags[self.F_INCLUDED][0])
|
||||
self.includedButton.setIcon(self._statusFlags[self.F_INCLUDED][1])
|
||||
self.includedButton.setToolTip(self.tr("Always included"))
|
||||
self.includedButton.setIcon(self._statusFlags[self.F_INCLUDED])
|
||||
self.includedButton.clicked.connect(lambda: self._setSelectedMode(self.F_INCLUDED))
|
||||
|
||||
self.excludedButton = QToolButton(self)
|
||||
self.excludedButton.setToolTip(self._statusFlags[self.F_EXCLUDED][0])
|
||||
self.excludedButton.setIcon(self._statusFlags[self.F_EXCLUDED][1])
|
||||
self.excludedButton.setToolTip(self.tr("Always excluded"))
|
||||
self.excludedButton.setIcon(self._statusFlags[self.F_EXCLUDED])
|
||||
self.excludedButton.clicked.connect(lambda: self._setSelectedMode(self.F_EXCLUDED))
|
||||
|
||||
self.resetButton = QToolButton(self)
|
||||
self.resetButton.setToolTip(self.tr("Reset to default"))
|
||||
self.resetButton.setIcon(self.mainTheme.getIcon("revert"))
|
||||
self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED))
|
||||
|
||||
self.modeBox = QHBoxLayout()
|
||||
self.modeBox.addWidget(QLabel(self.tr("Mark selection as")))
|
||||
self.modeBox.addStretch(1)
|
||||
self.modeBox.addWidget(self.filteredButton)
|
||||
self.modeBox.addWidget(self.includedButton)
|
||||
self.modeBox.addWidget(self.excludedButton)
|
||||
self.modeBox.addWidget(self.resetButton)
|
||||
self.modeBox.setSpacing(CONFIG.pxInt(4))
|
||||
|
||||
# Filer Options
|
||||
self.filterOpt = NSwitchBox(self, iPx)
|
||||
@@ -401,7 +415,7 @@ class _FilterTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
self._populateTree()
|
||||
self._populateFilters()
|
||||
@@ -418,7 +432,7 @@ class _FilterTab(QWidget):
|
||||
##
|
||||
|
||||
@pyqtSlot(str, bool)
|
||||
def _applyFilterSwitch(self, key: str, state: bool):
|
||||
def _applyFilterSwitch(self, key: str, state: bool) -> None:
|
||||
"""Apply filter switch and update the settings."""
|
||||
if key.startswith("doc:"):
|
||||
self._build.setValue(key[4:], state)
|
||||
@@ -432,7 +446,7 @@ class _FilterTab(QWidget):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _populateTree(self):
|
||||
def _populateTree(self) -> None:
|
||||
"""Build the tree of project items."""
|
||||
logger.debug("Building project tree")
|
||||
self._treeMap = {}
|
||||
@@ -486,7 +500,7 @@ class _FilterTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def _populateFilters(self):
|
||||
def _populateFilters(self) -> None:
|
||||
"""Populate the filter options switches."""
|
||||
self.filterOpt.clear()
|
||||
self.filterOpt.addLabel(self._build.getLabel("filter"))
|
||||
@@ -512,7 +526,7 @@ class _FilterTab(QWidget):
|
||||
self.filterOpt.addSeparator()
|
||||
|
||||
# Root Classes
|
||||
self.filterOpt.addLabel(self.tr("Root Folders"))
|
||||
self.filterOpt.addLabel(self.tr("Select Root Folders"))
|
||||
for tHandle, nwItem in self.theProject.tree.iterRoots(None):
|
||||
if not nwItem.isInactiveClass():
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
@@ -525,9 +539,13 @@ class _FilterTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def _setSelectedMode(self, mode: int):
|
||||
def _setSelectedMode(self, mode: int) -> None:
|
||||
"""Set the mode for the selected items."""
|
||||
for item in self.optTree.selectedItems():
|
||||
items = self.optTree.selectedItems()
|
||||
if len(items) == 1 and isinstance(items[0], QTreeWidgetItem):
|
||||
items = self._scanChildren(items[0], [])
|
||||
|
||||
for item in items:
|
||||
if isinstance(item, QTreeWidgetItem):
|
||||
tHandle = item.data(self.C_DATA, self.D_HANDLE)
|
||||
isFile = item.data(self.C_DATA, self.D_FILE)
|
||||
@@ -543,21 +561,34 @@ class _FilterTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def _setTreeItemMode(self):
|
||||
def _setTreeItemMode(self) -> None:
|
||||
"""Update the filtered mode icon on all items."""
|
||||
filtered = self._build.buildItemFilter(self.theProject)
|
||||
for tHandle, item in self._treeMap.items():
|
||||
allow, mode = filtered.get(tHandle, (False, FilterMode.UNKNOWN))
|
||||
if mode == FilterMode.INCLUDED:
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_INCLUDED][1])
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_INCLUDED])
|
||||
item.setToolTip(self.C_STATUS, self._trIncluded)
|
||||
elif mode == FilterMode.EXCLUDED:
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_EXCLUDED][1])
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_EXCLUDED])
|
||||
item.setToolTip(self.C_STATUS, self._trExcluded)
|
||||
elif mode == FilterMode.FILTERED and allow:
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_FILTERED][1])
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_FILTERED])
|
||||
item.setToolTip(self.C_STATUS, self._trIncluded)
|
||||
else:
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_NONE][1])
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_NONE])
|
||||
return
|
||||
|
||||
def _scanChildren(self, item: QTreeWidgetItem | None, items: list) -> list[QTreeWidgetItem]:
|
||||
"""This is a recursive function returning all items in a tree
|
||||
starting at a given QTreeWidgetItem.
|
||||
"""
|
||||
if isinstance(item, QTreeWidgetItem):
|
||||
items.append(item)
|
||||
for i in range(item.childCount()):
|
||||
self._scanChildren(item.child(i), items)
|
||||
return items
|
||||
|
||||
# END Class _FilterTab
|
||||
|
||||
|
||||
@@ -569,7 +600,7 @@ class _HeadingsTab(QWidget):
|
||||
EDIT_SCENE = 4
|
||||
EDIT_SECTION = 5
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
@@ -747,7 +778,7 @@ class _HeadingsTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
self.fmtTitle.setText(self._build.getStr("headings.fmtTitle"))
|
||||
self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
|
||||
@@ -758,7 +789,7 @@ class _HeadingsTab(QWidget):
|
||||
self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
def saveContent(self) -> None:
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("headings.hideScene", self.swtScene.isChecked())
|
||||
self._build.setValue("headings.hideSection", self.swtSection.isChecked())
|
||||
@@ -768,7 +799,7 @@ class _HeadingsTab(QWidget):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _insertIntoForm(self, text: str):
|
||||
def _insertIntoForm(self, text: str) -> None:
|
||||
"""Insert formatting text from the dropdown menu."""
|
||||
if self._editing > 0:
|
||||
cursor = self.editTextBox.textCursor()
|
||||
@@ -776,7 +807,7 @@ class _HeadingsTab(QWidget):
|
||||
self.editTextBox.setFocus()
|
||||
return
|
||||
|
||||
def _editHeading(self, heading: int):
|
||||
def _editHeading(self, heading: int) -> None:
|
||||
"""Populate the form with a specific heading format."""
|
||||
self._editing = heading
|
||||
self.editTextBox.setEnabled(True)
|
||||
@@ -801,7 +832,7 @@ class _HeadingsTab(QWidget):
|
||||
text = ""
|
||||
label = self.tr("None")
|
||||
|
||||
self.editTextBox.setPlainText(text.replace("//", "\n"))
|
||||
self.editTextBox.setPlainText(text.replace(nwHeadFmt.BR, "\n"))
|
||||
self.lblEditForm.setText(self.tr("Editing: {0}").format(label))
|
||||
|
||||
return
|
||||
@@ -810,10 +841,10 @@ class _HeadingsTab(QWidget):
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
def _saveFormat(self):
|
||||
def _saveFormat(self) -> None:
|
||||
"""Save the format from the edit text box."""
|
||||
heading = self._editing
|
||||
text = self.editTextBox.toPlainText().strip().replace("\n", "//")
|
||||
text = self.editTextBox.toPlainText().strip().replace("\n", nwHeadFmt.BR)
|
||||
if heading == self.EDIT_TITLE:
|
||||
self.fmtTitle.setText(text)
|
||||
self._build.setValue("headings.fmtTitle", text)
|
||||
@@ -842,7 +873,7 @@ class _HeadingsTab(QWidget):
|
||||
|
||||
class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def __init__(self, document: QTextDocument, mainTheme: GuiTheme):
|
||||
def __init__(self, document: QTextDocument, mainTheme: GuiTheme) -> None:
|
||||
super().__init__(document)
|
||||
self._fmtSymbol = QTextCharFormat()
|
||||
self._fmtSymbol.setForeground(QColor(*mainTheme.colHead))
|
||||
@@ -850,7 +881,7 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
|
||||
self._fmtFormat.setForeground(QColor(*mainTheme.colEmph))
|
||||
return
|
||||
|
||||
def highlightBlock(self, text: str):
|
||||
def highlightBlock(self, text: str) -> None:
|
||||
"""Add syntax highlighting to the text block."""
|
||||
for heading in nwHeadFmt.ALL:
|
||||
pos = text.find(heading)
|
||||
@@ -868,7 +899,7 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
|
||||
|
||||
class _ContentTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
@@ -917,7 +948,7 @@ class _ContentTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
|
||||
self.incComments.setChecked(self._build.getBool("text.includeComments"))
|
||||
@@ -926,7 +957,7 @@ class _ContentTab(QWidget):
|
||||
self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
def saveContent(self) -> None:
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
|
||||
self._build.setValue("text.includeComments", self.incComments.isChecked())
|
||||
@@ -940,7 +971,7 @@ class _ContentTab(QWidget):
|
||||
|
||||
class _FormatTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.buildMain = buildMain
|
||||
@@ -1033,10 +1064,12 @@ class _FormatTab(QWidget):
|
||||
self.pageWidth = QDoubleSpinBox(self)
|
||||
self.pageWidth.setFixedWidth(dbW)
|
||||
self.pageWidth.setMaximum(500.0)
|
||||
self.pageWidth.valueChanged.connect(self._pageSizeValueChanged)
|
||||
|
||||
self.pageHeight = QDoubleSpinBox(self)
|
||||
self.pageHeight.setFixedWidth(dbW)
|
||||
self.pageHeight.setMaximum(500.0)
|
||||
self.pageHeight.valueChanged.connect(self._pageSizeValueChanged)
|
||||
|
||||
self.topMargin = QDoubleSpinBox(self)
|
||||
self.topMargin.setFixedWidth(dbW)
|
||||
@@ -1085,7 +1118,7 @@ class _FormatTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
langIdx = self.buildLang.findData(self._build.getStr("format.buildLang"))
|
||||
if langIdx != -1:
|
||||
@@ -1128,7 +1161,7 @@ class _FormatTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
def saveContent(self) -> None:
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("format.buildLang", str(self.buildLang.currentData()))
|
||||
self._build.setValue("format.textFont", self.textFont.text())
|
||||
@@ -1154,7 +1187,7 @@ class _FormatTab(QWidget):
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectFont(self):
|
||||
def _selectFont(self) -> None:
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
currFont = QFont()
|
||||
currFont.setFamily(self.textFont.text())
|
||||
@@ -1166,7 +1199,7 @@ class _FormatTab(QWidget):
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _changeUnit(self, index: int):
|
||||
def _changeUnit(self, index: int) -> None:
|
||||
"""The current unit change, so recalculate sizes."""
|
||||
newUnit = self.pageUnit.itemData(index)
|
||||
newScale = nwLabels.UNIT_SCALE.get(newUnit, 1.0)
|
||||
@@ -1185,15 +1218,19 @@ class _FormatTab(QWidget):
|
||||
pMax = 500.0 if isMM else 50.0
|
||||
mMax = 150.0 if isMM else 15.0
|
||||
|
||||
self.pageWidth.blockSignals(True)
|
||||
self.pageWidth.setDecimals(nDec)
|
||||
self.pageWidth.setSingleStep(nStep)
|
||||
self.pageWidth.setMaximum(pMax)
|
||||
self.pageWidth.setValue(pageWidth)
|
||||
self.pageWidth.blockSignals(False)
|
||||
|
||||
self.pageHeight.blockSignals(True)
|
||||
self.pageHeight.setDecimals(nDec)
|
||||
self.pageHeight.setSingleStep(nStep)
|
||||
self.pageHeight.setMaximum(pMax)
|
||||
self.pageHeight.setValue(pageHeight)
|
||||
self.pageHeight.blockSignals(False)
|
||||
|
||||
self.topMargin.setDecimals(nDec)
|
||||
self.topMargin.setSingleStep(nStep)
|
||||
@@ -1216,22 +1253,31 @@ class _FormatTab(QWidget):
|
||||
self.rightMargin.setValue(rightMargin)
|
||||
|
||||
self._unitScale = newScale
|
||||
self._changePageSize(self.pageSize.currentIndex())
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _changePageSize(self, index: int):
|
||||
def _changePageSize(self, index: int) -> None:
|
||||
"""The page size has changed."""
|
||||
self.pageWidth.setEnabled(True)
|
||||
self.pageHeight.setEnabled(True)
|
||||
|
||||
w, h = nwLabels.PAPER_SIZE[self.pageSize.itemData(index)] if index >= 0 else (-1.0, -1.0)
|
||||
if w > 0.0 and h > 0.0:
|
||||
self.pageWidth.setEnabled(False)
|
||||
self.pageHeight.setEnabled(False)
|
||||
self.pageWidth.blockSignals(True)
|
||||
self.pageWidth.setValue(w/self._unitScale)
|
||||
self.pageWidth.blockSignals(False)
|
||||
self.pageHeight.blockSignals(True)
|
||||
self.pageHeight.setValue(h/self._unitScale)
|
||||
self.pageHeight.blockSignals(False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _pageSizeValueChanged(self):
|
||||
"""The user has changed the page size spin boxes, so we flip
|
||||
the page size box to Custom.
|
||||
"""
|
||||
index = self.pageSize.findData("Custom")
|
||||
if index >= 0:
|
||||
self.pageSize.setCurrentIndex(index)
|
||||
return
|
||||
|
||||
# END Class _FormatTab
|
||||
@@ -1239,7 +1285,7 @@ class _FormatTab(QWidget):
|
||||
|
||||
class _OutputTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
|
||||
super().__init__(parent=buildMain)
|
||||
|
||||
self.mainGui = buildMain.mainGui
|
||||
@@ -1282,13 +1328,13 @@ class _OutputTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
def loadContent(self) -> None:
|
||||
"""Populate the widgets."""
|
||||
self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
|
||||
self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
def saveContent(self) -> None:
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
|
||||
self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
|
||||
|
||||
@@ -168,11 +168,12 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath:
|
||||
# ========
|
||||
|
||||
# No build selected
|
||||
manus.buildList.clearSelection()
|
||||
manus.buildList.clear()
|
||||
manus.btnPreview.click()
|
||||
qtbot.wait(200) # Should be enough to run the build
|
||||
assert manus.docPreview.toPlainText().strip() == ""
|
||||
assert cacheFile.exists() is False
|
||||
manus._updateBuildsList()
|
||||
|
||||
# Preview the first, but fail to save cache
|
||||
manus.buildList.setCurrentRow(0)
|
||||
@@ -207,12 +208,6 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath:
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("novelwriter.tools.manusbuild.GuiManuscriptBuild.exec_", lambda *a: None)
|
||||
|
||||
# With no selection, no dialog should be created
|
||||
manus.btnBuild.click()
|
||||
for obj in manus.children():
|
||||
assert not isinstance(obj, GuiManuscriptBuild)
|
||||
|
||||
# With a selection, there should be one
|
||||
manus.buildList.setCurrentRow(0)
|
||||
manus.btnBuild.click()
|
||||
for obj in manus.children():
|
||||
|
||||
@@ -47,7 +47,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd
|
||||
build = BuildSettings()
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
@@ -132,10 +132,10 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
hCharDoc = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(hPlotDoc)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(hCharDoc)
|
||||
nwGUI.theProject.tree[hPlotDoc].setActive(False)
|
||||
nwGUI.theProject.tree[hPlotDoc].setActive(False) # type: ignore
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
@@ -147,7 +147,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
assert filterTab.optTree.topLevelItemCount() == 4 # The 4 root folders
|
||||
assert filterTab.filterOpt._index == 10 # 2 headers, 1 sep, 3 opt and 4 roots
|
||||
|
||||
# Untoggle note folders
|
||||
# Un-toggle note folders
|
||||
filterTab.filterOpt._widgets[switchMap["worldRoot"]].setChecked(False) # World Root
|
||||
assert filterTab.optTree.topLevelItemCount() == 3
|
||||
assert C.hWorldRoot in build._skipRoot
|
||||
@@ -229,8 +229,8 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
|
||||
# Set char and plot docs to excluded
|
||||
filterTab.optTree.clearSelection()
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True)
|
||||
filterTab._treeMap[hCharDoc].setSelected(True)
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||||
filterTab.excludedButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
@@ -260,13 +260,30 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||||
}
|
||||
|
||||
# Selecting only novel root should iterate through all children
|
||||
filterTab.optTree.clearSelection()
|
||||
filterTab._treeMap[C.hNovelRoot].setSelected(True)
|
||||
filterTab.resetButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (True, FilterMode.FILTERED),
|
||||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||||
C.hChapterDoc: (True, FilterMode.FILTERED),
|
||||
C.hSceneDoc: (True, FilterMode.FILTERED),
|
||||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||||
hPlotDoc: (False, FilterMode.EXCLUDED),
|
||||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||||
hCharDoc: (False, FilterMode.EXCLUDED),
|
||||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||||
}
|
||||
|
||||
# Set everything back to filtered
|
||||
filterTab.optTree.clearSelection()
|
||||
filterTab._treeMap[C.hChapterDoc].setSelected(True)
|
||||
filterTab._treeMap[C.hNovelRoot].setSelected(True)
|
||||
filterTab._treeMap[C.hSceneDoc].setSelected(True)
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True)
|
||||
filterTab._treeMap[hCharDoc].setSelected(True)
|
||||
filterTab.filteredButton.click()
|
||||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||||
filterTab.resetButton.click()
|
||||
assert build.buildItemFilter(nwGUI.theProject) == {
|
||||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||||
C.hTitlePage: (True, FilterMode.FILTERED),
|
||||
@@ -285,8 +302,8 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
|
||||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
C.hPlotRoot, hPlotDoc, C.hCharRoot, hCharDoc,
|
||||
]
|
||||
nwGUI.theProject.tree[hCharDoc].setRoot(None) # Char doc has no root handle
|
||||
nwGUI.theProject.tree[hPlotDoc].setParent(None) # Plot doc has no parent handle
|
||||
nwGUI.theProject.tree[hCharDoc].setRoot(None) # type: ignore
|
||||
nwGUI.theProject.tree[hPlotDoc].setParent(None) # type: ignore
|
||||
filterTab._populateTree()
|
||||
assert list(filterTab._treeMap.keys()) == [
|
||||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||
@@ -320,7 +337,7 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain):
|
||||
build.setValue("headings.hideSection", False)
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
@@ -412,7 +429,9 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain):
|
||||
headTab.btnChapter.click()
|
||||
headTab.editTextBox.setPlainText(f"Chapter {nwHeadFmt.CH_NUM}\n{nwHeadFmt.TITLE}\n")
|
||||
headTab.btnApply.click()
|
||||
assert build.getStr("headings.fmtChapter") == f"Chapter {nwHeadFmt.CH_NUM}//{nwHeadFmt.TITLE}"
|
||||
assert build.getStr("headings.fmtChapter") == (
|
||||
f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}"
|
||||
)
|
||||
|
||||
# Set all to plain title
|
||||
headTab.btnTitle.click()
|
||||
@@ -467,7 +486,7 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain):
|
||||
build.setValue("text.addNoteHeadings", False)
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
@@ -534,7 +553,7 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain):
|
||||
build.setValue("format.rightMargin", 15.0)
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
@@ -622,7 +641,7 @@ def testBuildSettings_Output(qtbot: QtBot, nwGUI: GuiMain):
|
||||
build.setValue("html.addStyles", False)
|
||||
|
||||
# Create the dialog and populate it
|
||||
bSettings = GuiBuildSettings(nwGUI, nwGUI, build)
|
||||
bSettings = GuiBuildSettings(nwGUI, build)
|
||||
bSettings.show()
|
||||
bSettings.loadContent()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user