Esempio n. 1
0
    def deleteItem(self, tHandle=None, alreadyAsked=False, askForTrash=False):
        """Delete an item from the project tree. As a first step, files are
        moved to the Trash folder. Permanent deletion is a second step. This
        second step also deletes the item from the project object as well as
        delete the files on disk. Folders are deleted if they're empty only,
        and the deletion is always permanent.
        """
        if not self.theParent.hasProject:
            logger.error("No project open")
            return False

        if tHandle is None:
            tHandle = self.getSelectedHandle()

        if tHandle is None:
            return False

        trItemS = self._getTreeItem(tHandle)
        nwItemS = self.theProject.projTree[tHandle]

        if trItemS is None or nwItemS is None:
            return False

        wCount = int(trItemS.data(self.C_COUNT, Qt.UserRole))
        if nwItemS.itemType == nwItemType.FILE:
            logger.debug("User requested file %s moved to trash" % tHandle)
            trItemP = trItemS.parent()
            trItemT = self._addTrashRoot()
            if trItemP is None or trItemT is None:
                logger.error("Could not delete item")
                return False

            pHandle = nwItemS.itemParent
            if self.theProject.projTree.isTrashRoot(pHandle):
                # If the file is in the trash folder already, as the
                # user if they want to permanently delete the file.
                doPermanent = False
                if not alreadyAsked:
                    msgYes = self.theParent.askQuestion(
                        "Delete File", "Permanently delete file '%s'?" % nwItemS.itemName
                    )
                    if msgYes:
                        doPermanent = True
                else:
                    doPermanent = True

                if doPermanent:
                    logger.debug("Permanently deleting file with handle %s" % tHandle)

                    self.propagateCount(tHandle, 0)
                    tIndex = trItemP.indexOfChild(trItemS)
                    trItemC = trItemP.takeChild(tIndex)

                    if self.theParent.docEditor.theHandle == tHandle:
                        self.theParent.closeDocument()

                    theDoc = NWDoc(self.theProject, self.theParent)
                    theDoc.deleteDocument(tHandle)
                    del self.theProject.projTree[tHandle]
                    self.theIndex.deleteHandle(tHandle)

            else:
                # The file is not already in the trash folder, so we
                # move it there.
                doTrash = False
                if askForTrash:
                    msgYes = self.theParent.askQuestion(
                        "Delete File", "Move file '%s' to Trash?" % nwItemS.itemName
                    )
                    if msgYes:
                        doTrash = True
                else:
                    doTrash = True

                if doTrash:
                    if pHandle is None:
                        logger.warning("File has no parent item")

                    self.propagateCount(tHandle, 0)
                    tIndex  = trItemP.indexOfChild(trItemS)
                    trItemC = trItemP.takeChild(tIndex)
                    trItemT.addChild(trItemC)
                    nwItemS.setParent(self.theProject.projTree.trashRoot())
                    self.propagateCount(tHandle, wCount)

                    self._setTreeChanged(True)
                    self.theIndex.deleteHandle(tHandle)

        elif nwItemS.itemType == nwItemType.FOLDER:
            logger.debug("User requested folder %s deleted" % tHandle)
            trItemP = trItemS.parent()
            if trItemP is None:
                logger.error("Could not delete folder")
                return False
            tIndex = trItemP.indexOfChild(trItemS)
            if trItemS.childCount() == 0:
                trItemP.takeChild(tIndex)
                del self.theProject.projTree[tHandle]
            else:
                self.makeAlert((
                    "Cannot delete folder. It is not empty. "
                    "Recursive deletion is not supported. "
                    "Please delete the content first."
                ), nwAlert.ERROR)
                return False

        elif nwItemS.itemType == nwItemType.ROOT:
            logger.debug("User requested root folder %s deleted" % tHandle)
            tIndex = self.indexOfTopLevelItem(trItemS)
            if trItemS.childCount() == 0:
                self.takeTopLevelItem(tIndex)
                del self.theProject.projTree[tHandle]
                self.theParent.mainMenu.setAvailableRoot()
                self._setTreeChanged(True)
            else:
                self.makeAlert((
                    "Cannot delete root folder. It is not empty. "
                    "Recursive deletion is not supported. "
                    "Please delete the content first."
                ), nwAlert.ERROR)
                return False

        return True
Esempio n. 2
0
def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
    """Test loading and saving a document with the NWDoc class.
    """
    theProject = NWProject(dummyGUI)
    assert theProject.openProject(nwMinimal)
    assert theProject.projPath == nwMinimal

    theDoc = NWDoc(theProject, dummyGUI)
    sHandle = "8c659a11cd429"

    # Not a valid handle
    assert theDoc.openDocument("dummy") is None

    # Non-existent handle
    assert theDoc.openDocument("0000000000000") is None

    # Cause open() to fail while loading
    def dummyOpen(*args, **kwargs):
        raise OSError

    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", dummyOpen)
        assert theDoc.openDocument(sHandle) is None

    # Load the text
    assert theDoc.openDocument(sHandle) == "### New Scene\n\n"

    # Try to open a new (non-existent) file
    nHandle = theProject.projTree.findRoot(nwItemClass.NOVEL)
    assert nHandle is not None
    xHandle = theProject.newFile("New File", nwItemClass.NOVEL, nHandle)
    assert theDoc.openDocument(xHandle) == ""

    # Check cached item
    assert isinstance(theDoc._theItem, NWItem)
    assert theDoc.openDocument(xHandle, isOrphan=True) == ""
    assert theDoc._theItem is None

    # Set handle and save again
    theText = "### Test File\n\nText ...\n\n"
    assert theDoc.openDocument(xHandle) == ""
    assert theDoc.saveDocument(theText)

    # Save again to ensure temp file and previous file is handled
    assert theDoc.saveDocument(theText)

    # Check file content
    docPath = os.path.join(nwMinimal, "content", xHandle + ".nwd")
    with open(docPath, mode="r", encoding="utf8") as inFile:
        assert inFile.read() == ("%%~name: New File\n"
                                 f"%%~path: a508bb932959c/{xHandle}\n"
                                 "%%~kind: NOVEL/SCENE\n"
                                 "### Test File\n\n"
                                 "Text ...\n\n")

    # Force no meta data
    theDoc._theItem = None
    assert theDoc.saveDocument(theText)

    with open(docPath, mode="r", encoding="utf8") as inFile:
        assert inFile.read() == theText

    # Cause open() to fail while saving
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert not theDoc.saveDocument(theText)

    # Saving with no handle
    theDoc.clearDocument()
    assert not theDoc.saveDocument(theText)

    # Delete the last document
    assert not theDoc.deleteDocument("dummy")
    assert os.path.isfile(docPath)

    # Cause the delete to fail
    with monkeypatch.context() as mp:
        mp.setattr("os.unlink", causeOSError)
        assert not theDoc.deleteDocument(xHandle)

    # Make the delete pass
    assert theDoc.deleteDocument(xHandle)
    assert not os.path.isfile(docPath)