diff --git a/manuskript/loadSave.py b/manuskript/loadSave.py index 76573768..1adfe4ce 100644 --- a/manuskript/loadSave.py +++ b/manuskript/loadSave.py @@ -63,6 +63,6 @@ def loadProject(project): LOGGER.info("Detected file format version: {}. Zip: {}.".format(version, isZip)) if version == 0: - v0.loadProject(project) + return v0.loadProject(project) else: - v1.loadProject(project, zip=isZip) + return v1.loadProject(project, zip=isZip) diff --git a/manuskript/load_save/version_1.py b/manuskript/load_save/version_1.py index e78ecabe..b2ad66c7 100644 --- a/manuskript/load_save/version_1.py +++ b/manuskript/load_save/version_1.py @@ -15,6 +15,7 @@ from collections import OrderedDict from PyQt5.QtCore import Qt, QModelIndex from PyQt5.QtGui import QColor, QStandardItem +from PyQt5.QtWidgets import QListWidgetItem from manuskript import settings from manuskript.enums import Character, World, Plot, PlotStep, Outline @@ -25,6 +26,7 @@ from lxml import etree as ET from manuskript.load_save.version_0 import loadFilesFromZip from manuskript.models.characterModel import CharacterInfo from manuskript.models import outlineItem +from manuskript.ui.listDialog import ListDialog import logging LOGGER = logging.getLogger(__name__) @@ -327,8 +329,8 @@ def saveProject(zip=None): # Save to plain text else: - global cache + filesWithPermissionErrors = list() # Project path dir = os.path.dirname(project) @@ -378,11 +380,19 @@ def saveProject(zip=None): LOGGER.debug("* Writing file {} ({})".format(path, "not in cache" if path not in cache else "different")) # mode = "w" + ("b" if type(content) == bytes else "") if type(content) == bytes: - with open(filename, "wb") as f: - f.write(content) + try: + with open(filename, "wb") as f: + f.write(content) + except PermissionError as e: + LOGGER.error("Cannot open file " + filename + " for writing: " + e.strerror) + filesWithPermissionErrors.append(filename) else: - with open(filename, "w", encoding='utf8') as f: - f.write(content) + try: + with open(filename, "w", encoding='utf8') as f: + f.write(content) + except PermissionError as e: + LOGGER.error("Cannot open file " + filename + " for writing: " + e.strerror) + filesWithPermissionErrors.append(filename) cache[path] = content @@ -412,9 +422,24 @@ def saveProject(zip=None): pass # Write the project file's content - with open(project, "w", encoding='utf8') as f: - f.write("1") # Format number + try: + with open(project, "w", encoding='utf8') as f: + f.write("1") # Format number + except PermissionError as e: + LOGGER.error("Cannot open file " + project + " for writing: " + e.strerror) + filesWithPermissionErrors.append(project) + if len(filesWithPermissionErrors) > 0: + dlg = ListDialog(mw) + dlg.setModal(True) + dlg.setWindowTitle(dlg.tr("Files not saved")) + dlg.label.setText(dlg.tr("The following files were not saved and appear to be open in another program")) + for f in filesWithPermissionErrors: + QListWidgetItem(f, dlg.listWidget) + dlg.open() + + if project in filesWithPermissionErrors: + return False return True @@ -622,7 +647,8 @@ def loadProject(project, zip=None): """ mw = mainWindow() - errors = [] + errors = list() + filesWithPermissionErrors = list() #################################################################################################################### # Read and store everything in a dict @@ -661,8 +687,14 @@ def loadProject(project, zip=None): with open(os.path.join(dirpath, f), "rb") as fo: files[os.path.join(p, f)] = fo.read() else: - with open(os.path.join(dirpath, f), "r", encoding="utf8") as fo: - files[os.path.join(p, f)] = fo.read() + try: + filename = os.path.join(dirpath, f) + with open(filename, "r", encoding="utf8") as fo: + files[os.path.join(p, f)] = fo.read() + except PermissionError as e: + LOGGER.error("Cannot open file " + filename + ": " + e.strerror) + errors.append(fo) + filesWithPermissionErrors.append(filename) # Saves to cache (only if we loaded from disk and not zip) global cache @@ -887,6 +919,15 @@ def loadProject(project, zip=None): # Check IDS mdl.rootItem.checkIDs() + if len(filesWithPermissionErrors) > 0: + dlg = ListDialog(mw) + dlg.setModal(True) + dlg.setWindowTitle(dlg.tr("Files not loaded")) + dlg.label.setText(dlg.tr("The following files were not loaded and appear to be open in another program")) + for f in filesWithPermissionErrors: + QListWidgetItem(f, dlg.listWidget) + dlg.open() + return errors diff --git a/manuskript/ui/listDialog.py b/manuskript/ui/listDialog.py new file mode 100644 index 00000000..e3941da0 --- /dev/null +++ b/manuskript/ui/listDialog.py @@ -0,0 +1,16 @@ +from PyQt5.QtWidgets import QDialog +from manuskript.ui.listDialog_ui import Ui_GenericListDialog + + +class ListDialog(QDialog, Ui_GenericListDialog): + def __init__(self, parent=None): + QDialog.__init__(self, parent) + self.setupUi(self) + + def accept(self): + self.hide() + self.close() + + def reject(self): + self.hide() + self.close() diff --git a/manuskript/ui/listDialog_ui.py b/manuskript/ui/listDialog_ui.py new file mode 100644 index 00000000..17620be1 --- /dev/null +++ b/manuskript/ui/listDialog_ui.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'listDialog_ui.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_GenericListDialog(object): + def setupUi(self, GenericListDialog): + GenericListDialog.setObjectName("GenericListDialog") + GenericListDialog.resize(451, 340) + GenericListDialog.setModal(False) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(GenericListDialog) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(GenericListDialog) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.listWidget = QtWidgets.QListWidget(GenericListDialog) + self.listWidget.setObjectName("listWidget") + self.verticalLayout.addWidget(self.listWidget) + self.verticalLayout_2.addLayout(self.verticalLayout) + self.buttonBox = QtWidgets.QDialogButtonBox(GenericListDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_2.addWidget(self.buttonBox) + + self.retranslateUi(GenericListDialog) + self.buttonBox.accepted.connect(GenericListDialog.accept) + self.buttonBox.rejected.connect(GenericListDialog.reject) + QtCore.QMetaObject.connectSlotsByName(GenericListDialog) + + def retranslateUi(self, GenericListDialog): + _translate = QtCore.QCoreApplication.translate + GenericListDialog.setWindowTitle(_translate("GenericListDialog", "Title")) + self.label.setText(_translate("GenericListDialog", "Text")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + GenericListDialog = QtWidgets.QDialog() + ui = Ui_GenericListDialog() + ui.setupUi(GenericListDialog) + GenericListDialog.show() + sys.exit(app.exec_()) diff --git a/manuskript/ui/listDialog_ui.ui b/manuskript/ui/listDialog_ui.ui new file mode 100644 index 00000000..b41a2575 --- /dev/null +++ b/manuskript/ui/listDialog_ui.ui @@ -0,0 +1,81 @@ + + + GenericListDialog + + + + 0 + 0 + 451 + 340 + + + + Title + + + false + + + + + + + + Text + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + GenericListDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + GenericListDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +