From bbabc41ac2b18a330d29b0e1be92a351e22d38ba Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 Dec 2023 12:16:52 +0100
Subject: [PATCH] Remove old open project dialog
---
novelwriter/config.py | 12 -
novelwriter/dialogs/projload.py | 294 ------------------------
novelwriter/guimain.py | 21 +-
tests/test_base/test_base_config.py | 13 --
tests/test_dialogs/test_dlg_projload.py | 99 --------
5 files changed, 3 insertions(+), 436 deletions(-)
delete mode 100644 novelwriter/dialogs/projload.py
delete mode 100644 tests/test_dialogs/test_dlg_projload.py
diff --git a/novelwriter/config.py b/novelwriter/config.py
index 000c85c1..cf22fe23 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -112,7 +112,6 @@ class Config:
self._mainWinSize = [1200, 650] # Last size of the main GUI window
self._welcomeSize = [800, 500] # Last size of the welcome window
self._prefsWinSize = [700, 615] # Last size of the Preferences dialog
- self._projLoadCols = [280, 60, 160] # Last columns widths of the Project Load dialog
self._mainPanePos = [300, 800] # Last position of the main window splitter
self._viewPanePos = [500, 150] # Last position of the document viewer splitter
self._outlnPanePos = [500, 150] # Last position of the outline panel splitter
@@ -258,10 +257,6 @@ class Config:
def preferencesWinSize(self) -> list[int]:
return [int(x*self.guiScale) for x in self._prefsWinSize]
- @property
- def projLoadColWidths(self) -> list[int]:
- return [int(x*self.guiScale) for x in self._projLoadCols]
-
@property
def mainPanePos(self) -> list[int]:
return [int(x*self.guiScale) for x in self._mainPanePos]
@@ -323,11 +318,6 @@ class Config:
self._prefsWinSize[1] = int(height/self.guiScale)
return
- def setProjLoadColWidths(self, widths: list[int]) -> None:
- """Set the column widths of the Load Project dialog."""
- self._projLoadCols = [int(x/self.guiScale) for x in widths]
- return
-
def setMainPanePos(self, pos: list[int]) -> None:
"""Set the position of the main GUI splitter."""
self._mainPanePos = [int(x/self.guiScale) for x in pos]
@@ -558,7 +548,6 @@ class Config:
self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
self._welcomeSize = conf.rdIntList(sec, "welcome", self._welcomeSize)
self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
- self._projLoadCols = conf.rdIntList(sec, "projloadcols", self._projLoadCols)
self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
@@ -666,7 +655,6 @@ class Config:
"mainwindow": self._packList(self._mainWinSize),
"welcome": self._packList(self._welcomeSize),
"preferences": self._packList(self._prefsWinSize),
- "projloadcols": self._packList(self._projLoadCols),
"mainpane": self._packList(self._mainPanePos),
"viewpane": self._packList(self._viewPanePos),
"outlinepane": self._packList(self._outlnPanePos),
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
deleted file mode 100644
index 4d48c19d..00000000
--- a/novelwriter/dialogs/projload.py
+++ /dev/null
@@ -1,294 +0,0 @@
-"""
-novelWriter – GUI Open Project
-==============================
-
-File History:
-Created: 2020-02-26 [0.4.5] GuiProjectLoad
-
-This file is a part of novelWriter
-Copyright 2018–2023, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-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 .
-"""
-from __future__ import annotations
-
-import logging
-
-from typing import TYPE_CHECKING
-from pathlib import Path
-from datetime import datetime
-
-from PyQt5.QtGui import QCloseEvent, QKeySequence
-from PyQt5.QtCore import Qt, QSize, pyqtSlot
-from PyQt5.QtWidgets import (
- QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QPushButton, QTreeWidget,
- QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel, QShortcut,
- QFileDialog, QLineEdit
-)
-
-from novelwriter import CONFIG, SHARED
-from novelwriter.common import formatInt
-from novelwriter.constants import nwFiles
-
-if TYPE_CHECKING: # pragma: no cover
- from novelwriter.guimain import GuiMain
-
-logger = logging.getLogger(__name__)
-
-
-class GuiProjectLoad(QDialog):
-
- NONE_STATE = 0
- NEW_STATE = 1
- OPEN_STATE = 2
-
- C_NAME = 0
- C_COUNT = 1
- C_TIME = 2
-
- D_PATH = Qt.ItemDataRole.UserRole
-
- def __init__(self, mainGui: GuiMain) -> None:
- super().__init__(parent=mainGui)
-
- logger.debug("Create: GuiProjectLoad")
- self.setObjectName("GuiProjectLoad")
-
- self.openState = self.NONE_STATE
- self.openPath = None
-
- sPx = CONFIG.pxInt(16)
- nPx = CONFIG.pxInt(96)
- iPx = SHARED.theme.baseIconSize
-
- self.outerBox = QVBoxLayout()
- self.innerBox = QHBoxLayout()
- self.outerBox.setSpacing(sPx)
- self.innerBox.setSpacing(sPx)
-
- self.setWindowTitle(self.tr("Open Project"))
- self.setMinimumWidth(CONFIG.pxInt(650))
- self.setMinimumHeight(CONFIG.pxInt(400))
-
- self.nwIcon = QLabel()
- self.nwIcon.setPixmap(SHARED.theme.getPixmap("novelwriter", (nPx, nPx)))
- self.innerBox.addWidget(self.nwIcon, 0, Qt.AlignTop)
-
- self.projectForm = QGridLayout()
- self.projectForm.setContentsMargins(0, 0, 0, 0)
-
- self.listBox = QTreeWidget()
- self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
- self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
- self.listBox.setColumnCount(3)
- self.listBox.setHeaderLabels([
- self.tr("Working Title"),
- self.tr("Words"),
- self.tr("Last Opened"),
- ])
- self.listBox.setRootIsDecorated(False)
- self.listBox.itemSelectionChanged.connect(self._doSelectRecent)
- self.listBox.itemDoubleClicked.connect(self._doOpenRecent)
- self.listBox.setIconSize(QSize(iPx, iPx))
-
- treeHead = self.listBox.headerItem()
- if treeHead:
- treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
- treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
-
- self.lblRecent = QLabel("%s" % self.tr("Recently Opened Projects"))
- self.lblPath = QLabel("%s" % self.tr("Path"))
- self.selPath = QLineEdit("")
- self.selPath.setReadOnly(True)
-
- self.browseButton = QPushButton(SHARED.theme.getIcon("browse"), "", self)
- self.browseButton.clicked.connect(self._doBrowse)
-
- self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3)
- self.projectForm.addWidget(self.listBox, 1, 0, 1, 3)
- self.projectForm.addWidget(self.lblPath, 2, 0, 1, 1)
- self.projectForm.addWidget(self.selPath, 2, 1, 1, 1)
- self.projectForm.addWidget(self.browseButton, 2, 2, 1, 1)
- self.projectForm.setColumnStretch(0, 0)
- self.projectForm.setColumnStretch(1, 1)
- self.projectForm.setColumnStretch(2, 0)
- self.projectForm.setVerticalSpacing(CONFIG.pxInt(4))
- self.projectForm.setHorizontalSpacing(CONFIG.pxInt(8))
-
- self.innerBox.addLayout(self.projectForm)
-
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Open | QDialogButtonBox.Cancel)
- self.buttonBox.accepted.connect(self._doOpenRecent)
- self.buttonBox.rejected.connect(self._doCancel)
-
- self.newButton = self.buttonBox.addButton(self.tr("New"), QDialogButtonBox.ActionRole)
- self.newButton.clicked.connect(self._doNewProject)
-
- self.delButton = self.buttonBox.addButton(self.tr("Remove"), QDialogButtonBox.ActionRole)
- self.delButton.clicked.connect(self._doDeleteRecent)
-
- self.outerBox.addLayout(self.innerBox)
- self.outerBox.addWidget(self.buttonBox)
- self.setLayout(self.outerBox)
-
- self._populateList()
- self._doSelectRecent()
-
- keyDelete = QShortcut(self.listBox)
- keyDelete.setKey(QKeySequence(Qt.Key_Delete))
- keyDelete.activated.connect(self._doDeleteRecent)
-
- logger.debug("Ready: GuiProjectLoad")
-
- return
-
- def __del__(self) -> None: # pragma: no cover
- logger.debug("Delete: GuiProjectLoad")
- return
-
- ##
- # Private Slots
- ##
-
- @pyqtSlot()
- def _doOpenRecent(self) -> None:
- """Close the dialog window with a recent project selected."""
- self._saveSettings()
-
- self.openPath = None
- self.openState = self.NONE_STATE
-
- selItems = self.listBox.selectedItems()
- if selItems:
- self.openPath = selItems[0].data(self.C_NAME, self.D_PATH)
- self.openState = self.OPEN_STATE
- self.accept()
-
- return
-
- @pyqtSlot()
- def _doSelectRecent(self) -> None:
- """Update path when a recent item has been selected."""
- selList = self.listBox.selectedItems()
- if selList:
- self.selPath.setText(selList[0].data(self.C_NAME, self.D_PATH))
- return
-
- @pyqtSlot()
- def _doBrowse(self) -> None:
- """Browse for a folder path."""
- extFilter = [
- self.tr("novelWriter Project File ({0})").format(nwFiles.PROJ_FILE),
- self.tr("All files ({0})").format("*"),
- ]
- projFile, _ = QFileDialog.getOpenFileName(
- self, self.tr("Open Project"), "", filter=";;".join(extFilter)
- )
- if projFile:
- thePath = Path(projFile).absolute()
- self.selPath.setText(str(thePath))
- self.openPath = thePath
- self.openState = self.OPEN_STATE
- self.accept()
-
- return
-
- @pyqtSlot()
- def _doCancel(self) -> None:
- """Close the dialog window without doing anything."""
- self.openPath = None
- self.openState = self.NONE_STATE
- self.close()
- return
-
- @pyqtSlot()
- def _doNewProject(self) -> None:
- """Create a new project."""
- self._saveSettings()
- self.openPath = None
- self.openState = self.NEW_STATE
- self.accept()
- return
-
- @pyqtSlot()
- def _doDeleteRecent(self) -> None:
- """Remove an entry from the recent projects list."""
- selList = self.listBox.selectedItems()
- if selList:
- projName = selList[0].text(self.C_NAME)
- msgYes = SHARED.question(self.tr(
- "Remove '{0}' from the recent projects list? "
- "The project files will not be deleted."
- ).format(projName))
- if msgYes:
- CONFIG.recentProjects.remove(
- selList[0].data(self.C_NAME, self.D_PATH)
- )
- self._populateList()
-
- return
-
- ##
- # Events
- ##
-
- def closeEvent(self, event: QCloseEvent) -> None:
- """Capture the user closing the dialog and save settings."""
- self._saveSettings()
- event.accept()
- return
-
- ##
- # Internal Functions
- ##
-
- def _saveSettings(self) -> None:
- """Save the changes made to the dialog."""
- colWidths = [0, 0, 0]
- colWidths[self.C_NAME] = self.listBox.columnWidth(self.C_NAME)
- colWidths[self.C_COUNT] = self.listBox.columnWidth(self.C_COUNT)
- colWidths[self.C_TIME] = self.listBox.columnWidth(self.C_TIME)
- CONFIG.setProjLoadColWidths(colWidths)
- return
-
- def _populateList(self) -> None:
- """Populate the list box with recent project data."""
- self.listBox.clear()
- dataList = CONFIG.recentProjects.listEntries()
- sortList = sorted(dataList, key=lambda x: x[3], reverse=True)
- nwxIcon = SHARED.theme.getIcon("proj_nwx")
- for path, title, words, time in sortList:
- newItem = QTreeWidgetItem([""]*4)
- newItem.setIcon(self.C_NAME, nwxIcon)
- newItem.setText(self.C_NAME, title)
- newItem.setData(self.C_NAME, self.D_PATH, path)
- newItem.setText(self.C_COUNT, formatInt(words))
- newItem.setText(self.C_TIME, datetime.fromtimestamp(time).strftime("%x %X"))
- newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
- newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
- newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
- newItem.setFont(self.C_TIME, SHARED.theme.guiFontFixed)
- self.listBox.addTopLevelItem(newItem)
-
- self.listBox.setCurrentItem(self.listBox.topLevelItem(0))
-
- projColWidth = CONFIG.projLoadColWidths
- if len(projColWidth) == 3:
- self.listBox.setColumnWidth(self.C_NAME, projColWidth[self.C_NAME])
- self.listBox.setColumnWidth(self.C_COUNT, projColWidth[self.C_COUNT])
- self.listBox.setColumnWidth(self.C_TIME, projColWidth[self.C_TIME])
-
- return
-
-# END Class GuiProjectLoad
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 75505273..d7a42247 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -30,11 +30,11 @@ from time import time
from pathlib import Path
from datetime import datetime
-from PyQt5.QtCore import Qt, QTimer, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
+from PyQt5.QtCore import Qt, QTimer, pyqtSlot
from PyQt5.QtWidgets import (
- QDialog, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut,
- QSplitter, QStackedWidget, QVBoxLayout, QWidget, qApp
+ QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
+ QStackedWidget, QVBoxLayout, QWidget, qApp
)
from novelwriter import CONFIG, SHARED, __hexversion__
@@ -51,7 +51,6 @@ from novelwriter.gui.itemdetails import GuiItemDetails
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
from novelwriter.dialogs.about import GuiAbout
from novelwriter.dialogs.updates import GuiUpdates
-from novelwriter.dialogs.projload import GuiProjectLoad
from novelwriter.dialogs.wordlist import GuiWordList
from novelwriter.dialogs.preferences import GuiPreferences
from novelwriter.dialogs.projdetails import GuiProjectDetails
@@ -799,20 +798,6 @@ class GuiMain(QMainWindow):
# Main Dialogs
##
- def showProjectLoadDialog(self) -> None:
- """Open the projects dialog for selecting either existing
- projects from a cache of recently opened projects, or provide a
- browse button for projects not yet cached. Selecting to create a
- new project is forwarded to the new project wizard.
- """
- dlgProj = GuiProjectLoad(self)
- dlgProj.exec_()
-
- if dlgProj.result() == QDialog.Accepted:
- if dlgProj.openState == GuiProjectLoad.OPEN_STATE:
- self.openProject(dlgProj.openPath)
- return
-
@pyqtSlot()
def showWelcomeDialog(self) -> None:
"""Open the welcome dialog."""
diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py
index d8938d45..fc85e05a 100644
--- a/tests/test_base/test_base_config.py
+++ b/tests/test_base/test_base_config.py
@@ -291,19 +291,6 @@ def testBaseConfig_SettersGetters(fncPath):
tstConf.setPreferencesWinSize(700, 615)
- # Project Settings Tree Columns
- tstConf.guiScale = 2.0
- tstConf.setProjLoadColWidths([10, 20, 30])
- assert tstConf.projLoadColWidths == [10, 20, 30]
- assert tstConf._projLoadCols == [5, 10, 15]
-
- tstConf.guiScale = 1.0
- tstConf.setProjLoadColWidths([10, 20, 30])
- assert tstConf.projLoadColWidths == [10, 20, 30]
- assert tstConf._projLoadCols == [10, 20, 30]
-
- tstConf.setProjLoadColWidths([200, 60, 140])
-
# Main Pane Splitter
tstConf.guiScale = 2.0
tstConf.setMainPanePos([200, 700])
diff --git a/tests/test_dialogs/test_dlg_projload.py b/tests/test_dialogs/test_dlg_projload.py
deleted file mode 100644
index ad1bd49a..00000000
--- a/tests/test_dialogs/test_dlg_projload.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""
-novelWriter – Project Load Dialog Class Tester
-==============================================
-
-This file is a part of novelWriter
-Copyright 2018–2023, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-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 .
-"""
-from __future__ import annotations
-
-import pytest
-
-from tools import buildTestProject, getGuiItem
-
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import (
- QDialogButtonBox, QTreeWidgetItem, QDialog, QAction, QFileDialog
-)
-
-from novelwriter.dialogs.projload import GuiProjectLoad
-
-
-@pytest.mark.gui
-def testDlgLoadProject_Main(qtbot, monkeypatch, nwGUI, projPath):
- """Test the load project wizard.
- """
- buildTestProject(nwGUI, projPath)
- assert nwGUI.closeProject()
-
- monkeypatch.setattr(GuiProjectLoad, "exec_", lambda *a: None)
- monkeypatch.setattr(GuiProjectLoad, "result", lambda *a: QDialog.Accepted)
- nwGUI.mainMenu.aOpenProject.activate(QAction.Trigger)
- qtbot.waitUntil(lambda: getGuiItem("GuiProjectLoad") is not None, timeout=1000)
-
- nwLoad = getGuiItem("GuiProjectLoad")
- assert isinstance(nwLoad, GuiProjectLoad)
- nwLoad.show()
-
- recentCount = nwLoad.listBox.topLevelItemCount()
- assert recentCount > 0
-
- selItem = nwLoad.listBox.topLevelItem(0)
- selPath = selItem.data(nwLoad.C_NAME, Qt.ItemDataRole.UserRole)
- assert isinstance(selItem, QTreeWidgetItem)
-
- nwLoad.selPath.setText("")
- nwLoad.listBox.setCurrentItem(selItem)
- nwLoad._doSelectRecent()
- assert nwLoad.selPath.text() == selPath
-
- qtbot.mouseClick(nwLoad.buttonBox.button(QDialogButtonBox.Open), Qt.LeftButton)
- assert nwLoad.openPath == selPath
- assert nwLoad.openState == nwLoad.OPEN_STATE
-
- # Just create a new project load from scratch for the rest of the test
- del nwLoad
-
- nwGUI.mainMenu.aOpenProject.activate(QAction.Trigger)
- qtbot.waitUntil(lambda: getGuiItem("GuiProjectLoad") is not None, timeout=1000)
-
- nwLoad = getGuiItem("GuiProjectLoad")
- assert isinstance(nwLoad, GuiProjectLoad)
- nwLoad.show()
-
- qtbot.mouseClick(nwLoad.buttonBox.button(QDialogButtonBox.Cancel), Qt.LeftButton)
- assert nwLoad.openPath is None
- assert nwLoad.openState == nwLoad.NONE_STATE
-
- nwLoad.show()
- qtbot.mouseClick(nwLoad.newButton, Qt.LeftButton)
- assert nwLoad.openPath is None
- assert nwLoad.openState == nwLoad.NEW_STATE
-
- nwLoad.show()
- nwLoad._doDeleteRecent()
- assert nwLoad.listBox.topLevelItemCount() == recentCount - 1
-
- getFile = str(projPath / "nwProject.nwx")
- monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (getFile, None))
- qtbot.mouseClick(nwLoad.browseButton, Qt.LeftButton)
- assert nwLoad.openPath == projPath / "nwProject.nwx"
- assert nwLoad.openState == nwLoad.OPEN_STATE
-
- nwLoad.close()
- # qtbot.stop()
-
-# END Test testDlgLoadProject_Main