Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve dialog handling #1844

Merged
merged 3 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions novelwriter/dialogs/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@

from PyQt5.QtGui import QCloseEvent, QColor
from PyQt5.QtWidgets import (
QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
QWidget
QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget
)

from novelwriter import CONFIG, SHARED
from novelwriter.common import cssCol, readTextFile
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NNonBlockingDialog
from novelwriter.extensions.versioninfo import VersionInfoWidget
from novelwriter.types import QtAlignRightTop, QtDialogClose

logger = logging.getLogger(__name__)


class GuiAbout(QDialog):
class GuiAbout(NNonBlockingDialog):

def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
Expand Down
49 changes: 47 additions & 2 deletions novelwriter/extensions/modified.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Created: 2024-02-01 [2.3b1] NComboBox
Created: 2024-02-01 [2.3b1] NSpinBox
Created: 2024-02-01 [2.3b1] NDoubleSpinBox
Created: 2024-05-01 [2.5b1] NToolDialog
Created: 2024-05-01 [2.5b1] NNonBlockingDialog

This file is a part of novelWriter
Copyright 2018–2024, Veronica Berglyd Olsen
Expand All @@ -29,9 +31,52 @@

from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QWheelEvent
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
from PyQt5.QtWidgets import (
QApplication, QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton,
QWidget
)

from novelwriter import SHARED
from novelwriter import CONFIG, SHARED


class NToolDialog(QDialog):

def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent=parent)
self.setModal(False)
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)
return

def activateDialog(self) -> None:
"""Helper function to activate dialog on various systems."""
self.show()
if CONFIG.osWindows:
self.activateWindow()
self.raise_()
QApplication.processEvents()
return

# END Class NToolDialog


class NNonBlockingDialog(QDialog):

def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent=parent)
self.setModal(True)
return

def activateDialog(self) -> None:
"""Helper function to activate dialog on various systems."""
self.show()
if CONFIG.osWindows:
self.activateWindow()
self.raise_()
QApplication.processEvents()
return

# END Class NNonBlockingDialog


class NComboBox(QComboBox):
Expand Down
37 changes: 11 additions & 26 deletions novelwriter/guimain.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@
"""
from __future__ import annotations

import sys
import logging
import sys

from time import time
from pathlib import Path
from datetime import datetime
from pathlib import Path
from time import time

from PyQt5.QtCore import Qt, QTimer, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon
from PyQt5.QtWidgets import (
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter,
QStackedWidget, QVBoxLayout, QWidget
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
QShortcut, QSplitter, QStackedWidget, QVBoxLayout, QWidget
)

from novelwriter import CONFIG, SHARED, __hexversion__, __version__
Expand All @@ -44,7 +44,7 @@
from novelwriter.dialogs.preferences import GuiPreferences
from novelwriter.dialogs.projectsettings import GuiProjectSettings
from novelwriter.dialogs.wordlist import GuiWordList
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwWidget, nwView
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwView, nwWidget
from novelwriter.gui.doceditor import GuiDocEditor
from novelwriter.gui.docviewer import GuiDocViewer
from novelwriter.gui.docviewerpanel import GuiDocViewerPanel
Expand Down Expand Up @@ -794,10 +794,7 @@ def showNovelDetailsDialog(self) -> None:
"""Open the novel details dialog."""
if SHARED.hasProject:
dialog = GuiNovelDetails(self)
dialog.setModal(True)
dialog.show()
dialog.raise_()
QApplication.processEvents()
dialog.activateDialog()
dialog.updateValues()
return

Expand All @@ -807,10 +804,7 @@ def showBuildManuscriptDialog(self) -> None:
if SHARED.hasProject:
if (dialog := SHARED.findTopLevelWidget(GuiManuscript)) is None:
dialog = GuiManuscript(self)
dialog.setModal(False)
dialog.show()
dialog.raise_()
QApplication.processEvents()
dialog.activateDialog()
dialog.loadContent()
return

Expand All @@ -829,21 +823,15 @@ def showWritingStatsDialog(self) -> None:
if SHARED.hasProject:
if (dialog := SHARED.findTopLevelWidget(GuiWritingStats)) is None:
dialog = GuiWritingStats(self)
dialog.setModal(False)
dialog.show()
dialog.raise_()
QApplication.processEvents()
dialog.activateDialog()
dialog.populateGUI()
return

@pyqtSlot()
def showAboutNWDialog(self) -> None:
"""Show the novelWriter about dialog."""
dialog = GuiAbout(self)
dialog.setModal(True)
dialog.show()
dialog.raise_()
QApplication.processEvents()
dialog.activateDialog()
dialog.populateGUI()
return

Expand All @@ -858,10 +846,7 @@ def showAboutQtDialog(self) -> None:
def showDictionariesDialog(self) -> None:
"""Show the download dictionaries dialog."""
dialog = GuiDictionaries(self)
dialog.setModal(True)
dialog.show()
dialog.raise_()
QApplication.processEvents()
dialog.activateDialog()
if not dialog.initDialog():
dialog.close()
SHARED.error(self.tr("Could not initialise the dialog."))
Expand Down
10 changes: 5 additions & 5 deletions novelwriter/tools/dictionaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtGui import QCloseEvent, QTextCursor
from PyQt5.QtWidgets import (
QApplication, QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout,
QLabel, QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
QApplication, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel,
QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
)

from novelwriter import CONFIG, SHARED
from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize
from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath
from novelwriter.error import formatException
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog
from novelwriter.types import QtDialogClose

logger = logging.getLogger(__name__)


class GuiDictionaries(QDialog):
class GuiDictionaries(NNonBlockingDialog):

def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
Expand Down
65 changes: 30 additions & 35 deletions novelwriter/tools/manuscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@

from datetime import datetime
from time import time
from typing import TYPE_CHECKING

from PyQt5.QtCore import QTimer, QUrl, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtWidgets import (
QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout,
QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
QSplitter, QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget,
QTreeWidgetItem, QVBoxLayout, QWidget
QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout,
QLabel, QListWidget, QListWidgetItem, QPushButton, QSplitter,
QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget
)

from novelwriter import CONFIG, SHARED
Expand All @@ -48,7 +47,7 @@
from novelwriter.core.tokenizer import HeadingFormatter
from novelwriter.error import logException
from novelwriter.extensions.circularprogress import NProgressCircle
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
from novelwriter.tools.manusbuild import GuiManuscriptBuild
from novelwriter.tools.manussettings import GuiBuildSettings
Expand All @@ -57,13 +56,10 @@
QtSizeExpanding, QtSizeIgnored, QtUserRole
)

if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain

logger = logging.getLogger(__name__)


class GuiManuscript(QDialog):
class GuiManuscript(NToolDialog):
"""GUI Tools: Manuscript Tool

The dialog displays all the users build definitions, a preview panel
Expand All @@ -73,15 +69,11 @@ class GuiManuscript(QDialog):

D_KEY = QtUserRole

def __init__(self, mainGui: GuiMain) -> None:
super().__init__(parent=mainGui)
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)

logger.debug("Create: GuiManuscript")
self.setObjectName("GuiManuscript")
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)

self.mainGui = mainGui

self._builds = BuildCollection(SHARED.project)
self._buildMap: dict[str, QListWidgetItem] = {}
Expand Down Expand Up @@ -280,7 +272,7 @@ def closeEvent(self, event: QCloseEvent) -> None:
dialog open.
"""
self._saveSettings()
for obj in self.mainGui.children():
for obj in SHARED.mainGui.children():
# Make sure we don't have any settings windows open
if isinstance(obj, GuiBuildSettings) and obj.isVisible():
obj.close()
Expand Down Expand Up @@ -319,6 +311,8 @@ def _deleteSelectedBuild(self) -> None:
"""Delete the currently selected build settings entry."""
if build := self._getSelectedBuild():
if SHARED.question(self.tr("Delete build '{0}'?".format(build.name))):
if dialog := self._findSettingsDialog(build.buildID):
dialog.close()
self._builds.removeBuild(build.buildID)
self._updateBuildsList()
return
Expand Down Expand Up @@ -467,22 +461,14 @@ def _saveSettings(self) -> None:

def _openSettingsDialog(self, build: BuildSettings) -> None:
"""Open the build settings dialog."""
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_()
QApplication.processEvents()
dlgSettings.loadContent()
dlgSettings.newSettingsReady.connect(self._processNewSettings)
if dialog := self._findSettingsDialog(build.buildID):
dialog.activateDialog()
return

dialog = GuiBuildSettings(SHARED.mainGui, build)
dialog.activateDialog()
dialog.loadContent()
dialog.newSettingsReady.connect(self._processNewSettings)

return

Expand All @@ -507,6 +493,15 @@ def _updateBuildItem(self, build: BuildSettings) -> None:
self._updateBuildsList()
return

def _findSettingsDialog(self, buildID: str) -> GuiBuildSettings | None:
"""Return an open build settings dialog for a given build, if
one exists.
"""
for obj in SHARED.mainGui.children():
if isinstance(obj, GuiBuildSettings) and obj.buildID == buildID:
return obj
return None

# END Class GuiManuscript


Expand Down
Loading