Source code for editortools.operation

#-# Modified by D.C.-G. for translation purpose
import atexit
import os
import shutil
import tempfile
import albow
from albow.translate import _
from pymclevel import BoundingBox
import numpy
from albow.root import Cancel
import pymclevel
from albow import showProgress
from pymclevel.mclevelbase import exhaust

undo_folder = os.path.join(tempfile.gettempdir(), "mcedit_undo", str(os.getpid()))


[docs]def mkundotemp(): if not os.path.exists(undo_folder): os.makedirs(undo_folder) return tempfile.mkdtemp("mceditundo", dir=undo_folder)
atexit.register(shutil.rmtree, undo_folder, True)
[docs]class Operation(object): changedLevel = True undoLevel = None redoLevel = None def __init__(self, editor, level): self.editor = editor self.level = level
[docs] def extractUndo(self, level, box): if isinstance(level, pymclevel.MCInfdevOldLevel): return self.extractUndoChunks(level, box.chunkPositions, box.chunkCount) else: return self.extractUndoSchematic(level, box)
[docs] def extractUndoChunks(self, level, chunks, chunkCount=None): if not isinstance(level, pymclevel.MCInfdevOldLevel): chunks = numpy.array(list(chunks)) mincx, mincz = numpy.min(chunks, 0) maxcx, maxcz = numpy.max(chunks, 0) box = BoundingBox((mincx << 4, 0, mincz << 4), (maxcx << 4, level.Height, maxcz << 4)) return self.extractUndoSchematic(level, box) undoLevel = pymclevel.MCInfdevOldLevel(mkundotemp(), create=True) if not chunkCount: try: chunkCount = len(chunks) except TypeError: chunkCount = -1 def _extractUndo(): yield 0, 0, "Recording undo..." for i, (cx, cz) in enumerate(chunks): undoLevel.copyChunkFrom(level, cx, cz) yield i, chunkCount, _("Copying chunk %s...") % ((cx, cz),) undoLevel.saveInPlace() if chunkCount > 25 or chunkCount < 1: if "Canceled" == showProgress("Recording undo...", _extractUndo(), cancel=True): if albow.ask("Continue with undo disabled?", ["Continue", "Cancel"]) == "Cancel": raise Cancel else: return None else: exhaust(_extractUndo()) return undoLevel
@staticmethod
[docs] def extractUndoSchematic(level, box): if box.volume > 131072: sch = showProgress("Recording undo...", level.extractZipSchematicIter(box), cancel=True) else: sch = level.extractZipSchematic(box) if sch == "Cancel": raise Cancel if sch: sch.sourcePoint = box.origin return sch # represents a single undoable operation
[docs] def perform(self, recordUndo=True): " Perform the operation. Record undo information if recordUndo"
[docs] def undo(self): """ Undo the operation. Ought to leave the Operation in a state where it can be performed again. Default implementation copies all chunks in undoLevel back into level. Non-chunk-based operations should override this.""" if self.undoLevel: self.redoLevel = self.extractUndo(self.level, self.dirtyBox()) def _undo(): yield 0, 0, "Undoing..." if hasattr(self.level, 'copyChunkFrom'): for i, (cx, cz) in enumerate(self.undoLevel.allChunks): self.level.copyChunkFrom(self.undoLevel, cx, cz) yield i, self.undoLevel.chunkCount, "Copying chunk %s..." % ((cx, cz),) else: for i in self.level.copyBlocksFromIter(self.undoLevel, self.undoLevel.bounds, self.undoLevel.sourcePoint, biomes=True): yield i, self.undoLevel.chunkCount, "Copying..." if self.undoLevel.chunkCount > 25: showProgress("Undoing...", _undo()) else: exhaust(_undo()) self.editor.invalidateChunks(self.undoLevel.allChunks)
[docs] def redo(self): if self.redoLevel: def _redo(): yield 0, 0, "Redoing..." if hasattr(self.level, 'copyChunkFrom'): for i, (cx, cz) in enumerate(self.redoLevel.allChunks): self.level.copyChunkFrom(self.redoLevel, cx, cz) yield i, self.redoLevel.chunkCount, "Copying chunk %s..." % ((cx, cz),) else: for i in self.level.copyBlocksFromIter(self.redoLevel, self.redoLevel.bounds, self.redoLevel.sourcePoint, biomes=True): yield i, self.undoLevel.chunkCount, "Copying..." if self.redoLevel.chunkCount > 25: showProgress("Redoing...", _redo()) else: exhaust(_redo())
[docs] def dirtyBox(self): """ The region modified by the operation. Return None to indicate no blocks were changed. """ return None