""" novelWriter – Custom Widget: Novel Selector =========================================== File History: Created: 2022-11-17 [2.0] NovelSelector This file is a part of novelWriter Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors 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 . """ # noqa from __future__ import annotations import logging from typing import TYPE_CHECKING from PyQt6.QtCore import pyqtSignal, pyqtSlot from PyQt6.QtGui import QPalette from PyQt6.QtWidgets import QComboBox from novelwriter import SHARED from novelwriter.constants import nwLabels from novelwriter.enum import nwItemClass if TYPE_CHECKING: from PyQt6.QtWidgets import QWidget logger = logging.getLogger(__name__) class NovelSelector(QComboBox): """Custom: Novel Root Folder Selector.""" novelSelectionChanged = pyqtSignal(str) def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) self._blockSignal = False self._firstHandle = None self._includeAll = False self._listFormat = None self.currentIndexChanged.connect(self._indexChanged) self.updateTheme() ## # Properties ## @property def handle(self) -> str | None: """Return the selected handle, if any.""" if tHandle := self.currentData(): return tHandle return None @property def firstHandle(self) -> str | None: return self._firstHandle ## # Methods ## def setHandle(self, tHandle: str | None, blockSignal: bool = True) -> None: """Set the currently selected handle.""" if (index := self.findData(tHandle) if tHandle else (self.count() - 1)) >= 0: self._blockSignal = blockSignal self.setCurrentIndex(index) self._blockSignal = False def setIncludeAll(self, value: bool) -> None: """Set flag to add an "All Novel Folders" option.""" self._includeAll = value def setListFormat(self, value: str | None) -> None: """Set a format string for the list entries.""" if value is None or "{0}" in value: self._listFormat = value def updateTheme(self) -> None: """Update theme colours.""" palette = self.palette() palette.setBrush(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, palette.text()) self.setPalette(palette) self.refreshNovelList() ## # Public Slots ## @pyqtSlot() def refreshNovelList(self) -> None: """Rebuild the list of novel items.""" cHandle = self.currentData() self._blockSignal = True self._firstHandle = None self.clear() icon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL], "root") for tHandle, nwItem in SHARED.project.tree.iterRoots(nwItemClass.NOVEL): if self._listFormat: name = self._listFormat.format(nwItem.itemName) self.addItem(name, tHandle) else: name = nwItem.itemName self.addItem(icon, nwItem.itemName, tHandle) if self._firstHandle is None: self._firstHandle = tHandle if self._includeAll: self.insertSeparator(self.count()) self.addItem(icon, self.tr("All Novel Folders"), "") self.setHandle(cHandle) self.setEnabled(self.count() > 1) self._blockSignal = False ## # Private Slots ## @pyqtSlot(int) def _indexChanged(self, index: int) -> None: """Re-emit the change of selection signal, unless blocked.""" if not self._blockSignal: self.novelSelectionChanged.emit(self.currentData())