Add import/export for status labels

This commit is contained in:
Veronica Berglyd Olsen
2024-12-31 00:14:47 +01:00
parent 136939d391
commit 9461eea03a
2 changed files with 84 additions and 16 deletions
+14
View File
@@ -174,6 +174,20 @@ class NWStatus:
"""Yield entries from the status icons.""" """Yield entries from the status icons."""
yield from self._store.items() yield from self._store.items()
def fromRaw(self, data: list[str]) -> StatusEntry | None:
"""Create a StatusEntry from a list of three strings consisting
of shape, colour, and name. This entry is not automatically
added to the list of entries.
"""
try:
shape = nwStatusShape[str(data[0])]
color = QColor(str(data[1]))
icon = NWStatus.createIcon(self._height, color, shape)
return StatusEntry(simplified(data[2]), color, shape, icon)
except Exception:
logger.error("Could not parse entry %s", str(data))
return None
@staticmethod @staticmethod
def createIcon(height: int, color: QColor, shape: nwStatusShape) -> QIcon: def createIcon(height: int, color: QColor, shape: nwStatusShape) -> QIcon:
"""Generate an icon for a status label.""" """Generate an icon for a status label."""
+70 -16
View File
@@ -24,18 +24,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations from __future__ import annotations
import csv
import logging import logging
from pathlib import Path
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QColor from PyQt5.QtGui import QCloseEvent, QColor
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox, QAbstractItemView, QApplication, QColorDialog, QDialogButtonBox,
QHBoxLayout, QLineEdit, QMenu, QStackedWidget, QTreeWidget, QFileDialog, QGridLayout, QHBoxLayout, QLineEdit, QMenu, QStackedWidget,
QTreeWidgetItem, QVBoxLayout, QWidget QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import qtLambda, simplified from novelwriter.common import formatFileFilter, qtLambda, simplified
from novelwriter.constants import nwLabels, trConst from novelwriter.constants import nwLabels, trConst
from novelwriter.core.status import NWStatus, StatusEntry from novelwriter.core.status import NWStatus, StatusEntry
from novelwriter.enum import nwStatusShape from novelwriter.enum import nwStatusShape
@@ -310,11 +313,13 @@ class _StatusPage(NFixedPage):
super().__init__(parent=parent) super().__init__(parent=parent)
if isStatus: if isStatus:
status = SHARED.project.data.itemStatus self._kind = self.tr("Status")
self._store = SHARED.project.data.itemStatus
pageLabel = self.tr("Novel Document Status Levels") pageLabel = self.tr("Novel Document Status Levels")
colSetting = "statusColW" colSetting = "statusColW"
else: else:
status = SHARED.project.data.itemImport self._kind = self.tr("Importance")
self._store = SHARED.project.data.itemImport
pageLabel = self.tr("Project Note Importance Levels") pageLabel = self.tr("Project Note Importance Levels")
colSetting = "importColW" colSetting = "importColW"
@@ -354,21 +359,33 @@ class _StatusPage(NFixedPage):
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged) self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
for key, entry in status.iterItems(): for key, entry in self._store.iterItems():
self._addItem(key, StatusEntry.duplicate(entry)) self._addItem(key, StatusEntry.duplicate(entry))
# List Controls # List Controls
self.addButton = NIconToolButton(self, iSz, "add") self.addButton = NIconToolButton(self, iSz, "add")
self.addButton.setToolTip(self.tr("Add Label"))
self.addButton.clicked.connect(self._onItemCreate) self.addButton.clicked.connect(self._onItemCreate)
self.delButton = NIconToolButton(self, iSz, "remove") self.delButton = NIconToolButton(self, iSz, "remove")
self.delButton.setToolTip(self.tr("Delete Label"))
self.delButton.clicked.connect(self._onItemDelete) self.delButton.clicked.connect(self._onItemDelete)
self.upButton = NIconToolButton(self, iSz, "up") self.upButton = NIconToolButton(self, iSz, "up")
self.upButton.setToolTip(self.tr("Move Up"))
self.upButton.clicked.connect(qtLambda(self._moveItem, -1)) self.upButton.clicked.connect(qtLambda(self._moveItem, -1))
self.dnButton = NIconToolButton(self, iSz, "down") self.downButton = NIconToolButton(self, iSz, "down")
self.dnButton.clicked.connect(qtLambda(self._moveItem, 1)) self.downButton.setToolTip(self.tr("Move Down"))
self.downButton.clicked.connect(qtLambda(self._moveItem, 1))
self.importButton = NIconToolButton(self, iSz, "import")
self.importButton.setToolTip(self.tr("Import Labels"))
self.importButton.clicked.connect(self._importLabels)
self.exportButton = NIconToolButton(self, iSz, "export")
self.exportButton.setToolTip(self.tr("Export Labels"))
self.exportButton.clicked.connect(self._exportLabels)
# Edit Form # Edit Form
self.labelText = QLineEdit(self) self.labelText = QLineEdit(self)
@@ -414,21 +431,22 @@ class _StatusPage(NFixedPage):
self.listControls.addWidget(self.addButton) self.listControls.addWidget(self.addButton)
self.listControls.addWidget(self.delButton) self.listControls.addWidget(self.delButton)
self.listControls.addWidget(self.upButton) self.listControls.addWidget(self.upButton)
self.listControls.addWidget(self.dnButton) self.listControls.addWidget(self.downButton)
self.listControls.addStretch(1) self.listControls.addStretch(1)
self.listControls.addWidget(self.importButton)
self.listControls.addWidget(self.exportButton)
self.editBox = QHBoxLayout() self.editBox = QHBoxLayout()
self.editBox.addWidget(self.labelText, 1) self.editBox.addWidget(self.labelText, 1)
self.editBox.addWidget(self.colorButton, 0) self.editBox.addWidget(self.colorButton, 0)
self.editBox.addWidget(self.shapeButton, 0) self.editBox.addWidget(self.shapeButton, 0)
self.mainBox = QVBoxLayout() self.innerBox = QGridLayout()
self.mainBox.addWidget(self.listBox, 1) self.innerBox.addWidget(self.listBox, 0, 0)
self.mainBox.addLayout(self.editBox, 0) self.innerBox.addLayout(self.listControls, 0, 1)
self.innerBox.addLayout(self.editBox, 1, 0)
self.innerBox = QHBoxLayout() self.innerBox.setRowStretch(0, 1)
self.innerBox.addLayout(self.mainBox, 1) self.innerBox.setColumnStretch(1, 0)
self.innerBox.addLayout(self.listControls, 0)
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.pageTitle, 0) self.outerBox.addWidget(self.pageTitle, 0)
@@ -540,6 +558,42 @@ class _StatusPage(NFixedPage):
self.shapeButton.setEnabled(False) self.shapeButton.setEnabled(False)
return return
@pyqtSlot()
def _importLabels(self) -> None:
"""Import labels from file."""
if path := QFileDialog.getOpenFileName(
self, self.tr("Import File"),
str(CONFIG.homePath()), filter=formatFileFilter(["*.csv", "*"]),
)[0]:
try:
with open(path, mode="r", encoding="utf-8") as fo:
for row in csv.reader(fo):
if entry := self._store.fromRaw(row):
self._addItem(None, entry)
except Exception as exc:
SHARED.error("Could not read file.", exc=exc)
return
return
@pyqtSlot()
def _exportLabels(self) -> None:
"""Export labels to file."""
name = f"{SHARED.project.data.fileSafeName} - {self._kind}.csv"
if path := QFileDialog.getSaveFileName(
self, self.tr("Export File"), str(CONFIG.homePath() / name),
)[0]:
try:
path = Path(path).with_suffix(".csv")
with open(path, mode="w", encoding="utf-8") as fo:
writer = csv.writer(fo)
for n in range(self.listBox.topLevelItemCount()):
if item := self.listBox.topLevelItem(n):
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
writer.writerow([entry.shape.name, entry.color.name(), entry.name])
except Exception as exc:
SHARED.error("Could not write file.", exc=exc)
return
## ##
# Internal Functions # Internal Functions
## ##