Fix various issues on the Welcome dialog (#1707)
This commit is contained in:
@@ -60,11 +60,13 @@ fmt_superscript = nw_tb-superscript.svg
|
|||||||
fmt_underline = nw_tb-underline.svg
|
fmt_underline = nw_tb-underline.svg
|
||||||
forward = typ_chevron-right.svg
|
forward = typ_chevron-right.svg
|
||||||
import = mixed_import.svg
|
import = mixed_import.svg
|
||||||
|
list = typ_th-list.svg
|
||||||
maximise = typ_arrow-maximise.svg
|
maximise = typ_arrow-maximise.svg
|
||||||
menu = typ_th-dot-menu.svg
|
menu = typ_th-dot-menu.svg
|
||||||
minimise = typ_arrow-minimise.svg
|
minimise = typ_arrow-minimise.svg
|
||||||
more = typ_th-dot-more.svg
|
more = typ_th-dot-more.svg
|
||||||
noncheckable = mixed_input-none.svg
|
noncheckable = mixed_input-none.svg
|
||||||
|
open = typ_folder.svg
|
||||||
panel = nw_panel.svg
|
panel = nw_panel.svg
|
||||||
proj_chapter = mixed_document-chapter.svg
|
proj_chapter = mixed_document-chapter.svg
|
||||||
proj_details = typ_th-list-grey.svg
|
proj_details = typ_th-list-grey.svg
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?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">
|
||||||
|
<g fill="#69c" stroke-width="1.0526">
|
||||||
|
<path d="m19.632 17.263h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053s0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053s-0.94421-2.1053-2.1053-2.1053zm0-7.3684h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053s0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053s-0.94421-2.1053-2.1053-2.1053zm0-7.3684h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053 0 1.1611 0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053 0-1.1611-0.94421-2.1053-2.1053-2.1053z"/>
|
||||||
|
<circle cx="4.8947" cy="19.368" r="2.6316"/>
|
||||||
|
<circle cx="4.8947" cy="12" r="2.6316"/>
|
||||||
|
<circle cx="4.8947" cy="4.6316" r="2.6316"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 846 B |
@@ -60,11 +60,13 @@ fmt_superscript = nw_tb-superscript.svg
|
|||||||
fmt_underline = nw_tb-underline.svg
|
fmt_underline = nw_tb-underline.svg
|
||||||
forward = typ_chevron-right.svg
|
forward = typ_chevron-right.svg
|
||||||
import = mixed_import.svg
|
import = mixed_import.svg
|
||||||
|
list = typ_th-list.svg
|
||||||
maximise = typ_arrow-maximise.svg
|
maximise = typ_arrow-maximise.svg
|
||||||
menu = typ_th-dot-menu.svg
|
menu = typ_th-dot-menu.svg
|
||||||
minimise = typ_arrow-minimise.svg
|
minimise = typ_arrow-minimise.svg
|
||||||
more = typ_th-dot-more.svg
|
more = typ_th-dot-more.svg
|
||||||
noncheckable = mixed_input-none.svg
|
noncheckable = mixed_input-none.svg
|
||||||
|
open = typ_folder.svg
|
||||||
panel = nw_panel.svg
|
panel = nw_panel.svg
|
||||||
proj_chapter = mixed_document-chapter.svg
|
proj_chapter = mixed_document-chapter.svg
|
||||||
proj_details = typ_th-list-grey.svg
|
proj_details = typ_th-list-grey.svg
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?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">
|
||||||
|
<g fill="#4271ae" stroke-width="1.0526">
|
||||||
|
<path d="m19.632 17.263h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053s0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053s-0.94421-2.1053-2.1053-2.1053zm0-7.3684h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053s0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053s-0.94421-2.1053-2.1053-2.1053zm0-7.3684h-7.3684c-1.1611 0-2.1053 0.94421-2.1053 2.1053 0 1.1611 0.94421 2.1053 2.1053 2.1053h7.3684c1.1611 0 2.1053-0.94421 2.1053-2.1053 0-1.1611-0.94421-2.1053-2.1053-2.1053z"/>
|
||||||
|
<circle cx="4.8947" cy="19.368" r="2.6316"/>
|
||||||
|
<circle cx="4.8947" cy="12" r="2.6316"/>
|
||||||
|
<circle cx="4.8947" cy="4.6316" r="2.6316"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 849 B |
@@ -365,14 +365,10 @@ class ProjectBuilder:
|
|||||||
lblByAuthors = self.tr("By")
|
lblByAuthors = self.tr("By")
|
||||||
|
|
||||||
# Settings
|
# Settings
|
||||||
projName = data.get("name", lblNewProject)
|
|
||||||
projAuthor = data.get("author", "")
|
|
||||||
projLang = data.get("language", "en_GB")
|
|
||||||
|
|
||||||
project.data.setUuid(None)
|
project.data.setUuid(None)
|
||||||
project.data.setName(projName)
|
project.data.setName(data.get("name", lblNewProject))
|
||||||
project.data.setAuthor(projAuthor)
|
project.data.setAuthor(data.get("author", ""))
|
||||||
project.data.setLanguage(projLang)
|
project.data.setLanguage(CONFIG.guiLocale)
|
||||||
project.setDefaultStatusImport()
|
project.setDefaultStatusImport()
|
||||||
project.session.startSession()
|
project.session.startSession()
|
||||||
|
|
||||||
@@ -502,7 +498,6 @@ class ProjectBuilder:
|
|||||||
project.data.setUuid("") # Creates a fresh uuid
|
project.data.setUuid("") # Creates a fresh uuid
|
||||||
project.data.setName(data.get("name", "None"))
|
project.data.setName(data.get("name", "None"))
|
||||||
project.data.setAuthor(data.get("author", ""))
|
project.data.setAuthor(data.get("author", ""))
|
||||||
project.data.setLanguage(data.get("language", "en_GB"))
|
|
||||||
project.data.setSpellCheck(True)
|
project.data.setSpellCheck(True)
|
||||||
project.data.setSpellLang(None)
|
project.data.setSpellLang(None)
|
||||||
project.data.setDoBackup(True)
|
project.data.setDoBackup(True)
|
||||||
@@ -518,6 +513,13 @@ class ProjectBuilder:
|
|||||||
"""Make a copy of the sample project by extracting the
|
"""Make a copy of the sample project by extracting the
|
||||||
sample.zip file to the new path.
|
sample.zip file to the new path.
|
||||||
"""
|
"""
|
||||||
|
if path.exists():
|
||||||
|
SHARED.error(self.tr(
|
||||||
|
"The target folder already exists. "
|
||||||
|
"Please choose another folder."
|
||||||
|
))
|
||||||
|
return False
|
||||||
|
|
||||||
if (sample := CONFIG.assetPath("sample.zip")).is_file():
|
if (sample := CONFIG.assetPath("sample.zip")).is_file():
|
||||||
try:
|
try:
|
||||||
shutil.unpack_archive(sample, path)
|
shutil.unpack_archive(sample, path)
|
||||||
|
|||||||
@@ -453,9 +453,9 @@ class GuiIcons:
|
|||||||
|
|
||||||
# General Button Icons
|
# General Button Icons
|
||||||
"add", "add_document", "backward", "bookmark", "browse", "checked", "close", "cross",
|
"add", "add_document", "backward", "bookmark", "browse", "checked", "close", "cross",
|
||||||
"document", "down", "edit", "export", "forward", "import", "maximise", "menu", "minimise",
|
"document", "down", "edit", "export", "forward", "import", "list", "maximise", "menu",
|
||||||
"more", "noncheckable", "panel", "refresh", "remove", "revert", "search_replace", "search",
|
"minimise", "more", "noncheckable", "open", "panel", "refresh", "remove", "revert",
|
||||||
"settings", "star", "unchecked", "up", "view",
|
"search_replace", "search", "settings", "star", "unchecked", "up", "view",
|
||||||
|
|
||||||
# Switches
|
# Switches
|
||||||
"sticky-on", "sticky-off",
|
"sticky-on", "sticky-off",
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ from PyQt5.QtCore import (
|
|||||||
pyqtSignal, pyqtSlot
|
pyqtSignal, pyqtSlot
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAction, QDialog, QDialogButtonBox, QFileDialog, QFormLayout, QHBoxLayout,
|
QAction, QDialog, QFileDialog, QFormLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||||
QLabel, QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut,
|
QListView, QMenu, QPushButton, QScrollArea, QShortcut, QStackedWidget,
|
||||||
QStackedWidget, QStyle, QStyleOptionViewItem, QStyledItemDelegate,
|
QStyle, QStyleOptionViewItem, QStyledItemDelegate, QToolButton,
|
||||||
QToolButton, QVBoxLayout, QWidget, qApp
|
QVBoxLayout, QWidget, qApp
|
||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
@@ -46,8 +46,9 @@ from novelwriter.common import formatInt, makeFileNameSafe
|
|||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.core.coretools import ProjectBuilder
|
from novelwriter.core.coretools import ProjectBuilder
|
||||||
from novelwriter.extensions.switch import NSwitch
|
from novelwriter.extensions.switch import NSwitch
|
||||||
from novelwriter.extensions.modified import NComboBox, NSpinBox
|
from novelwriter.extensions.modified import NSpinBox
|
||||||
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
||||||
|
from novelwriter.extensions.configlayout import NColourLabel
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -97,7 +98,6 @@ class GuiWelcome(QDialog):
|
|||||||
self.tabOpen.openProjectRequest.connect(self._openProjectPath)
|
self.tabOpen.openProjectRequest.connect(self._openProjectPath)
|
||||||
|
|
||||||
self.tabNew = _NewProjectPage(self)
|
self.tabNew = _NewProjectPage(self)
|
||||||
self.tabNew.cancelNewProject.connect(self._showOpenProjectPage)
|
|
||||||
self.tabNew.openProjectRequest.connect(self._openProjectPath)
|
self.tabNew.openProjectRequest.connect(self._openProjectPath)
|
||||||
|
|
||||||
self.mainStack = QStackedWidget(self)
|
self.mainStack = QStackedWidget(self)
|
||||||
@@ -107,17 +107,39 @@ class GuiWelcome(QDialog):
|
|||||||
# Buttons
|
# Buttons
|
||||||
# =======
|
# =======
|
||||||
|
|
||||||
self.btnBox = QDialogButtonBox(QDialogButtonBox.Open | QDialogButtonBox.Cancel, self)
|
self.btnList = QPushButton(self.tr("List Projects"), self)
|
||||||
self.btnBox.accepted.connect(self.tabOpen.openSelectedItem)
|
self.btnList.setIcon(SHARED.theme.getIcon("list"))
|
||||||
self.btnBox.rejected.connect(self.close)
|
self.btnList.clicked.connect(self._showOpenProjectPage)
|
||||||
|
|
||||||
self.newButton = self.btnBox.addButton(self.tr("New Project"), QDialogButtonBox.ActionRole)
|
self.btnNew = QPushButton(self.tr("New Project"), self)
|
||||||
self.newButton.setIcon(SHARED.theme.getIcon("add"))
|
self.btnNew.setIcon(SHARED.theme.getIcon("add"))
|
||||||
self.newButton.clicked.connect(self._showNewProjectPage)
|
self.btnNew.clicked.connect(self._showNewProjectPage)
|
||||||
|
|
||||||
self.browseButton = self.btnBox.addButton(self.tr("Browse"), QDialogButtonBox.ActionRole)
|
self.btnBrowse = QPushButton(self.tr("Browse"), self)
|
||||||
self.browseButton.setIcon(SHARED.theme.getIcon("browse"))
|
self.btnBrowse.setIcon(SHARED.theme.getIcon("browse"))
|
||||||
self.browseButton.clicked.connect(self._browseForProject)
|
self.btnBrowse.clicked.connect(self._browseForProject)
|
||||||
|
|
||||||
|
self.btnCancel = QPushButton(self.tr("Cancel"), self)
|
||||||
|
self.btnCancel.setIcon(SHARED.theme.getIcon("cross"))
|
||||||
|
self.btnCancel.clicked.connect(self.close)
|
||||||
|
|
||||||
|
self.btnCreate = QPushButton(self.tr("Create"), self)
|
||||||
|
self.btnCreate.setIcon(SHARED.theme.getIcon("star"))
|
||||||
|
self.btnCreate.clicked.connect(self.tabNew.createNewProject)
|
||||||
|
|
||||||
|
self.btnOpen = QPushButton(self.tr("Open"), self)
|
||||||
|
self.btnOpen.setIcon(SHARED.theme.getIcon("open"))
|
||||||
|
self.btnOpen.clicked.connect(self._openSelectedItem)
|
||||||
|
|
||||||
|
self.btnBox = QHBoxLayout()
|
||||||
|
self.btnBox.addStretch(1)
|
||||||
|
self.btnBox.addWidget(self.btnList)
|
||||||
|
self.btnBox.addWidget(self.btnNew)
|
||||||
|
self.btnBox.addWidget(self.btnBrowse)
|
||||||
|
self.btnBox.addWidget(self.btnCancel)
|
||||||
|
self.btnBox.addWidget(self.btnCreate)
|
||||||
|
self.btnBox.addWidget(self.btnOpen)
|
||||||
|
self._setButtonVisibility()
|
||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
# ========
|
# ========
|
||||||
@@ -129,7 +151,7 @@ class GuiWelcome(QDialog):
|
|||||||
self.innerBox.addSpacing(hA)
|
self.innerBox.addSpacing(hA)
|
||||||
self.innerBox.addWidget(self.mainStack)
|
self.innerBox.addWidget(self.mainStack)
|
||||||
self.innerBox.addSpacing(hB)
|
self.innerBox.addSpacing(hB)
|
||||||
self.innerBox.addWidget(self.btnBox)
|
self.innerBox.addLayout(self.btnBox)
|
||||||
|
|
||||||
topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
|
topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
|
||||||
|
|
||||||
@@ -179,12 +201,14 @@ class GuiWelcome(QDialog):
|
|||||||
def _showNewProjectPage(self) -> None:
|
def _showNewProjectPage(self) -> None:
|
||||||
"""Show the create new project page."""
|
"""Show the create new project page."""
|
||||||
self.mainStack.setCurrentWidget(self.tabNew)
|
self.mainStack.setCurrentWidget(self.tabNew)
|
||||||
|
self._setButtonVisibility()
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _showOpenProjectPage(self) -> None:
|
def _showOpenProjectPage(self) -> None:
|
||||||
"""Show the open exiting project page."""
|
"""Show the open exiting project page."""
|
||||||
self.mainStack.setCurrentWidget(self.tabOpen)
|
self.mainStack.setCurrentWidget(self.tabOpen)
|
||||||
|
self._setButtonVisibility()
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@@ -195,6 +219,13 @@ class GuiWelcome(QDialog):
|
|||||||
self._openProjectPath(path)
|
self._openProjectPath(path)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _openSelectedItem(self) -> None:
|
||||||
|
"""Open the currently selected project item."""
|
||||||
|
if self.mainStack.currentWidget() == self.tabOpen:
|
||||||
|
self.tabOpen.openSelectedItem()
|
||||||
|
return
|
||||||
|
|
||||||
@pyqtSlot(Path)
|
@pyqtSlot(Path)
|
||||||
def _openProjectPath(self, path: Path) -> None:
|
def _openProjectPath(self, path: Path) -> None:
|
||||||
"""Emit a project open signal."""
|
"""Emit a project open signal."""
|
||||||
@@ -216,6 +247,20 @@ class GuiWelcome(QDialog):
|
|||||||
CONFIG.setWelcomeWinSize(self.width(), self.height())
|
CONFIG.setWelcomeWinSize(self.width(), self.height())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _setButtonVisibility(self) -> None:
|
||||||
|
"""Change the visibility of the dialog buttons."""
|
||||||
|
listMode = self.mainStack.currentWidget() == self.tabOpen
|
||||||
|
self.btnList.setVisible(not listMode)
|
||||||
|
self.btnNew.setVisible(listMode)
|
||||||
|
self.btnBrowse.setVisible(listMode)
|
||||||
|
self.btnCreate.setVisible(not listMode)
|
||||||
|
self.btnOpen.setVisible(listMode)
|
||||||
|
if listMode:
|
||||||
|
self.btnOpen.setFocus()
|
||||||
|
else:
|
||||||
|
self.btnCreate.setFocus()
|
||||||
|
return
|
||||||
|
|
||||||
# END Class GuiWelcome
|
# END Class GuiWelcome
|
||||||
|
|
||||||
|
|
||||||
@@ -445,7 +490,6 @@ class _ProjectListModel(QAbstractListModel):
|
|||||||
|
|
||||||
class _NewProjectPage(QWidget):
|
class _NewProjectPage(QWidget):
|
||||||
|
|
||||||
cancelNewProject = pyqtSignal()
|
|
||||||
openProjectRequest = pyqtSignal(Path)
|
openProjectRequest = pyqtSignal(Path)
|
||||||
|
|
||||||
def __init__(self, parent: QWidget) -> None:
|
def __init__(self, parent: QWidget) -> None:
|
||||||
@@ -462,28 +506,11 @@ class _NewProjectPage(QWidget):
|
|||||||
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||||
|
|
||||||
# Controls
|
|
||||||
# ========
|
|
||||||
|
|
||||||
self.cancelButton = QPushButton(self.tr("Go Back"), self)
|
|
||||||
self.cancelButton.setIcon(SHARED.theme.getIcon("backward"))
|
|
||||||
self.cancelButton.clicked.connect(lambda: self.cancelNewProject.emit())
|
|
||||||
|
|
||||||
self.createButton = QPushButton(self.tr("Create Project"), self)
|
|
||||||
self.createButton.setIcon(SHARED.theme.getIcon("star"))
|
|
||||||
self.createButton.clicked.connect(self._createNewProject)
|
|
||||||
|
|
||||||
self.buttonBox = QHBoxLayout()
|
|
||||||
self.buttonBox.addStretch(1)
|
|
||||||
self.buttonBox.addWidget(self.cancelButton, 0)
|
|
||||||
self.buttonBox.addWidget(self.createButton, 0)
|
|
||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
# ========
|
# ========
|
||||||
|
|
||||||
self.outerBox = QVBoxLayout()
|
self.outerBox = QVBoxLayout()
|
||||||
self.outerBox.addWidget(self.scrollArea)
|
self.outerBox.addWidget(self.scrollArea)
|
||||||
self.outerBox.addLayout(self.buttonBox)
|
|
||||||
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
@@ -500,11 +527,11 @@ class _NewProjectPage(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Private Slots
|
# Public Slots
|
||||||
##
|
##
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _createNewProject(self) -> None:
|
def createNewProject(self) -> None:
|
||||||
"""Create a new project from the data in the form."""
|
"""Create a new project from the data in the form."""
|
||||||
data = self.projectForm.getProjectData()
|
data = self.projectForm.getProjectData()
|
||||||
if not data.get("name"):
|
if not data.get("name"):
|
||||||
@@ -532,10 +559,15 @@ class _NewProjectForm(QWidget):
|
|||||||
self._copyPath = None
|
self._copyPath = None
|
||||||
|
|
||||||
iPx = SHARED.theme.baseIconSize
|
iPx = SHARED.theme.baseIconSize
|
||||||
|
sPx = CONFIG.pxInt(16)
|
||||||
|
|
||||||
# Project Settings
|
# Project Settings
|
||||||
# ================
|
# ================
|
||||||
|
|
||||||
|
self.projHelp = NColourLabel(self.tr(
|
||||||
|
"These setting can be changed later from Project Settings."
|
||||||
|
), color=SHARED.theme.helpText, parent=self)
|
||||||
|
|
||||||
# Project Name
|
# Project Name
|
||||||
self.projName = QLineEdit(self)
|
self.projName = QLineEdit(self)
|
||||||
self.projName.setMaxLength(200)
|
self.projName.setMaxLength(200)
|
||||||
@@ -547,15 +579,6 @@ class _NewProjectForm(QWidget):
|
|||||||
self.projAuthor.setMaxLength(200)
|
self.projAuthor.setMaxLength(200)
|
||||||
self.projAuthor.setPlaceholderText(self.tr("Optional"))
|
self.projAuthor.setPlaceholderText(self.tr("Optional"))
|
||||||
|
|
||||||
# Project Language
|
|
||||||
self.projLang = NComboBox(self)
|
|
||||||
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
|
|
||||||
self.projLang.addItem(language, tag)
|
|
||||||
|
|
||||||
langIdx = self.projLang.findData(CONFIG.guiLocale)
|
|
||||||
if langIdx != -1:
|
|
||||||
self.projLang.setCurrentIndex(langIdx)
|
|
||||||
|
|
||||||
# Project Path
|
# Project Path
|
||||||
self.projPath = QLineEdit(self)
|
self.projPath = QLineEdit(self)
|
||||||
self.projPath.setReadOnly(True)
|
self.projPath.setReadOnly(True)
|
||||||
@@ -601,7 +624,6 @@ class _NewProjectForm(QWidget):
|
|||||||
self.projectForm.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
self.projectForm.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
self.projectForm.addRow(self.tr("Project Name"), self.projName)
|
self.projectForm.addRow(self.tr("Project Name"), self.projName)
|
||||||
self.projectForm.addRow(self.tr("Author"), self.projAuthor)
|
self.projectForm.addRow(self.tr("Author"), self.projAuthor)
|
||||||
self.projectForm.addRow(self.tr("Language"), self.projLang)
|
|
||||||
self.projectForm.addRow(self.tr("Project Path"), self.pathBox)
|
self.projectForm.addRow(self.tr("Project Path"), self.pathBox)
|
||||||
self.projectForm.addRow(self.tr("Prefill Project"), self.fillBox)
|
self.projectForm.addRow(self.tr("Prefill Project"), self.fillBox)
|
||||||
|
|
||||||
@@ -661,15 +683,24 @@ class _NewProjectForm(QWidget):
|
|||||||
# Assemble
|
# Assemble
|
||||||
# ========
|
# ========
|
||||||
|
|
||||||
|
self.extraBox = QVBoxLayout()
|
||||||
|
self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes"))))
|
||||||
|
self.extraBox.addLayout(self.novelForm)
|
||||||
|
self.extraBox.addSpacing(sPx)
|
||||||
|
self.extraBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes"))))
|
||||||
|
self.extraBox.addLayout(self.notesForm)
|
||||||
|
self.extraBox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
self.extraWidget = QWidget(self)
|
||||||
|
self.extraWidget.setLayout(self.extraBox)
|
||||||
|
self.extraWidget.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
self.formBox = QVBoxLayout()
|
self.formBox = QVBoxLayout()
|
||||||
self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project"))))
|
self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Create New Project"))))
|
||||||
|
self.formBox.addWidget(self.projHelp)
|
||||||
self.formBox.addLayout(self.projectForm)
|
self.formBox.addLayout(self.projectForm)
|
||||||
self.formBox.addSpacing(16)
|
self.formBox.addSpacing(sPx)
|
||||||
self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Chapters and Scenes"))))
|
self.formBox.addWidget(self.extraWidget)
|
||||||
self.formBox.addLayout(self.novelForm)
|
|
||||||
self.formBox.addSpacing(16)
|
|
||||||
self.formBox.addWidget(QLabel("<b>{0}</b>".format(self.tr("Project Notes"))))
|
|
||||||
self.formBox.addLayout(self.notesForm)
|
|
||||||
self.formBox.addStretch(1)
|
self.formBox.addStretch(1)
|
||||||
|
|
||||||
self.setLayout(self.formBox)
|
self.setLayout(self.formBox)
|
||||||
@@ -691,7 +722,6 @@ class _NewProjectForm(QWidget):
|
|||||||
return {
|
return {
|
||||||
"name": self.projName.text().strip(),
|
"name": self.projName.text().strip(),
|
||||||
"author": self.projAuthor.text().strip(),
|
"author": self.projAuthor.text().strip(),
|
||||||
"language": self.projLang.currentData(),
|
|
||||||
"path": self.projPath.text(),
|
"path": self.projPath.text(),
|
||||||
"blank": self._fillMode == self.FILL_BLANK,
|
"blank": self._fillMode == self.FILL_BLANK,
|
||||||
"sample": self._fillMode == self.FILL_SAMPLE,
|
"sample": self._fillMode == self.FILL_SAMPLE,
|
||||||
@@ -775,14 +805,7 @@ class _NewProjectForm(QWidget):
|
|||||||
self.projFill.setText(text)
|
self.projFill.setText(text)
|
||||||
self.projFill.setToolTip(text)
|
self.projFill.setToolTip(text)
|
||||||
self.projFill.setCursorPosition(0)
|
self.projFill.setCursorPosition(0)
|
||||||
|
self.extraWidget.setVisible(self._fillMode == self.FILL_BLANK)
|
||||||
isBlank = self._fillMode == self.FILL_BLANK
|
|
||||||
self.numChapters.setEnabled(isBlank)
|
|
||||||
self.numScenes.setEnabled(isBlank)
|
|
||||||
self.addPlot.setEnabled(isBlank)
|
|
||||||
self.addChar.setEnabled(isBlank)
|
|
||||||
self.addWorld.setEnabled(isBlank)
|
|
||||||
self.addNotes.setEnabled(isBlank)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
|
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-20 12:52:16">
|
||||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||||
<name>Test Project A</name>
|
<name>Test Project A</name>
|
||||||
<author>Jane Doe</author>
|
<author>Jane Doe</author>
|
||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
<doBackup>yes</doBackup>
|
<doBackup>yes</doBackup>
|
||||||
<language>None</language>
|
<language>en_GB</language>
|
||||||
<spellChecking auto="no">None</spellChecking>
|
<spellChecking auto="no">None</spellChecking>
|
||||||
<lastHandle>
|
<lastHandle>
|
||||||
<entry key="editor">None</entry>
|
<entry key="editor">None</entry>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
|
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-20 12:52:16">
|
||||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||||
<name>Test Project B</name>
|
<name>Test Project B</name>
|
||||||
<author>Jane Doe</author>
|
<author>Jane Doe</author>
|
||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
<doBackup>yes</doBackup>
|
<doBackup>yes</doBackup>
|
||||||
<language>None</language>
|
<language>en_GB</language>
|
||||||
<spellChecking auto="no">None</spellChecking>
|
<spellChecking auto="no">None</spellChecking>
|
||||||
<lastHandle>
|
<lastHandle>
|
||||||
<entry key="editor">None</entry>
|
<entry key="editor">None</entry>
|
||||||
|
|||||||
@@ -509,7 +509,6 @@ def testCoreTools_ProjectBuilderCopyPlain(monkeypatch, caplog, mockGUI, prjLipsu
|
|||||||
data = {
|
data = {
|
||||||
"name": "Test Project",
|
"name": "Test Project",
|
||||||
"author": "Jane Doe",
|
"author": "Jane Doe",
|
||||||
"language": "en_US",
|
|
||||||
"path": dstPath,
|
"path": dstPath,
|
||||||
"template": srcPath,
|
"template": srcPath,
|
||||||
}
|
}
|
||||||
@@ -556,9 +555,9 @@ def testCoreTools_ProjectBuilderCopyPlain(monkeypatch, caplog, mockGUI, prjLipsu
|
|||||||
assert srcProject.data.author == "lipsum.com"
|
assert srcProject.data.author == "lipsum.com"
|
||||||
assert dstProject.data.author == "Jane Doe"
|
assert dstProject.data.author == "Jane Doe"
|
||||||
|
|
||||||
# Language should be different
|
# Language should be the same
|
||||||
assert srcProject.data.language == "en_GB"
|
assert srcProject.data.language == "en_GB"
|
||||||
assert dstProject.data.language == "en_US"
|
assert dstProject.data.language == "en_GB"
|
||||||
|
|
||||||
# Counts should be more or less zeroed
|
# Counts should be more or less zeroed
|
||||||
assert dstProject.data.saveCount < 5
|
assert dstProject.data.saveCount < 5
|
||||||
@@ -634,9 +633,9 @@ def testCoreTools_ProjectBuilderCopyZipped(monkeypatch, caplog, mockGUI, fncPath
|
|||||||
assert srcProject.data.author == "Jane Doe"
|
assert srcProject.data.author == "Jane Doe"
|
||||||
assert dstProject.data.author == "Jane Doe"
|
assert dstProject.data.author == "Jane Doe"
|
||||||
|
|
||||||
# Language should be different
|
# Language should be the same
|
||||||
assert srcProject.data.language is None
|
assert srcProject.data.language is None
|
||||||
assert dstProject.data.language == "en_US"
|
assert dstProject.data.language is None
|
||||||
|
|
||||||
# Counts should be more or less zeroed
|
# Counts should be more or less zeroed
|
||||||
assert dstProject.data.saveCount < 5
|
assert dstProject.data.saveCount < 5
|
||||||
@@ -652,7 +651,7 @@ def testCoreTools_ProjectBuilderSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
|||||||
data = {
|
data = {
|
||||||
"name": "Test Sample",
|
"name": "Test Sample",
|
||||||
"author": "Jane Doe",
|
"author": "Jane Doe",
|
||||||
"path": fncPath,
|
"path": fncPath / "project",
|
||||||
"sample": True,
|
"sample": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,6 +684,9 @@ def testCoreTools_ProjectBuilderSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
|||||||
zipObj.write(docFile, f"content/{docFile.name}")
|
zipObj.write(docFile, f"content/{docFile.name}")
|
||||||
|
|
||||||
assert builder.buildProject(data) is True
|
assert builder.buildProject(data) is True
|
||||||
|
|
||||||
|
# Can't create to the same target again
|
||||||
|
assert builder.buildProject(data) is False
|
||||||
dstSample.unlink()
|
dstSample.unlink()
|
||||||
|
|
||||||
# END Test testCoreTools_ProjectBuilderSample
|
# END Test testCoreTools_ProjectBuilderSample
|
||||||
|
|||||||
@@ -47,18 +47,18 @@ def testToolWelcome_Main(qtbot: QtBot, monkeypatch, nwGUI, fncPath):
|
|||||||
assert welcome.mainStack.currentIndex() == 0
|
assert welcome.mainStack.currentIndex() == 0
|
||||||
|
|
||||||
# Show the new project form
|
# Show the new project form
|
||||||
welcome.newButton.click()
|
welcome.btnNew.click()
|
||||||
assert welcome.mainStack.currentIndex() == 1
|
assert welcome.mainStack.currentIndex() == 1
|
||||||
|
|
||||||
# Revert to project lits
|
# Revert to project lits
|
||||||
welcome.tabNew.cancelNewProject.emit()
|
welcome.btnList.click()
|
||||||
assert welcome.mainStack.currentIndex() == 0
|
assert welcome.mainStack.currentIndex() == 0
|
||||||
|
|
||||||
# Open a project
|
# Open a project
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(SHARED, "getProjectPath", lambda *a, **k: fncPath)
|
mp.setattr(SHARED, "getProjectPath", lambda *a, **k: fncPath)
|
||||||
with qtbot.waitSignal(welcome.openProjectRequest) as signal:
|
with qtbot.waitSignal(welcome.openProjectRequest) as signal:
|
||||||
welcome.browseButton.click()
|
welcome.btnBrowse.click()
|
||||||
assert signal.args and signal.args[0] == fncPath
|
assert signal.args and signal.args[0] == fncPath
|
||||||
|
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
@@ -103,7 +103,7 @@ def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath):
|
|||||||
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
||||||
assert tabOpen.selectedPath.text() == "Path: /stuff/project_one"
|
assert tabOpen.selectedPath.text() == "Path: /stuff/project_one"
|
||||||
|
|
||||||
# Double Click item
|
# Double click item
|
||||||
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(welcome, "close", lambda *a: None)
|
mp.setattr(welcome, "close", lambda *a: None)
|
||||||
@@ -111,6 +111,14 @@ def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath):
|
|||||||
qtbot.mouseDClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
qtbot.mouseDClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
||||||
assert signal.args and signal.args[0] == Path("/stuff/project_one")
|
assert signal.args and signal.args[0] == Path("/stuff/project_one")
|
||||||
|
|
||||||
|
# Press open button
|
||||||
|
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(welcome, "close", lambda *a: None)
|
||||||
|
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
|
||||||
|
welcome.btnOpen.click()
|
||||||
|
assert signal.args and signal.args[0] == Path("/stuff/project_one")
|
||||||
|
|
||||||
# Context Menu
|
# Context Menu
|
||||||
def getMenuForPos(pos: QPoint) -> QMenu | None:
|
def getMenuForPos(pos: QPoint) -> QMenu | None:
|
||||||
nonlocal tabOpen
|
nonlocal tabOpen
|
||||||
@@ -165,7 +173,7 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
with qtbot.waitExposed(welcome):
|
with qtbot.waitExposed(welcome):
|
||||||
welcome.show()
|
welcome.show()
|
||||||
|
|
||||||
welcome.newButton.click()
|
welcome.btnNew.click()
|
||||||
assert welcome.mainStack.currentIndex() == 1
|
assert welcome.mainStack.currentIndex() == 1
|
||||||
tabNew = welcome.tabNew
|
tabNew = welcome.tabNew
|
||||||
newForm = tabNew.projectForm
|
newForm = tabNew.projectForm
|
||||||
@@ -188,12 +196,7 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
newForm.fillSample.trigger()
|
newForm.fillSample.trigger()
|
||||||
assert newForm._fillMode == newForm.FILL_SAMPLE
|
assert newForm._fillMode == newForm.FILL_SAMPLE
|
||||||
assert newForm.projFill.text() == "Example Project"
|
assert newForm.projFill.text() == "Example Project"
|
||||||
assert newForm.addNotes.isEnabled() is False
|
assert newForm.extraWidget.isVisible() is False
|
||||||
assert newForm.addPlot.isEnabled() is False
|
|
||||||
assert newForm.addChar.isEnabled() is False
|
|
||||||
assert newForm.addWorld.isEnabled() is False
|
|
||||||
assert newForm.numChapters.isEnabled() is False
|
|
||||||
assert newForm.numScenes.isEnabled() is False
|
|
||||||
|
|
||||||
# Change fill info to template
|
# Change fill info to template
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
@@ -201,12 +204,7 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
newForm.fillCopy.trigger()
|
newForm.fillCopy.trigger()
|
||||||
assert newForm._fillMode == newForm.FILL_COPY
|
assert newForm._fillMode == newForm.FILL_COPY
|
||||||
assert newForm.projFill.text() == f"Template: {fncPath}"
|
assert newForm.projFill.text() == f"Template: {fncPath}"
|
||||||
assert newForm.addNotes.isEnabled() is False
|
assert newForm.extraWidget.isVisible() is False
|
||||||
assert newForm.addPlot.isEnabled() is False
|
|
||||||
assert newForm.addChar.isEnabled() is False
|
|
||||||
assert newForm.addWorld.isEnabled() is False
|
|
||||||
assert newForm.numChapters.isEnabled() is False
|
|
||||||
assert newForm.numScenes.isEnabled() is False
|
|
||||||
|
|
||||||
# Change back to fill blank using the menu
|
# Change back to fill blank using the menu
|
||||||
newForm.browseFill.click()
|
newForm.browseFill.click()
|
||||||
@@ -215,16 +213,11 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
newForm.fillMenu.close()
|
newForm.fillMenu.close()
|
||||||
assert newForm._fillMode == newForm.FILL_BLANK
|
assert newForm._fillMode == newForm.FILL_BLANK
|
||||||
assert newForm.projFill.text() == "Fresh Project"
|
assert newForm.projFill.text() == "Fresh Project"
|
||||||
assert newForm.addNotes.isEnabled() is True
|
assert newForm.extraWidget.isVisible() is True
|
||||||
assert newForm.addPlot.isEnabled() is True
|
|
||||||
assert newForm.addChar.isEnabled() is True
|
|
||||||
assert newForm.addWorld.isEnabled() is True
|
|
||||||
assert newForm.numChapters.isEnabled() is True
|
|
||||||
assert newForm.numScenes.isEnabled() is True
|
|
||||||
|
|
||||||
# Creating a project without a name, pops an error
|
# Creating a project without a name, pops an error
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
tabNew.createButton.click()
|
welcome.btnCreate.click()
|
||||||
assert "A project name is required." in caplog.text
|
assert "A project name is required." in caplog.text
|
||||||
|
|
||||||
# Set some more values, and extract data
|
# Set some more values, and extract data
|
||||||
@@ -240,7 +233,6 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
assert newForm.getProjectData() == {
|
assert newForm.getProjectData() == {
|
||||||
"name": "Test Project",
|
"name": "Test Project",
|
||||||
"author": "Jane Smith",
|
"author": "Jane Smith",
|
||||||
"language": "en_GB",
|
|
||||||
"path": str(projPath),
|
"path": str(projPath),
|
||||||
"blank": True,
|
"blank": True,
|
||||||
"sample": False,
|
"sample": False,
|
||||||
@@ -253,7 +245,7 @@ def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
|
|||||||
|
|
||||||
# Create a project with these values
|
# Create a project with these values
|
||||||
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
|
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
|
||||||
tabNew.createButton.click()
|
welcome.btnCreate.click()
|
||||||
assert signal.args and signal.args[0] == projPath
|
assert signal.args and signal.args[0] == projPath
|
||||||
assert (projPath / nwFiles.PROJ_FILE).exists()
|
assert (projPath / nwFiles.PROJ_FILE).exists()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user