Removes deleted character's files when saving

This commit is contained in:
Olivier Keshavjee 2016-03-09 14:10:22 +01:00
parent 97903b2781
commit da5bfb8951
2 changed files with 97 additions and 35 deletions

View file

@ -66,6 +66,10 @@ def slugify(name):
return newName
def log(*args):
print(" ".join(str(a) for a in args))
def saveProject(zip=None):
"""
Saves the project. If zip is False, the project is saved as a multitude of plain-text files for the most parts
@ -80,12 +84,14 @@ def saveProject(zip=None):
zip = False
# Fixme
print("\n\n", "Saving to:", "zip" if zip else "folder")
log("\n\nSaving to:", "zip" if zip else "folder")
# List of files to be written
files = []
# List of files to be removed
removes = []
# List of files to be moved
moves = []
mw = mainWindow()
@ -117,6 +123,7 @@ def saveProject(zip=None):
)
files.append((path, content))
####################################################################################################################
# Summary
# In plain text, in summary.txt
@ -135,6 +142,7 @@ def saveProject(zip=None):
files.append((path, content))
####################################################################################################################
# Label & Status
# In plain text
@ -162,7 +170,8 @@ def saveProject(zip=None):
files.append((path, content))
# Characters (self.mdlCharacter)
####################################################################################################################
# Characters
# In a character folder
path = os.path.join("characters", "{name}.txt")
@ -179,7 +188,11 @@ def saveProject(zip=None):
(Character.notes, "Notes"),
]
mdl = mw.mdlCharacter
# Review characters
for c in mdl.characters:
# Generates file's content
content = ""
for m, name in _map:
val = mdl.data(c.index(m.value)).strip()
@ -189,28 +202,46 @@ def saveProject(zip=None):
for info in c.infos:
content += formatMetaData(info.description, info.value, 20)
# generate file's path
cpath = path.format(name="{ID}-{slugName}".format(
ID=c.ID(),
slugName=slugify(c.name())
))
# Has the character been renamed?
# If so, we remove the old file (if not zipped)
if c.lastPath and cpath != c.lastPath:
removes.append(c.lastPath)
c.lastPath = cpath
files.append((
cpath,
content))
# Has the character been renamed?
if c.lastPath and cpath != c.lastPath:
moves.append((c.lastPath, cpath))
# Update character's path
c.lastPath = cpath
files.append((cpath, content))
# List removed characters
for c in mdl.removed:
# generate file's path
cpath = path.format(name="{ID}-{slugName}".format(
ID=c.ID(),
slugName=slugify(c.name())
))
# Mark for removal
removes.append(cpath)
mdl.removed.clear()
####################################################################################################################
# Texts
# In an outline folder
mdl = mw.mdlOutline
f, r = exportOutlineItem(mdl.rootItem)
f, m, r = exportOutlineItem(mdl.rootItem)
files += f
moves += m
removes += r
# World (mw.mdlWorld)
####################################################################################################################
# World
# Either in an XML file, or in lots of plain texts?
# More probably text, since there might be writing done in third-party.
@ -224,6 +255,7 @@ def saveProject(zip=None):
content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
files.append((path, content))
####################################################################################################################
# Plots (mw.mdlPlots)
# Either in XML or lots of plain texts?
# More probably XML since there is not really a lot if writing to do (third-party)
@ -236,15 +268,19 @@ def saveProject(zip=None):
content = ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
files.append((path, content))
####################################################################################################################
# Settings
# Saved in readable text (json) for easier versionning. But they mustn't be shared, it seems.
# Maybe include them only if zipped?
# Well, for now, we keep them here...
files.append(("settings.txt", settings.save(protocol=0)))
project = mw.currentProject
####################################################################################################################
# Save to zip
if zip:
project = os.path.join(
os.path.dirname(project),
@ -258,41 +294,58 @@ def saveProject(zip=None):
zf.close()
####################################################################################################################
# Save to plain text
else:
# Project path
dir = os.path.dirname(project)
# Folder containing file: name of the project file (without .msk extension)
folder = os.path.splitext(os.path.basename(project))[0]
print("\nSaving to folder", folder)
# Debug
log("\nSaving to folder", folder)
# Moving files that have been renamed
for old, new in moves:
# Get full path
oldPath = os.path.join(dir, folder, old)
newPath = os.path.join(dir, folder, new)
# Move the old file to the new place
os.replace(oldPath, newPath)
log("* Renaming {} to {}".format(old, new))
# Update cache
if old in cache:
cache[new] = cache.pop(old)
for path in removes:
if path not in [p for p,c in files]:
filename = os.path.join(dir, folder, path)
print("* Removing", filename)
log("* Removing", path)
if os.path.isdir(filename):
shutil.rmtree(filename)
# FIXME: when deleting a folder, there are still files in "removes".
# FIXME: if user copied custom files in the directory, they will be lost.
# need to find a way to rename instead of remove.
# FIXME: items removed have to be removed (not just the renamed)
else: # elif os.path.exists(filename)
os.remove(filename)
# Clear cache
cache.pop(path, 0)
for path, content in files:
filename = os.path.join(dir, folder, path)
os.makedirs(os.path.dirname(filename), exist_ok=True)
# print("* Saving file", filename)
# TODO: the first time it saves, it will overwrite everything, since it's not yet in cache.
# Or we have to cache while loading.
if not path in cache or cache[path] != content:
print("* Saving file", filename)
print(" Not in cache or changed: we write")
log("* Writing file", path)
mode = "w"+ ("b" if type(content) == bytes else "")
with open(filename, mode) as f:
f.write(content)
@ -300,7 +353,7 @@ def saveProject(zip=None):
else:
pass
# print(" In cache, and identical. Do nothing.")
# log(" In cache, and identical. Do nothing.")
def addWorldItem(root, mdl, parent=QModelIndex()):
@ -393,6 +446,7 @@ def exportOutlineItem(root):
"""
Takes an outline item, and returns two lists:
1. of (`filename`, `content`), representing the whole tree of files to be written, in multimarkdown.
3. of (`filename`, `filename`) listing files to be moved
2. of `filename`, representing files to be removed.
@param root: OutlineItem
@ -400,6 +454,7 @@ def exportOutlineItem(root):
"""
files = []
moves = []
removes = []
path = "outline"
@ -410,16 +465,15 @@ def exportOutlineItem(root):
k += 1
# Has the item been renamed?
# If so, we mark the old file for removal
if "Herod_dies" in spath:
print(child.title(), spath, "<==", child.lastPath)
if child.lastPath and spath != child.lastPath:
removes.append(child.lastPath)
print(child.title(), "has been renamed (", child.lastPath, "", spath, ")")
print(" → We remove:", child.lastPath)
moves.append((child.lastPath, spath))
log(child.title(), "has been renamed (", child.lastPath, "", spath, ")")
log(" → We mark for moving:", child.lastPath)
# Updates item last's path
child.lastPath = spath
# Generating content
if child.type() == "folder":
fpath = os.path.join(spath, "folder.txt")
content = outlineToMMD(child)
@ -431,16 +485,18 @@ def exportOutlineItem(root):
elif child.type() in ["html"]:
# FIXME: Convert first
pass
content = outlineToMMD(child)
files.append((spath, content))
else:
print("Unknown type")
log("Unknown type")
f, r = exportOutlineItem(child)
f, m, r = exportOutlineItem(child)
files += f
moves += m
removes += r
return files, removes
return files, moves, removes
def outlineItemPath(item):
# Root item
@ -472,7 +528,7 @@ def outlineToMMD(item):
content += item.data(Outline.text.value)
# Saving revisions
# TODO
# TODO: saving revisions?
# rev = item.revisions()
# for r in rev:
# revItem = ET.Element("revision")

View file

@ -12,7 +12,11 @@ class characterModel(QAbstractItemModel):
def __init__(self, parent):
QAbstractItemModel.__init__(self, parent)
# CharacterItems are stored in this list
self.characters = []
# We keep track of removed character, so that when we save in multiple files, we can remove old character's
# files.
self.removed = []
###############################################################################
# QAbstractItemModel subclassed
@ -170,7 +174,9 @@ class characterModel(QAbstractItemModel):
"""
c = self.getCharacterByID(ID)
self.beginRemoveRows(QModelIndex(), self.characters.index(c), self.characters.index(c))
self.removed.append(c)
self.characters.remove(c)
self.endRemoveRows()
###############################################################################
# CHARACTER INFOS