Add import and export feature to word list
This commit is contained in:
@@ -26,12 +26,13 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QCloseEvent
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QDialog, QDialogButtonBox, QHBoxLayout, QLabel,
|
||||
QLineEdit, QListWidget, QListWidgetItem, QPushButton, QVBoxLayout, qApp
|
||||
QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog, QHBoxLayout,
|
||||
QLabel, QLineEdit, QListWidget, QPushButton, QVBoxLayout, qApp
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
@@ -57,30 +58,44 @@ class GuiWordList(QDialog):
|
||||
mS = CONFIG.pxInt(250)
|
||||
wW = CONFIG.pxInt(320)
|
||||
wH = CONFIG.pxInt(340)
|
||||
pOptions = SHARED.project.options
|
||||
options = SHARED.project.options
|
||||
|
||||
self.setMinimumWidth(mS)
|
||||
self.setMinimumHeight(mS)
|
||||
self.resize(
|
||||
CONFIG.pxInt(pOptions.getInt("GuiWordList", "winWidth", wW)),
|
||||
CONFIG.pxInt(pOptions.getInt("GuiWordList", "winHeight", wH))
|
||||
CONFIG.pxInt(options.getInt("GuiWordList", "winWidth", wW)),
|
||||
CONFIG.pxInt(options.getInt("GuiWordList", "winHeight", wH))
|
||||
)
|
||||
|
||||
# Main Widgets
|
||||
# ============
|
||||
|
||||
# Header
|
||||
self.headLabel = QLabel("<b>%s</b>" % self.tr("Project Word List"))
|
||||
|
||||
self.listBox = QListWidget()
|
||||
self.importButton = QPushButton(SHARED.theme.getIcon("add_document"), "", self)
|
||||
self.importButton.setToolTip(self.tr("Import words from text file"))
|
||||
self.importButton.clicked.connect(self._importWords)
|
||||
|
||||
self.exportButton = QPushButton(SHARED.theme.getIcon("export"), "", self)
|
||||
self.exportButton.setToolTip(self.tr("Export words to text file"))
|
||||
self.exportButton.clicked.connect(self._exportWords)
|
||||
|
||||
self.headerBox = QHBoxLayout()
|
||||
self.headerBox.addWidget(self.headLabel, 1)
|
||||
self.headerBox.addWidget(self.importButton, 0)
|
||||
self.headerBox.addWidget(self.exportButton, 0)
|
||||
|
||||
# List Box
|
||||
self.listBox = QListWidget(self)
|
||||
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||
self.listBox.setSortingEnabled(True)
|
||||
|
||||
# Add/Remove Form
|
||||
self.newEntry = QLineEdit(self)
|
||||
|
||||
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "")
|
||||
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "", self)
|
||||
self.addButton.clicked.connect(self._doAdd)
|
||||
|
||||
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "")
|
||||
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "", self)
|
||||
self.delButton.clicked.connect(self._doDelete)
|
||||
|
||||
self.editBox = QHBoxLayout()
|
||||
@@ -88,20 +103,19 @@ class GuiWordList(QDialog):
|
||||
self.editBox.addWidget(self.addButton, 0)
|
||||
self.editBox.addWidget(self.delButton, 0)
|
||||
|
||||
# Buttons
|
||||
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close)
|
||||
self.buttonBox.accepted.connect(self._doSave)
|
||||
self.buttonBox.rejected.connect(self.close)
|
||||
|
||||
# Assemble
|
||||
# ========
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(self.headLabel)
|
||||
self.outerBox.addSpacing(CONFIG.pxInt(8))
|
||||
self.outerBox.addLayout(self.headerBox, 0)
|
||||
self.outerBox.addWidget(self.listBox, 1)
|
||||
self.outerBox.addLayout(self.editBox, 0)
|
||||
self.outerBox.addSpacing(CONFIG.pxInt(12))
|
||||
self.outerBox.addWidget(self.buttonBox, 0)
|
||||
self.outerBox.setSpacing(CONFIG.pxInt(4))
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
@@ -134,45 +148,72 @@ class GuiWordList(QDialog):
|
||||
def _doAdd(self) -> None:
|
||||
"""Add a new word to the word list."""
|
||||
word = self.newEntry.text().strip()
|
||||
if word == "":
|
||||
SHARED.error(self.tr("Cannot add a blank word."))
|
||||
return
|
||||
|
||||
if self.listBox.findItems(word, Qt.MatchExactly):
|
||||
SHARED.error(self.tr(
|
||||
"The word '{0}' is already in the word list."
|
||||
).format(word))
|
||||
return
|
||||
|
||||
self.listBox.addItem(word)
|
||||
self.newEntry.setText("")
|
||||
|
||||
self.listBox.clearSelection()
|
||||
self._addWord(word)
|
||||
if items := self.listBox.findItems(word, Qt.MatchExactly):
|
||||
self.listBox.setCurrentItem(items[0])
|
||||
self.listBox.scrollToItem(items[0], QAbstractItemView.ScrollHint.PositionAtCenter)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _doDelete(self) -> None:
|
||||
"""Delete the selected item."""
|
||||
selItem = self.listBox.selectedItems()
|
||||
if selItem:
|
||||
self.listBox.takeItem(self.listBox.row(selItem[0]))
|
||||
"""Delete the selected items."""
|
||||
for item in self.listBox.selectedItems():
|
||||
self.listBox.takeItem(self.listBox.row(item))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _doSave(self) -> None:
|
||||
"""Save the new word list and close."""
|
||||
userDict = UserDictionary(SHARED.project)
|
||||
for i in range(self.listBox.count()):
|
||||
item = self.listBox.item(i)
|
||||
if isinstance(item, QListWidgetItem):
|
||||
word = item.text().strip()
|
||||
if word:
|
||||
userDict.add(word)
|
||||
for word in self._listWords():
|
||||
userDict.add(word)
|
||||
userDict.save()
|
||||
self.newWordListReady.emit()
|
||||
qApp.processEvents()
|
||||
self.close()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _importWords(self) -> None:
|
||||
"""Import words from file."""
|
||||
SHARED.info(self.tr(
|
||||
"Note: The import file must be a plain text file with UTF-8 or ASCII encoding."
|
||||
))
|
||||
extFilter = [
|
||||
"{0} (*.txt)".format(self.tr("Text files")),
|
||||
"{0} (*)".format(self.tr("All files")),
|
||||
]
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self, self.tr("Import File"), str(Path.home()), filter=";;".join(extFilter)
|
||||
)
|
||||
if path:
|
||||
try:
|
||||
with open(path, mode="r", encoding="utf-8") as fo:
|
||||
words = set(w.strip() for w in fo.read().split())
|
||||
except Exception as exc:
|
||||
SHARED.error("Could not read file.", exc=exc)
|
||||
return
|
||||
for word in words:
|
||||
self._addWord(word)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _exportWords(self) -> None:
|
||||
"""Export words to file."""
|
||||
path, _ = QFileDialog.getSaveFileName(
|
||||
self, self.tr("Export File"), str(Path.home())
|
||||
)
|
||||
if path:
|
||||
try:
|
||||
path = Path(path).with_suffix(".txt")
|
||||
with open(path, mode="w", encoding="utf-8") as fo:
|
||||
fo.write("\n".join(self._listWords()))
|
||||
except Exception as exc:
|
||||
SHARED.error("Could not write file.", exc=exc)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
@@ -183,8 +224,7 @@ class GuiWordList(QDialog):
|
||||
userDict.load()
|
||||
self.listBox.clear()
|
||||
for word in userDict:
|
||||
if word:
|
||||
self.listBox.addItem(word)
|
||||
self.listBox.addItem(word)
|
||||
return
|
||||
|
||||
def _saveGuiSettings(self) -> None:
|
||||
@@ -199,4 +239,19 @@ class GuiWordList(QDialog):
|
||||
|
||||
return
|
||||
|
||||
def _addWord(self, word: str) -> None:
|
||||
"""Add a single word to the list."""
|
||||
if word and not self.listBox.findItems(word, Qt.MatchExactly):
|
||||
self.listBox.addItem(word)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def _listWords(self) -> list[str]:
|
||||
"""List all words in the list box."""
|
||||
result = []
|
||||
for i in range(self.listBox.count()):
|
||||
if (item := self.listBox.item(i)) and (word := item.text().strip()):
|
||||
result.append(word)
|
||||
return result
|
||||
|
||||
# END Class GuiWordList
|
||||
|
||||
@@ -665,10 +665,10 @@ class GuiMain(QMainWindow):
|
||||
|
||||
lastPath = CONFIG.lastPath()
|
||||
extFilter = [
|
||||
self.tr("Text files ({0})").format("*.txt"),
|
||||
self.tr("Markdown files ({0})").format("*.md"),
|
||||
self.tr("novelWriter files ({0})").format("*.nwd"),
|
||||
self.tr("All files ({0})").format("*"),
|
||||
"{0} (*.txt)".format(self.tr("Text files")),
|
||||
"{0} (*.md)".format(self.tr("Markdown files")),
|
||||
"{0} (*.nwd)".format(self.tr("novelWriter files")),
|
||||
"{0} (*)".format(self.tr("All files")),
|
||||
]
|
||||
loadFile, _ = QFileDialog.getOpenFileName(
|
||||
self, self.tr("Import File"), str(lastPath), filter=";;".join(extFilter)
|
||||
|
||||
Reference in New Issue
Block a user