diff --git a/src/mcedit2/editorcommands/find_replace.py b/src/mcedit2/editorcommands/find_replace.py
index 2a2dd1f..ab99b44 100644
--- a/src/mcedit2/editorcommands/find_replace.py
+++ b/src/mcedit2/editorcommands/find_replace.py
@@ -13,10 +13,11 @@ from mcedit2.util.resources import resourcePath
from mcedit2.util.showprogress import showProgress
from mcedit2.widgets.blockpicker import BlockTypeButton
from mcedit2.widgets.layout import Row, Column
+from mceditlib.selection import BoundingBox
log = logging.getLogger(__name__)
-class NBTResultsEntry(namedtuple("NBTResultsEntry", "displayName location value resultType")):
+class NBTResultsEntry(namedtuple("NBTResultsEntry", "tagName value id path position uuid resultType")):
EntityResult = "ENTITY"
TileEntityResult = "TILE_ENTITY"
ItemResult = "ITEM"
@@ -75,14 +76,16 @@ class NBTResultsModel(QtCore.QAbstractItemModel):
if role in (Qt.DisplayRole, Qt.EditRole):
column = index.column()
if column == 0:
- return entry.displayName
+ return entry.tagName
elif column == 1:
return entry.value
elif column == 2:
+ path = "/".join(str(p) for p in entry.path)
+
if entry.resultType == entry.EntityResult:
- return "%s@%s/%s (%s)" % entry.location
+ return "%s@%s/%s (%s)" % (entry.id, entry.position, path, entry.uuid)
elif entry.resultType == entry.TileEntityResult:
- return "%s@%s/%s" % entry.location[:3]
+ return "%s@%s/%s" % (entry.id, entry.position, path)
else:
return ""
# value = entry.value
@@ -100,6 +103,11 @@ class NBTResultsModel(QtCore.QAbstractItemModel):
self.results.extend(results)
self.endInsertRows()
+ def clear(self):
+ size = len(self.results)
+ self.beginRemoveRows(QtCore.QModelIndex(), 0, size - 1)
+ self.results[:] = []
+ self.endRemoveRows()
# def setData(self, index, value, role=Qt.EditRole):
# row = index.row()
@@ -214,15 +222,34 @@ class FindReplaceBlocks(QtCore.QObject):
self.editorSession.pushCommand(command)
nbtReplaceSettings = settings.Settings().getNamespace("findreplace/nbt")
-nbtReplaceSettings.nameField = nbtReplaceSettings.getOption("nameField", unicode)
-nbtReplaceSettings.valueField = nbtReplaceSettings.getOption("valueField", unicode)
+nbtReplaceSettings.nameField = nbtReplaceSettings.getOption("nameField", unicode, "")
+nbtReplaceSettings.valueField = nbtReplaceSettings.getOption("valueField", unicode, "")
-nbtReplaceSettings.entityIDField = nbtReplaceSettings.getOption("entityIDField", unicode)
-nbtReplaceSettings.searchEntitiesChecked = nbtReplaceSettings.getOption("searchEntitiesChecked", bool)
+nbtReplaceSettings.entityIDField = nbtReplaceSettings.getOption("entityIDField", unicode, "")
+nbtReplaceSettings.searchEntitiesChecked = nbtReplaceSettings.getOption("searchEntitiesChecked", bool, False)
-nbtReplaceSettings.tileEntityIDField = nbtReplaceSettings.getOption("tileEntityIDField", unicode)
-nbtReplaceSettings.searchTileEntitiesChecked = nbtReplaceSettings.getOption("searchTileEntitiesChecked", bool)
+nbtReplaceSettings.tileEntityIDField = nbtReplaceSettings.getOption("tileEntityIDField", unicode, "")
+nbtReplaceSettings.searchTileEntitiesChecked = nbtReplaceSettings.getOption("searchTileEntitiesChecked", bool, False)
+nbtReplaceSettings.replaceNameField = nbtReplaceSettings.getOption("replaceNameField", unicode, "")
+nbtReplaceSettings.replaceValueField = nbtReplaceSettings.getOption("replaceValueField", unicode, "")
+nbtReplaceSettings.replaceValueTagType = nbtReplaceSettings.getOption("replaceValueTagType", int, 0)
+
+class ReplaceValueTagType(object):
+ """
+ duplicated from find_replace_nbt.ui
+ """
+ EXISTING = 0
+ STRING = 1
+ BYTE = 2
+ SHORT = 3
+ INT = 4
+ LONG = 5
+ FLOAT = 6
+ DOUBLE = 7
+
+class NBTReplaceCommand(SimpleRevisionCommand):
+ pass
class FindReplaceNBT(QtCore.QObject):
def __init__(self, editorSession, dialog):
@@ -231,24 +258,29 @@ class FindReplaceNBT(QtCore.QObject):
self.widget = load_ui("find_replace_nbt.ui")
self.dialog = dialog
- self.resultsWidgetContents = load_ui("find_replace_nbt_results.ui")
- self.resultsWidget = QtGui.QDockWidget("NBT Search", objectName="nbtSearch")
- self.resultsWidget.setWidget(self.resultsWidgetContents)
- self.resultsWidget.hide()
+ self.resultsWidget = load_ui("find_replace_nbt_results.ui")
+ self.resultsDockWidget = QtGui.QDockWidget("NBT Search", objectName="nbtSearch")
+ self.resultsDockWidget.setWidget(self.resultsWidget)
+ self.resultsDockWidget.hide()
self.resultsModel = NBTResultsModel()
- self.resultsWidgetContents.resultsView.setModel(self.resultsModel)
+ self.resultsWidget.resultsView.setModel(self.resultsModel)
+ # --- Buttons ---
self.widget.findButton.clicked.connect(self.find)
- self.resultsWidgetContents.stopButton.clicked.connect(self.stop)
- self.resultsWidgetContents.findAgainButton.clicked.connect(dialog.exec_)
+ self.resultsWidget.stopButton.clicked.connect(self.stop)
+ self.resultsWidget.findAgainButton.clicked.connect(dialog.exec_)
+
+ self.resultsWidget.replaceSelectedButton.clicked.connect(self.replaceSelected)
+ self.resultsWidget.replaceAllButton.clicked.connect(self.replaceAll)
self.widget.searchNameCheckbox.toggled.connect(self.searchForToggled)
self.widget.searchValueCheckbox.toggled.connect(self.searchForToggled)
self.findTimer = None
self.finder = None
+ # --- Search for... ---
self.widget.nameField.setText(nbtReplaceSettings.nameField.value(""))
self.widget.searchNameCheckbox.setChecked(len(self.widget.nameField.text()) > 0)
self.widget.nameField.textChanged.connect(self.nameFieldChanged)
@@ -257,18 +289,37 @@ class FindReplaceNBT(QtCore.QObject):
self.widget.searchValueCheckbox.setChecked(len(self.widget.valueField.text()) > 0)
self.widget.valueField.textChanged.connect(self.valueFieldChanged)
- self.widget.searchEntitiesCheckbox.setChecked(nbtReplaceSettings.searchEntitiesChecked.value(False))
+ # --- Search in... ---
+ self.widget.searchEntitiesCheckbox.setChecked(nbtReplaceSettings.searchEntitiesChecked.value())
self.widget.searchEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchEntitiesChecked.setValue)
- self.widget.entityIDField.setText(nbtReplaceSettings.entityIDField.value(""))
+ self.widget.entityIDField.setText(nbtReplaceSettings.entityIDField.value())
self.widget.entityIDField.textChanged.connect(self.entityIDFieldChanged)
- self.widget.searchTileEntitiesCheckbox.setChecked(nbtReplaceSettings.searchTileEntitiesChecked.value(False))
+ self.widget.searchTileEntitiesCheckbox.setChecked(nbtReplaceSettings.searchTileEntitiesChecked.value())
self.widget.searchTileEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchTileEntitiesChecked.setValue)
- self.widget.tileEntityIDField.setText(nbtReplaceSettings.tileEntityIDField.value(""))
+ self.widget.tileEntityIDField.setText(nbtReplaceSettings.tileEntityIDField.value())
self.widget.tileEntityIDField.textChanged.connect(self.tileEntityIDFieldChanged)
+ # --- Replace with... ---
+ self.widget.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value())
+ self.resultsWidget.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value())
+ self.widget.replaceNameField.textChanged.connect(self.replaceNameFieldChanged)
+
+ self.widget.replaceNameCheckbox.setChecked(len(self.widget.replaceNameField.text()))
+ self.resultsWidget.replaceNameCheckbox.setChecked(len(self.widget.replaceNameField.text()))
+
+ self.widget.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value())
+ self.resultsWidget.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value())
+ self.widget.replaceValueField.textChanged.connect(self.replaceValueFieldChanged)
+
+ self.widget.replaceValueCheckbox.setChecked(len(self.widget.replaceValueField.text()))
+ self.resultsWidget.replaceValueCheckbox.setChecked(len(self.widget.replaceValueField.text()))
+
+ self.widget.replaceValueTagTypeComboBox.setCurrentIndex(nbtReplaceSettings.replaceValueTagType.value())
+ self.widget.replaceValueTagTypeComboBox.currentIndexChanged[int].connect(self.valueTagTypeChanged)
+
def dialogOpened(self):
currentSelection = self.editorSession.currentSelection
self.widget.inSelectionCheckbox.setChecked(currentSelection is not None and currentSelection.volume > 0)
@@ -295,6 +346,29 @@ class FindReplaceNBT(QtCore.QObject):
if len(value):
self.widget.searchTileEntitiesCheckbox.setChecked(True)
+ def replaceNameFieldChanged(self, value):
+ if value != nbtReplaceSettings.replaceNameField.value():
+ nbtReplaceSettings.replaceNameField.setValue(value)
+
+ self.widget.replaceNameCheckbox.setChecked(len(value) > 0)
+ self.widget.replaceNameField.setText(value)
+
+ self.resultsWidget.replaceNameCheckbox.setChecked(len(value) > 0)
+ self.resultsWidget.replaceNameField.setText(value)
+
+ def replaceValueFieldChanged(self, value):
+ if value != nbtReplaceSettings.replaceValueField.value():
+ nbtReplaceSettings.replaceValueField.setValue(value)
+
+ self.widget.replaceValueCheckbox.setChecked(len(value) > 0)
+ self.widget.replaceValueField.setText(value)
+
+ self.resultsWidget.replaceValueCheckbox.setChecked(len(value) > 0)
+ self.resultsWidget.replaceValueField.setText(value)
+
+ def valueTagTypeChanged(self, index):
+ nbtReplaceSettings.replaceValueTagType.setValue(index)
+
def find(self):
searchNames = self.widget.searchNameCheckbox.isChecked()
targetName = self.widget.nameField.text()
@@ -360,9 +434,15 @@ class FindReplaceNBT(QtCore.QObject):
result = _findTag(name, subtag, path)
if result:
name, path, value = result
- location = entity.id, entity.Position, path, uuid
- results.append(NBTResultsEntry(name, location, value, NBTResultsEntry.EntityResult))
+ results.append(NBTResultsEntry(tagName=name,
+ value=value,
+ id=entity.id,
+ path=path,
+ position=entity.Position,
+ uuid=uuid,
+ resultType=NBTResultsEntry.EntityResult))
+
self.resultsModel.addResults(results)
@@ -379,18 +459,24 @@ class FindReplaceNBT(QtCore.QObject):
result = _findTag(name, subtag, path)
if result:
name, path, value = result
- location = tileEntity.id, tileEntity.Position, path, None
- results.append(NBTResultsEntry(name, location, value, NBTResultsEntry.TileEntityResult))
+ results.append(NBTResultsEntry(tagName=name,
+ value=value,
+ id=tileEntity.id,
+ path=path,
+ position=tileEntity.Position,
+ uuid=None,
+ resultType=NBTResultsEntry.TileEntityResult))
self.resultsModel.addResults(results)
def _find():
- self.resultsWidget.show()
+ self.resultsDockWidget.show()
+ self.resultsModel.clear()
self.dialog.accept()
- self.resultsWidgetContents.findAgainButton.setEnabled(False)
+ self.resultsWidget.findAgainButton.setEnabled(False)
- self.resultsWidgetContents.progressBar.setMaximum(selection.chunkCount-1)
+ self.resultsWidget.progressBar.setMaximum(selection.chunkCount-1)
for i, cPos in enumerate(selection.chunkPositions()):
if dim.containsChunk(*cPos):
chunk = dim.getChunk(*cPos)
@@ -400,7 +486,7 @@ class FindReplaceNBT(QtCore.QObject):
_findTileEntitiesInChunk(chunk)
yield
- self.resultsWidgetContents.progressBar.setValue(i)
+ self.resultsWidget.progressBar.setValue(i)
self.stop()
@@ -414,26 +500,76 @@ class FindReplaceNBT(QtCore.QObject):
self.findTimer = QtCore.QTimer(timeout=find, interval=1.0)
self.findTimer.start()
- self.resultsWidgetContents.stopButton.setEnabled(True)
+ self.resultsWidget.stopButton.setEnabled(True)
def stop(self):
if self.findTimer:
self.findTimer.stop()
self.widget.findButton.setEnabled(True)
- self.resultsWidgetContents.stopButton.setEnabled(False)
- self.resultsWidgetContents.findAgainButton.setEnabled(True)
+ self.resultsWidget.stopButton.setEnabled(False)
+ self.resultsWidget.findAgainButton.setEnabled(True)
+ def replaceEntries(self, entries):
+ shouldReplaceName = self.widget.replaceNameCheckbox.isChecked()
+ newName = self.widget.replaceNameField.text()
+ shouldReplaceValue = self.widget.replaceValueCheckbox.isChecked()
+ newValue = self.widget.replaceValueField.text()
+ # newTagType = self.widget.replaceTagTypeComboBox.currentIndex()
-def walkNBT(tag, path=""):
+ def _replaceInTag(result, tag):
+ for component in result.path:
+ tag = tag[component]
+
+ if shouldReplaceName:
+ subtag = tag.pop(result.tagName)
+ tag[newName] = subtag
+
+ if shouldReplaceValue:
+ subtag = tag[result.tagName]
+ # xxx newTagType
+ subtag.value = newValue
+
+ def _replace():
+ for result in entries:
+ if result.resultType == result.TileEntityResult:
+ tileEntity = self.editorSession.currentDimension.getTileEntity(result.position)
+ tag = tileEntity.raw_tag()
+ _replaceInTag(result, tag)
+
+ if result.resultType == result.EntityResult:
+ box = BoundingBox(result.position, (1, 1, 1)).chunkBox(self.editorSession.currentDimension)
+ entity = self.editorSession.currentDimension.getEntities(box, UUID=result.uuid)
+ tag = entity.raw_tag()
+ _replaceInTag(result, tag)
+
+ # if result.resultType == result.ItemResult: # xxx
+ yield
+
+ command = NBTReplaceCommand(self.editorSession, "Replace NBT data") # xxx replace details
+ with command.begin():
+ replacer = _replace()
+ showProgress("Replacing NBT data...", replacer)
+
+ self.editorSession.pushCommand(command)
+
+ def replaceAll(self):
+ self.replaceEntries(self.resultsModel.results)
+
+ def replaceSelected(self):
+ pass
+
+def walkNBT(tag, path=None):
+ if path is None:
+ path = []
if tag.isCompound():
for name, subtag in tag.iteritems():
yield (name, subtag, path)
- walkNBT(subtag, path + "/" + name)
+ walkNBT(subtag, path + [name])
if tag.isList():
for i, subtag in enumerate(tag):
yield (i, subtag, path)
- walkNBT(subtag, path + "/" + str(i))
+ walkNBT(subtag, path + [i])
class FindReplaceDialog(QtGui.QDialog):
@@ -449,8 +585,8 @@ class FindReplaceDialog(QtGui.QDialog):
self.nbtTab.setLayout(Column(self.findReplaceNBT.widget, margin=0))
self.resultsWidgets = [
- # self.findReplaceBlocks.resultsWidget,
- self.findReplaceNBT.resultsWidget,
+ # self.findReplaceBlocks.resultsDockWidget,
+ self.findReplaceNBT.resultsDockWidget,
]
self.adjustSize()
diff --git a/src/mcedit2/ui/find_replace_nbt.ui b/src/mcedit2/ui/find_replace_nbt.ui
index 08e783f..d1075c0 100644
--- a/src/mcedit2/ui/find_replace_nbt.ui
+++ b/src/mcedit2/ui/find_replace_nbt.ui
@@ -215,7 +215,7 @@
-
-
+
-
Existing
diff --git a/src/mcedit2/ui/find_replace_nbt_results.ui b/src/mcedit2/ui/find_replace_nbt_results.ui
index 99f9c97..c2996de 100644
--- a/src/mcedit2/ui/find_replace_nbt_results.ui
+++ b/src/mcedit2/ui/find_replace_nbt_results.ui
@@ -6,8 +6,8 @@
0
0
- 578
- 345
+ 771
+ 458
@@ -27,6 +27,81 @@
+ -
+
+
-
+
+
+ Replace Name With:
+
+
+
+ -
+
+
+ -
+
+
+ Replace Value With:
+
+
+
+ -
+
+
+ -
+
+
+ Tag Type:
+
+
+
+ -
+
+
-
+
+ Existing
+
+
+ -
+
+ String
+
+
+ -
+
+ Byte
+
+
+ -
+
+ Short
+
+
+ -
+
+ Int
+
+
+ -
+
+ Long
+
+
+ -
+
+ Float
+
+
+ -
+
+ Double
+
+
+
+
+
+
-
-
diff --git a/src/mcedit2/util/settings.py b/src/mcedit2/util/settings.py
index a4cb07b..d41510e 100644
--- a/src/mcedit2/util/settings.py
+++ b/src/mcedit2/util/settings.py
@@ -22,13 +22,17 @@ def Settings():
class MCESettingsOption(QtCore.QObject):
- def __init__(self, settings, key, type, *args, **kwargs):
+ def __init__(self, settings, key, type, default=None, *args, **kwargs):
super(MCESettingsOption, self).__init__(*args, **kwargs)
self.settings = settings
self.key = key
self.type = type
+ self.default = default
def value(self, default=None):
+ if default is None:
+ default = self.default
+
value = self.settings.value(self.key, default)
if self.type:
value = self.type(value)
@@ -53,8 +57,8 @@ class MCESettingsNamespace(object):
self.prefix = prefix
- def getOption(self, key, type=None):
- return self.rootSettings.getOption(self.prefix + key, type)
+ def getOption(self, key, type=None, default=None):
+ return self.rootSettings.getOption(self.prefix + key, type, default)
class MCESettings(QtCore.QSettings):
@@ -123,7 +127,7 @@ class MCESettings(QtCore.QSettings):
def setJsonValue(self, key, value):
self.setValue(key, json.dumps(value))
- def getOption(self, key, type=None):
+ def getOption(self, key, type=None, default=None):
"""
Return an object that represents the setting at 'key'. The object may be used to get and set the value and
get the value's valueChanged signal. Among other uses, the object's setValue attribute may be connected to the
@@ -138,7 +142,7 @@ class MCESettings(QtCore.QSettings):
if option:
return option
- option = MCESettingsOption(self, key, type)
+ option = MCESettingsOption(self, key, type, default)
self.options[key] = option
return option