Redesign the Document Merge dialog box
This commit is contained in:
@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from novelwriter.core.doctools import DocMerger
|
||||||
from novelwriter.core.document import NWDoc
|
from novelwriter.core.document import NWDoc
|
||||||
from novelwriter.core.index import countWords
|
from novelwriter.core.index import countWords
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
@@ -28,6 +29,7 @@ from novelwriter.core.toodt import ToOdt
|
|||||||
from novelwriter.core.tomd import ToMarkdown
|
from novelwriter.core.tomd import ToMarkdown
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"DocMerger",
|
||||||
"countWords",
|
"countWords",
|
||||||
"NWDoc",
|
"NWDoc",
|
||||||
"NWProject",
|
"NWProject",
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
"""
|
||||||
|
novelWriter – Project Document Tools
|
||||||
|
====================================
|
||||||
|
A collection of tools to create and manipulate documents
|
||||||
|
|
||||||
|
File History:
|
||||||
|
Created: 2022-10-02 [2.0b1]
|
||||||
|
|
||||||
|
This file is a part of novelWriter
|
||||||
|
Copyright 2018–2022, 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 <https://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# logger.verbose("GuiDocMerge merge button clicked")
|
||||||
|
|
||||||
|
# finalOrder = []
|
||||||
|
# for i in range(self.listBox.count()):
|
||||||
|
# finalOrder.append(self.listBox.item(i).data(Qt.UserRole))
|
||||||
|
|
||||||
|
# if len(finalOrder) == 0:
|
||||||
|
# self.mainGui.makeAlert(self.tr(
|
||||||
|
# "No source documents found. Nothing to do."
|
||||||
|
# ), nwAlert.ERROR)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# theText = ""
|
||||||
|
# for tHandle in finalOrder:
|
||||||
|
# inDoc = NWDoc(self.theProject, tHandle)
|
||||||
|
# docText = inDoc.readDocument()
|
||||||
|
# docErr = inDoc.getError()
|
||||||
|
# if docText is None and docErr:
|
||||||
|
# self.mainGui.makeAlert([
|
||||||
|
# self.tr("Failed to open document file."), docErr
|
||||||
|
# ], nwAlert.ERROR)
|
||||||
|
# if docText:
|
||||||
|
# theText += docText.rstrip("\n")+"\n\n"
|
||||||
|
|
||||||
|
# if self.sourceItem is None:
|
||||||
|
# self.mainGui.makeAlert(self.tr(
|
||||||
|
# "No source folder selected. Nothing to do."
|
||||||
|
# ), nwAlert.ERROR)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# srcItem = self.theProject.tree[self.sourceItem]
|
||||||
|
# if srcItem is None:
|
||||||
|
# self.mainGui.makeAlert(self.tr("Internal error."), nwAlert.ERROR)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemParent)
|
||||||
|
# newItem = self.theProject.tree[nHandle]
|
||||||
|
# newItem.setStatus(srcItem.itemStatus)
|
||||||
|
# newItem.setImport(srcItem.itemImport)
|
||||||
|
|
||||||
|
# outDoc = NWDoc(self.theProject, nHandle)
|
||||||
|
# if not outDoc.writeDocument(theText):
|
||||||
|
# self.mainGui.makeAlert([
|
||||||
|
# self.tr("Could not save document."), outDoc.getError()
|
||||||
|
# ], nwAlert.ERROR)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# self.mainGui.projView.revealNewTreeItem(nHandle)
|
||||||
|
# self.mainGui.openDocument(nHandle, doScroll=True)
|
||||||
|
|
||||||
|
# self._doClose()
|
||||||
|
|
||||||
|
|
||||||
|
class DocMerger:
|
||||||
|
|
||||||
|
def __init__(self, theProject):
|
||||||
|
|
||||||
|
self.theProject = theProject
|
||||||
|
|
||||||
|
self._targetDoc = None
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def setTargetDoc(self, tHandle):
|
||||||
|
return
|
||||||
|
|
||||||
|
def createNewDoc(self, docLabel, pHandle, itemLayout):
|
||||||
|
return
|
||||||
|
|
||||||
|
def appendDoc(self, tHandle):
|
||||||
|
return
|
||||||
|
|
||||||
|
# END Class DocMerger
|
||||||
+76
-113
@@ -1,10 +1,11 @@
|
|||||||
"""
|
"""
|
||||||
novelWriter – GUI Doc Merge Tool
|
novelWriter – GUI Doc Merge Dialog
|
||||||
================================
|
==================================
|
||||||
GUI class for merging multiple documents to one document
|
Custom dialog class for merging documents.
|
||||||
|
|
||||||
File History:
|
File History:
|
||||||
Created: 2020-01-23 [0.4.3]
|
Created: 2020-01-23 [0.4.3]
|
||||||
|
Rewritten: 2022-10-06 [2.0b1]
|
||||||
|
|
||||||
This file is a part of novelWriter
|
This file is a part of novelWriter
|
||||||
Copyright 2018–2022, Veronica Berglyd Olsen
|
Copyright 2018–2022, Veronica Berglyd Olsen
|
||||||
@@ -26,169 +27,131 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
import logging
|
import logging
|
||||||
import novelwriter
|
import novelwriter
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt, QSize
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QDialog, QVBoxLayout, QLabel, QListWidget, QAbstractItemView,
|
QDialog, QVBoxLayout, QLabel, QListWidget, QAbstractItemView,
|
||||||
QListWidgetItem, QDialogButtonBox
|
QListWidgetItem, QDialogButtonBox, QGridLayout
|
||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter.core import NWDoc
|
from novelwriter.gui.custom import QHelpLabel, QSwitch
|
||||||
from novelwriter.enum import nwAlert, nwItemType
|
|
||||||
from novelwriter.gui.custom import QHelpLabel
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class GuiDocMerge(QDialog):
|
class GuiDocMerge(QDialog):
|
||||||
|
|
||||||
def __init__(self, mainGui):
|
def __init__(self, mainGui, sHandle, itemList):
|
||||||
QDialog.__init__(self, mainGui)
|
super().__init__(parent=mainGui)
|
||||||
|
|
||||||
logger.debug("Initialising GuiDocMerge ...")
|
logger.debug("Initialising GuiDocMerge ...")
|
||||||
self.setObjectName("GuiDocMerge")
|
self.setObjectName("GuiDocMerge")
|
||||||
|
|
||||||
self.mainConf = novelwriter.CONFIG
|
self.mainConf = novelwriter.CONFIG
|
||||||
self.mainGui = mainGui
|
self.mainGui = mainGui
|
||||||
|
self.mainTheme = mainGui.mainTheme
|
||||||
self.theProject = mainGui.theProject
|
self.theProject = mainGui.theProject
|
||||||
self.sourceItem = None
|
|
||||||
|
|
||||||
self.outerBox = QVBoxLayout()
|
self._data = {}
|
||||||
|
|
||||||
self.setWindowTitle(self.tr("Merge Documents"))
|
self.setWindowTitle(self.tr("Merge Documents"))
|
||||||
|
|
||||||
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
|
self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
|
||||||
self.helpLabel = QHelpLabel(
|
self.helpLabel = QHelpLabel(self.tr(
|
||||||
self.tr("Drag and drop items to change the order."), self.mainGui.mainTheme.helpText
|
"Drag and drop items to change the order, or uncheck to exclude."
|
||||||
)
|
), self.mainTheme.helpText)
|
||||||
|
|
||||||
|
iPx = self.mainTheme.baseIconSize
|
||||||
|
hSp = self.mainConf.pxInt(12)
|
||||||
|
vSp = self.mainConf.pxInt(8)
|
||||||
|
bSp = self.mainConf.pxInt(12)
|
||||||
|
|
||||||
self.listBox = QListWidget()
|
self.listBox = QListWidget()
|
||||||
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
|
self.listBox.setIconSize(QSize(iPx, iPx))
|
||||||
self.listBox.setMinimumWidth(self.mainConf.pxInt(400))
|
self.listBox.setMinimumWidth(self.mainConf.pxInt(400))
|
||||||
self.listBox.setMinimumHeight(self.mainConf.pxInt(180))
|
self.listBox.setMinimumHeight(self.mainConf.pxInt(180))
|
||||||
|
self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
|
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
|
||||||
|
|
||||||
|
# Merge Options
|
||||||
|
self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
|
||||||
|
self.trashSwitch = QSwitch()
|
||||||
|
|
||||||
|
self.optBox = QGridLayout()
|
||||||
|
self.optBox.addWidget(self.trashLabel, 0, 0)
|
||||||
|
self.optBox.addWidget(self.trashSwitch, 0, 1)
|
||||||
|
self.optBox.setHorizontalSpacing(hSp)
|
||||||
|
self.optBox.setColumnStretch(2, 1)
|
||||||
|
|
||||||
|
# Buttons
|
||||||
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||||
self.buttonBox.accepted.connect(self._doMerge)
|
self.buttonBox.accepted.connect(self.accept)
|
||||||
self.buttonBox.rejected.connect(self._doClose)
|
self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
# Assemble
|
||||||
|
self.outerBox = QVBoxLayout()
|
||||||
self.outerBox.setSpacing(0)
|
self.outerBox.setSpacing(0)
|
||||||
self.outerBox.addWidget(self.headLabel)
|
self.outerBox.addWidget(self.headLabel)
|
||||||
self.outerBox.addWidget(self.helpLabel)
|
self.outerBox.addWidget(self.helpLabel)
|
||||||
self.outerBox.addSpacing(self.mainConf.pxInt(8))
|
self.outerBox.addSpacing(vSp)
|
||||||
self.outerBox.addWidget(self.listBox)
|
self.outerBox.addWidget(self.listBox)
|
||||||
self.outerBox.addSpacing(self.mainConf.pxInt(12))
|
self.outerBox.addSpacing(vSp)
|
||||||
|
self.outerBox.addLayout(self.optBox)
|
||||||
|
self.outerBox.addSpacing(bSp)
|
||||||
self.outerBox.addWidget(self.buttonBox)
|
self.outerBox.addWidget(self.buttonBox)
|
||||||
self.setLayout(self.outerBox)
|
self.setLayout(self.outerBox)
|
||||||
|
|
||||||
self.rejected.connect(self._doClose)
|
# Load Content
|
||||||
|
self._loadContent(sHandle, itemList)
|
||||||
self._populateList()
|
|
||||||
|
|
||||||
logger.debug("GuiDocMerge initialisation complete")
|
logger.debug("GuiDocMerge initialisation complete")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
def getData(self):
|
||||||
# Buttons
|
"""Return the user's choices.
|
||||||
##
|
|
||||||
|
|
||||||
def _doMerge(self):
|
|
||||||
"""Perform the merge of the files in the selected folder, and
|
|
||||||
create a new file in the same parent folder. The old files are
|
|
||||||
not removed in the merge process, and must be deleted manually.
|
|
||||||
"""
|
"""
|
||||||
logger.verbose("GuiDocMerge merge button clicked")
|
finalItems = []
|
||||||
|
|
||||||
finalOrder = []
|
|
||||||
for i in range(self.listBox.count()):
|
for i in range(self.listBox.count()):
|
||||||
finalOrder.append(self.listBox.item(i).data(Qt.UserRole))
|
item = self.listBox.item(i)
|
||||||
|
if item.checkState() == Qt.Checked:
|
||||||
|
finalItems.append(item.data(Qt.UserRole))
|
||||||
|
|
||||||
if len(finalOrder) == 0:
|
self._data["moveToTrash"] = self.trashSwitch.isChecked()
|
||||||
self.mainGui.makeAlert(self.tr(
|
self._data["finalItems"] = finalItems
|
||||||
"No source documents found. Nothing to do."
|
|
||||||
), nwAlert.ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
theText = ""
|
return self._data
|
||||||
for tHandle in finalOrder:
|
|
||||||
inDoc = NWDoc(self.theProject, tHandle)
|
|
||||||
docText = inDoc.readDocument()
|
|
||||||
docErr = inDoc.getError()
|
|
||||||
if docText is None and docErr:
|
|
||||||
self.mainGui.makeAlert([
|
|
||||||
self.tr("Failed to open document file."), docErr
|
|
||||||
], nwAlert.ERROR)
|
|
||||||
if docText:
|
|
||||||
theText += docText.rstrip("\n")+"\n\n"
|
|
||||||
|
|
||||||
if self.sourceItem is None:
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
|
||||||
"No source folder selected. Nothing to do."
|
|
||||||
), nwAlert.ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
srcItem = self.theProject.tree[self.sourceItem]
|
|
||||||
if srcItem is None:
|
|
||||||
self.mainGui.makeAlert(self.tr("Internal error."), nwAlert.ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemParent)
|
|
||||||
newItem = self.theProject.tree[nHandle]
|
|
||||||
newItem.setStatus(srcItem.itemStatus)
|
|
||||||
newItem.setImport(srcItem.itemImport)
|
|
||||||
|
|
||||||
outDoc = NWDoc(self.theProject, nHandle)
|
|
||||||
if not outDoc.writeDocument(theText):
|
|
||||||
self.mainGui.makeAlert([
|
|
||||||
self.tr("Could not save document."), outDoc.getError()
|
|
||||||
], nwAlert.ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.mainGui.projView.revealNewTreeItem(nHandle)
|
|
||||||
self.mainGui.openDocument(nHandle, doScroll=True)
|
|
||||||
|
|
||||||
self._doClose()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _doClose(self):
|
|
||||||
"""Close the dialog window without doing anything.
|
|
||||||
"""
|
|
||||||
self.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _populateList(self):
|
def _loadContent(self, sHandle, itemList):
|
||||||
"""Get the item selected in the tree, check that it is a folder,
|
"""Load content from a given list of items.
|
||||||
and try to find all files associated with it. The valid files
|
|
||||||
are then added to the list view in order. The list itself can be
|
|
||||||
reordered by the user.
|
|
||||||
"""
|
"""
|
||||||
tHandle = self.mainGui.projView.getSelectedHandle()
|
self._data = {}
|
||||||
self.sourceItem = tHandle
|
self._data["sHandle"] = sHandle
|
||||||
if tHandle is None:
|
self._data["origItems"] = itemList
|
||||||
return False
|
|
||||||
|
|
||||||
nwItem = self.theProject.tree[tHandle]
|
self.listBox.clear()
|
||||||
if nwItem is None:
|
for tHandle in itemList:
|
||||||
return False
|
nwItem = self.theProject.tree[tHandle]
|
||||||
|
if nwItem is None or not nwItem.isFileType():
|
||||||
if nwItem.itemType is not nwItemType.FOLDER:
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
|
||||||
"Element selected in the project tree must be a folder."
|
|
||||||
), nwAlert.ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle):
|
|
||||||
newItem = QListWidgetItem()
|
|
||||||
nwItem = self.theProject.tree[sHandle]
|
|
||||||
if not nwItem.isFileType():
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
|
||||||
|
itemIcon = self.mainTheme.getItemIcon(
|
||||||
|
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
newItem = QListWidgetItem()
|
||||||
|
newItem.setIcon(itemIcon)
|
||||||
newItem.setText(nwItem.itemName)
|
newItem.setText(nwItem.itemName)
|
||||||
newItem.setData(Qt.UserRole, sHandle)
|
newItem.setData(Qt.UserRole, tHandle)
|
||||||
|
newItem.setCheckState(Qt.Checked)
|
||||||
|
|
||||||
self.listBox.addItem(newItem)
|
self.listBox.addItem(newItem)
|
||||||
|
|
||||||
return True
|
return
|
||||||
|
|
||||||
# END Class GuiDocMerge
|
# END Class GuiDocMerge
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ class QConfigLayout(QGridLayout):
|
|||||||
class QHelpLabel(QLabel):
|
class QHelpLabel(QLabel):
|
||||||
|
|
||||||
def __init__(self, theText, textCol, fontSize=0.9):
|
def __init__(self, theText, textCol, fontSize=0.9):
|
||||||
QLabel.__init__(self, theText)
|
super().__init__(theText)
|
||||||
|
|
||||||
if isinstance(textCol, QColor):
|
if isinstance(textCol, QColor):
|
||||||
qCol = textCol
|
qCol = textCol
|
||||||
@@ -377,7 +377,7 @@ class QSwitch(QAbstractButton):
|
|||||||
class PagedDialog(QDialog):
|
class PagedDialog(QDialog):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QDialog.__init__(self, parent=parent)
|
super().__init__(parent=parent)
|
||||||
|
|
||||||
self._tabBar = VerticalTabBar(self)
|
self._tabBar = VerticalTabBar(self)
|
||||||
self._tabBar.setExpanding(False)
|
self._tabBar.setExpanding(False)
|
||||||
@@ -410,13 +410,13 @@ class PagedDialog(QDialog):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def addTab(self, widget, label):
|
def addTab(self, widget, label):
|
||||||
"""Forwards the adding of tabs to the QTabWidget.
|
"""Forward the adding of tabs to the QTabWidget.
|
||||||
"""
|
"""
|
||||||
self._tabBox.addTab(widget, label)
|
self._tabBox.addTab(widget, label)
|
||||||
return
|
return
|
||||||
|
|
||||||
def addControls(self, buttonBar):
|
def addControls(self, buttonBar):
|
||||||
"""Adds a button bar to the dialog.
|
"""Add a button bar to the dialog.
|
||||||
"""
|
"""
|
||||||
self._buttonBox.addWidget(buttonBar)
|
self._buttonBox.addWidget(buttonBar)
|
||||||
return
|
return
|
||||||
@@ -427,14 +427,14 @@ class PagedDialog(QDialog):
|
|||||||
class VerticalTabBar(QTabBar):
|
class VerticalTabBar(QTabBar):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QTabBar.__init__(self, parent=parent)
|
super().__init__(parent=parent)
|
||||||
self._mW = novelwriter.CONFIG.pxInt(150)
|
self._mW = novelwriter.CONFIG.pxInt(150)
|
||||||
return
|
return
|
||||||
|
|
||||||
def tabSizeHint(self, index):
|
def tabSizeHint(self, index):
|
||||||
"""Returns a transposed size hint for the rotated bar.
|
"""Return a transposed size hint for the rotated bar.
|
||||||
"""
|
"""
|
||||||
tSize = QTabBar.tabSizeHint(self, index)
|
tSize = super().tabSizeHint(index)
|
||||||
tSize.transpose()
|
tSize.transpose()
|
||||||
tSize.setWidth(min(tSize.width(), self._mW))
|
tSize.setWidth(min(tSize.width(), self._mW))
|
||||||
return tSize
|
return tSize
|
||||||
|
|||||||
+51
-11
@@ -34,15 +34,15 @@ from time import time
|
|||||||
from PyQt5.QtGui import QPalette
|
from PyQt5.QtGui import QPalette
|
||||||
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAbstractItemView, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
QAbstractItemView, QFrame, QHBoxLayout, QHeaderView, QLabel, QDialog,
|
||||||
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
|
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
|
||||||
QVBoxLayout, QWidget
|
QVBoxLayout, QWidget
|
||||||
)
|
)
|
||||||
|
|
||||||
from novelwriter.core import NWDoc
|
from novelwriter.core import NWDoc
|
||||||
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
||||||
|
from novelwriter.dialogs import GuiDocMerge, GuiEditLabel
|
||||||
from novelwriter.constants import nwHeaders, trConst, nwLabels
|
from novelwriter.constants import nwHeaders, trConst, nwLabels
|
||||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
self.mainConf = novelwriter.CONFIG
|
self.mainConf = novelwriter.CONFIG
|
||||||
self.projView = projView
|
self.projView = projView
|
||||||
self.mainGui = projView.mainGui
|
self.mainGui = projView.mainGui
|
||||||
self.mainTheme = projView.mainGui.mainTheme
|
self.mainTheme = projView.mainGui.mainTheme
|
||||||
self.theProject = projView.mainGui.theProject
|
self.theProject = projView.mainGui.theProject
|
||||||
|
|
||||||
# Internal Variables
|
# Internal Variables
|
||||||
@@ -382,9 +382,8 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
trRoot = self.invisibleRootItem()
|
trRoot = self.invisibleRootItem()
|
||||||
trRoot.setFlags(trRoot.flags() ^ Qt.ItemIsDropEnabled)
|
trRoot.setFlags(trRoot.flags() ^ Qt.ItemIsDropEnabled)
|
||||||
|
|
||||||
# Set Multiple Selection by CTRL
|
# Set selection options
|
||||||
# Disabled for now, until the merge files option has been added
|
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
# self.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
|
||||||
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
|
||||||
# Connect signals
|
# Connect signals
|
||||||
@@ -1077,16 +1076,21 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
lambda n, key=key: self._changeItemImport(tHandle, key)
|
lambda n, key=key: self._changeItemImport(tHandle, key)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Transform Item
|
||||||
|
# ==============
|
||||||
|
|
||||||
|
mTrans = ctxMenu.addMenu(self.tr("Transform"))
|
||||||
|
|
||||||
if isFile and tItem.documentAllowed():
|
if isFile and tItem.documentAllowed():
|
||||||
if tItem.isNoteLayout():
|
if tItem.isNoteLayout():
|
||||||
ctxMenu.addAction(
|
mTrans.addAction(
|
||||||
self.tr("Convert to {0}").format(
|
self.tr("Convert to {0}").format(
|
||||||
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
|
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
|
||||||
),
|
),
|
||||||
lambda: self._changeItemLayout(tHandle, nwItemLayout.DOCUMENT)
|
lambda: self._changeItemLayout(tHandle, nwItemLayout.DOCUMENT)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ctxMenu.addAction(
|
mTrans.addAction(
|
||||||
self.tr("Convert to {0}").format(
|
self.tr("Convert to {0}").format(
|
||||||
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
|
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
|
||||||
),
|
),
|
||||||
@@ -1094,19 +1098,37 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
)
|
)
|
||||||
elif isFolder:
|
elif isFolder:
|
||||||
if tItem.documentAllowed():
|
if tItem.documentAllowed():
|
||||||
ctxMenu.addAction(
|
mTrans.addAction(
|
||||||
self.tr("Convert to {0}").format(
|
self.tr("Convert to {0}").format(
|
||||||
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
|
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
|
||||||
),
|
),
|
||||||
lambda: self._covertFolderToFile(tHandle, nwItemLayout.DOCUMENT)
|
lambda: self._covertFolderToFile(tHandle, nwItemLayout.DOCUMENT)
|
||||||
)
|
)
|
||||||
ctxMenu.addAction(
|
mTrans.addAction(
|
||||||
self.tr("Convert to {0}").format(
|
self.tr("Convert to {0}").format(
|
||||||
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
|
trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
|
||||||
),
|
),
|
||||||
lambda: self._covertFolderToFile(tHandle, nwItemLayout.NOTE)
|
lambda: self._covertFolderToFile(tHandle, nwItemLayout.NOTE)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if hasChild:
|
||||||
|
if isFile:
|
||||||
|
mTrans.addAction(
|
||||||
|
self.tr("Merge Child Documents"),
|
||||||
|
lambda: self._mergeDocuments(tHandle, isFile)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
mTrans.addAction(
|
||||||
|
self.tr("Combine Documents in Folder"),
|
||||||
|
lambda: self._mergeDocuments(tHandle, isFile)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isFile:
|
||||||
|
mTrans.addAction(
|
||||||
|
self.tr("Split Document by Header"),
|
||||||
|
lambda: self._splitDocument(tHandle)
|
||||||
|
)
|
||||||
|
|
||||||
ctxMenu.addSeparator()
|
ctxMenu.addSeparator()
|
||||||
|
|
||||||
# Expand/Collapse
|
# Expand/Collapse
|
||||||
@@ -1355,6 +1377,24 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
logger.info("Folder conversion cancelled")
|
logger.info("Folder conversion cancelled")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _mergeDocuments(self, tHandle, isFile):
|
||||||
|
"""Merge an item's child documents into a single document.
|
||||||
|
"""
|
||||||
|
logger.info("Request to merge items under handle '%s'", tHandle)
|
||||||
|
itemList = self.getTreeFromHandle(tHandle)
|
||||||
|
itemList.remove(tHandle)
|
||||||
|
|
||||||
|
dlgMerge = GuiDocMerge(self.mainGui, tHandle, itemList)
|
||||||
|
dlgMerge.exec_()
|
||||||
|
|
||||||
|
if dlgMerge.result() == QDialog.Accepted:
|
||||||
|
print(dlgMerge.getData())
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def _splitDocument(self, tHandle):
|
||||||
|
return
|
||||||
|
|
||||||
def _scanChildren(self, theList, tItem, tIndex):
|
def _scanChildren(self, theList, tItem, tIndex):
|
||||||
"""This is a recursive function returning all items in a tree
|
"""This is a recursive function returning all items in a tree
|
||||||
starting at a given QTreeWidgetItem.
|
starting at a given QTreeWidgetItem.
|
||||||
@@ -1380,7 +1420,7 @@ class GuiProjectTree(QTreeWidget):
|
|||||||
"""
|
"""
|
||||||
tHandle = nwItem.itemHandle
|
tHandle = nwItem.itemHandle
|
||||||
pHandle = nwItem.itemParent
|
pHandle = nwItem.itemParent
|
||||||
newItem = QTreeWidgetItem([""]*4)
|
newItem = QTreeWidgetItem()
|
||||||
|
|
||||||
newItem.setText(self.C_NAME, "")
|
newItem.setText(self.C_NAME, "")
|
||||||
newItem.setText(self.C_COUNT, "0")
|
newItem.setText(self.C_COUNT, "0")
|
||||||
|
|||||||
Reference in New Issue
Block a user