""" novelWriter – GUI Doc Merge Dialog ================================== File History: Created: 2020-01-23 [0.4.3] GuiDocMerge Rewritten: 2022-10-06 [2.0rc1] GuiDocMerge This file is a part of novelWriter Copyright (C) 2020 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 PyQt6.QtCore import Qt, pyqtSlot from PyQt6.QtWidgets import ( QAbstractItemView, QDialogButtonBox, QGridLayout, QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget ) from novelwriter import SHARED from novelwriter.enum import nwStandardButton from novelwriter.extensions.configlayout import NColorLabel from novelwriter.extensions.modified import NDialog from novelwriter.extensions.switch import NSwitch from novelwriter.types import QtAccepted, QtRoleAccept, QtRoleReject, QtRoleReset, QtUserRole logger = logging.getLogger(__name__) class GuiDocMerge(NDialog): """GUI: Document Merge Tool.""" D_HANDLE = QtUserRole def __init__(self, parent: QWidget, sHandle: str, itemList: list[str]) -> None: super().__init__(parent=parent) logger.debug("Create: GuiDocMerge") self.setObjectName("GuiDocMerge") self.setWindowTitle(self.tr("Merge Documents")) self._data = {} self.headLabel = QLabel(self.tr("Documents to Merge"), self) self.headLabel.setFont(SHARED.theme.guiFontB) self.helpLabel = NColorLabel( self.tr("Drag and drop items to change the order, or uncheck to exclude."), self, color=SHARED.theme.helpText, wrap=True ) iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize self.listBox = QListWidget(self) self.listBox.setIconSize(iSz) self.listBox.setMinimumWidth(400) self.listBox.setMinimumHeight(180) self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) # Merge Options self.trashSwitch = NSwitch(self, height=iPx) self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self) self.trashLabel.setBuddy(self.trashSwitch) self.optBox = QGridLayout() self.optBox.addWidget(self.trashLabel, 0, 0) self.optBox.addWidget(self.trashSwitch, 0, 1) self.optBox.setHorizontalSpacing(12) self.optBox.setColumnStretch(2, 1) # Buttons self.btnOk = SHARED.theme.getStandardButton(nwStandardButton.OK, self) self.btnOk.clicked.connect(self.accept) self.btnCancel = SHARED.theme.getStandardButton(nwStandardButton.CANCEL, self) self.btnCancel.clicked.connect(self.reject) self.btnReset = SHARED.theme.getStandardButton(nwStandardButton.RESET, self) self.btnReset.clicked.connect(self._resetList) self.btnBox = QDialogButtonBox(self) self.btnBox.addButton(self.btnOk, QtRoleAccept) self.btnBox.addButton(self.btnCancel, QtRoleReject) self.btnBox.addButton(self.btnReset, QtRoleReset) # Assemble self.outerBox = QVBoxLayout() self.outerBox.setSpacing(0) self.outerBox.addWidget(self.headLabel) self.outerBox.addWidget(self.helpLabel) self.outerBox.addSpacing(8) self.outerBox.addWidget(self.listBox) self.outerBox.addSpacing(8) self.outerBox.addLayout(self.optBox) self.outerBox.addSpacing(12) self.outerBox.addWidget(self.btnBox) self.setLayout(self.outerBox) # Load Content self._loadContent(sHandle, itemList) logger.debug("Ready: GuiDocMerge") def __del__(self) -> None: # pragma: no cover logger.debug("Delete: GuiDocMerge") def data(self) -> dict: """Return the user's choices.""" finalItems = [] for i in range(self.listBox.count()): item = self.listBox.item(i) if item is not None and item.checkState() == Qt.CheckState.Checked: finalItems.append(item.data(self.D_HANDLE)) self._data["moveToTrash"] = self.trashSwitch.isChecked() self._data["finalItems"] = finalItems return self._data @classmethod def getData(cls, parent: QWidget, handle: str, items: list[str]) -> tuple[dict, bool]: """Pop the dialog and return the result.""" dialog = cls(parent, handle, items) dialog.exec() data = dialog.data() accepted = dialog.result() == QtAccepted dialog.softDelete() return data, accepted ## # Private Slots ## @pyqtSlot() def _resetList(self) -> None: """Reset the content of the list box to its original state.""" logger.debug("Resetting list box content") if sHandle := self._data.get("sHandle"): itemList = self._data.get("origItems", []) self._loadContent(sHandle, itemList) ## # Internal Functions ## def _loadContent(self, sHandle: str, itemList: list[str]) -> None: """Load content from a given list of items.""" self._data = {} self._data["sHandle"] = sHandle self._data["origItems"] = itemList self.listBox.clear() for tHandle in itemList: if (nwItem := SHARED.project.tree[tHandle]) and nwItem.isFileType(): item = QListWidgetItem() item.setIcon(nwItem.getMainIcon()) item.setText(nwItem.itemName) item.setData(self.D_HANDLE, tHandle) item.setCheckState(Qt.CheckState.Checked) self.listBox.addItem(item)