Ejemplo n.º 1
0
class TrackingMouseAction(ViewAction):
    button = Qt.NoButton
    hidden = True
    modifiers = None
    labelText = "Mouse Tracking (Don't change!)"
    settingsKey = None

    editorTab = weakrefprop()

    def __init__(self, editorTab):
        super(TrackingMouseAction, self).__init__()
        self.editorTab = editorTab

    def mouseMoveEvent(self, event):
        self.editorTab.editorSession.viewMouseMove(event)
Ejemplo n.º 2
0
class EntityListProxy(collections.MutableSequence):
    """
    A proxy for the Entities and TileEntities lists of a WorldEditorChunk. Accessing an element returns an EntityRef
    or TileEntityRef wrapping the element of the underlying NBT compound, with a reference to the WorldEditorChunk.

    These Refs cannot be created at load time as they hold a reference to the chunk, preventing the chunk from being
    unloaded when its refcount reaches zero.
    """

    chunk = weakrefprop()

    def __init__(self, chunk, attrName, refClass):
        self.attrName = attrName
        self.refClass = refClass
        self.chunk = chunk

    def __getitem__(self, key):
        return self.refClass(
            getattr(self.chunk.chunkData, self.attrName)[key], self.chunk)

    def __setitem__(self, key, value):
        tagList = getattr(self.chunk.chunkData, self.attrName)
        if isinstance(key, slice):
            tagList[key] = [v.rootTag for v in value]
        else:
            tagList[key] = value.rootTag
        self.chunk.dirty = True

    def __delitem__(self, key):
        del getattr(self.chunk.chunkData, self.attrName)[key]
        self.chunk.dirty = True

    def __len__(self):
        return len(getattr(self.chunk.chunkData, self.attrName))

    def insert(self, index, value):
        getattr(self.chunk.chunkData,
                self.attrName).insert(index, value.rootTag)
        self.chunk.dirty = True

    def remove(self, value):
        getattr(self.chunk.chunkData, self.attrName).remove(value.rootTag)
        self.chunk.dirty = True
Ejemplo n.º 3
0
class UseToolMouseAction(ViewAction):
    button = Qt.LeftButton
    labelText = "Use Tool (Don't change!)"
    hidden = True
    settingsKey = None

    editorTab = weakrefprop()

    def __init__(self, editorTab):
        super(UseToolMouseAction, self).__init__()
        self.editorTab = editorTab

    def mousePressEvent(self, event):
        self.editorTab.editorSession.viewMousePress(event)
        event.view.update()

    def mouseMoveEvent(self, event):
        self.editorTab.editorSession.viewMouseDrag(event)
        event.view.update()

    def mouseReleaseEvent(self, event):
        self.editorTab.editorSession.viewMouseRelease(event)
        event.view.update()
Ejemplo n.º 4
0
class EditorTool(QtCore.QObject):
    name = "Unnamed tool"
    iconName = None
    toolWidget = None
    cursorNode = None
    overlayNode = None
    editorSession = weakrefprop()

    def __init__(self, editorSession, *args, **kwargs):
        """
        Initialize toolWidget here.

        :type editorSession: EditorSession
        """
        super(EditorTool, self).__init__(*args, **kwargs)
        self.editorSession = editorSession

    def mousePress(self, event):
        """
        :type event: QMouseEvent
        event has been augmented with these attributes:

            point, ray, blockPosition, blockFace
        """

    def mouseMove(self, event):
        """
        :type event: QMouseEvent

        event has been augmented
        """

    def mouseDrag(self, event):
        """
        :type event: QMouseEvent

        event has been augmented
        """

    def mouseRelease(self, event):
        """
        :type event: QMouseEvent

        event has been augmented
        """

    def toolActive(self):
        """
        Called when this tool is selected.
        :return:
        :rtype:
        """

    def toolInactive(self):
        """
        Called when a different tool is selected.
        :return:
        :rtype:
        """

    toolPicked = QtCore.Signal(object)

    def pick(self):
        self.toolPicked.emit(self.name)

    def pickToolAction(self):
        name = self.name
        iconName = self.iconName
        if iconName:
            iconPath = resourcePath("mcedit2/assets/mcedit2/toolicons/%s.png" %
                                    iconName)
            if not os.path.exists(iconPath):
                log.error("Tool icon %s not found", iconPath)
                icon = None
            else:
                icon = QtGui.QIcon(iconPath)
        else:
            icon = None

        action = QtGui.QAction(
            self.tr(name),
            self,
            #shortcut=self.toolShortcut(name),  # xxxx coordinate with view movement keys
            triggered=self.pick,
            checkable=True,
            icon=icon,
        )
        action.toolName = name

        return action
Ejemplo n.º 5
0
class EditorTab(QtGui.QWidget):
    def __init__(self, editorSession):
        """
        EditorTab is the widget containing the editor viewports, the minimap, and
        the settings panel for the currently selected tool and its dockwidget.

        :type editorSession: mcedit2.editorsession.EditorSession
        :rtype: EditorTab
        """

        QtGui.QWidget.__init__(self)
        self.setContentsMargins(0, 0, 0, 0)

        self.editorSession = editorSession
        self.editorSession.dimensionChanged.connect(self.dimensionDidChange)
        self.debugLastCenters = []

        self.viewButtonGroup = QtGui.QButtonGroup(self)
        self.viewButtonToolbar = QtGui.QToolBar()
        self.viewButtons = {}
        self.views = []

        for name, handler in (
                ("2D", self.showCutawayView),
                ("Over", self.showOverheadView),
                # ("Iso", self.showIsoView),
                ("Cam", self.showCameraView),
                # ("4-up", self.showFourUpView),
        ):
            button = QtGui.QToolButton(text=name, checkable=True)
            button.clicked.connect(handler)
            self.viewButtonGroup.addButton(button)
            self.viewButtonToolbar.addWidget(button)
            self.viewButtons[name] = button

        self.viewStack = QtGui.QStackedWidget()

        self.miniMap = MinimapWorldView(editorSession.currentDimension, editorSession.textureAtlas, editorSession.geometryCache)
        self.miniMapDockWidget = QtGui.QDockWidget("Minimap", objectName="MinimapWidget", floating=True)
        self.miniMapDockWidget.setWidget(self.miniMap)
        self.miniMapDockWidget.setFixedSize(256, 256)

        self.views.append(self.miniMap)

        self.toolOptionsArea = QtGui.QScrollArea()
        self.toolOptionsArea.setWidgetResizable(True)

        self.toolOptionsDockWidget = QtGui.QDockWidget("Tool Options", objectName="ToolOptionsWidget", floating=True)
        self.toolOptionsDockWidget.setWidget(self.toolOptionsArea)
        editorSession.dockWidgets.append((Qt.LeftDockWidgetArea, self.miniMapDockWidget))
        editorSession.dockWidgets.append((Qt.LeftDockWidgetArea, self.toolOptionsDockWidget))

        editorSession.loader.addClient(self.miniMap)

        self.overheadViewFrame = OverheadWorldViewFrame(editorSession.currentDimension, editorSession.textureAtlas, editorSession.geometryCache, self.miniMap)
        self.overheadViewFrame.worldView.viewID = "Over"
        self._addView(self.overheadViewFrame)

        self.cutawayViewFrame = CutawayWorldViewFrame(editorSession.currentDimension, editorSession.textureAtlas, editorSession.geometryCache, self.miniMap)
        self.cutawayViewFrame.worldView.viewID = "2D"
        self._addView(self.cutawayViewFrame)
        #
        # self.fourUpViewFrame = FourUpWorldViewFrame(editorSession.currentDimension, editorSession.textureAtlas, editorSession.geometryCache, self.miniMap)
        # self.fourUpViewFrame.worldView.viewID = "4-up"
        # self._addView(self.fourUpViewFrame)

        self.cameraViewFrame = CameraWorldViewFrame(editorSession.currentDimension, editorSession.textureAtlas, editorSession.geometryCache, self.miniMap)
        self.cameraViewFrame.worldView.viewID = "Cam"
        self.cameraView = self.cameraViewFrame.worldView
        self._addView(self.cameraViewFrame)

        self.viewStack.currentChanged.connect(self._viewChanged)
        self.viewChanged.connect(self.viewDidChange)

        self.setLayout(Column(self.viewButtonToolbar,
                              Row(self.viewStack, margin=0), margin=0))

        currentViewName = currentViewSetting.value()
        if currentViewName not in self.viewButtons:
            currentViewName = "Cam"
        self.viewButtons[currentViewName].click()

        self.editorSession.configuredBlocksChanged.connect(self.configuredBlocksDidChange)

    def destroy(self):
        self.editorSession = None
        for view in self.views:
            view.destroy()

        super(EditorTab, self).destroy()

    editorSession = weakrefprop()

    def configuredBlocksDidChange(self):
        for view in self.views:
            view.setTextureAtlas(self.editorSession.textureAtlas)

    def dimensionDidChange(self, dim):
        for view in self.views:
            view.setDimension(dim)
        # EditorSession has a new loader now, so re-add minimap and current view

        self.editorSession.loader.addClient(self.miniMap)
        view = self.currentView()
        if view is not None:
            self.editorSession.loader.addClient(view)


    def toolDidChange(self, tool):
        if tool.toolWidget:
            self.toolOptionsArea.takeWidget()  # setWidget gives ownership to the scroll area
            self.toolOptionsArea.setWidget(tool.toolWidget)
            self.toolOptionsDockWidget.setWindowTitle(self.tr(tool.name) + self.tr(" Tool Options"))
        log.info("Setting cursor %r for tool %r on view %r", tool.cursorNode, tool,
                 self.currentView())
        self.currentView().setToolCursor(tool.cursorNode)

    def saveState(self):
        pass

    viewChanged = QtCore.Signal(object)

    def _viewChanged(self, index):
        self.viewChanged.emit(self.currentView())

    def viewDidChange(self, view):
        self.miniMap.centerOnPoint(view.viewCenter())
        if self.editorSession.currentTool:
            view.setToolCursor(self.editorSession.currentTool.cursorNode)

        overlayNodes = [tool.overlayNode
                        for tool in self.editorSession.tools
                        if tool.overlayNode is not None]

        overlayNodes.insert(0, self.editorSession.editorOverlay)
        view.setToolOverlays(overlayNodes)
        view.setFocus()

    def viewOffsetChanged(self, view):
        self.miniMap.centerOnPoint(view.viewCenter())
        self.miniMap.currentViewMatrixChanged(view)

    def _addView(self, frame):
        self.views.append(frame.worldView)
        frame.stackIndex = self.viewStack.addWidget(frame)
        frame.worldView.viewportMoved.connect(self.viewOffsetChanged)
        frame.worldView.viewActions.extend([
            UseToolMouseAction(self),
            TrackingMouseAction(self)
        ])

    def currentView(self):
        """

        :rtype: mcedit2.worldview.worldview.WorldView
        """
        widget = self.viewStack.currentWidget()
        if widget is None:
            return None
        return widget.worldView

    def showViewFrame(self, frame):
        center = self.currentView().viewCenter()
        self.debugLastCenters.append(center)
        log.info("Going from %s to %s: Center was %s", self.currentView(), frame.worldView, center)

        self.editorSession.loader.removeClient(self.currentView())
        self.editorSession.loader.addClient(frame.worldView, 0)
        self.viewStack.setCurrentIndex(frame.stackIndex)

        frame.worldView.centerOnPoint(center)

        log.info("Center is now %s", self.currentView().viewCenter())

    def showOverheadView(self):
        self.showViewFrame(self.overheadViewFrame)

    #
    # def showIsoView(self):
    #     self.showViewFrame(self.isoViewFrame)
    #
    # def showFourUpView(self):
    #     self.showViewFrame(self.fourUpViewFrame)

    def showCutawayView(self):
        self.showViewFrame(self.cutawayViewFrame)

    def showCameraView(self):
        self.showViewFrame(self.cameraViewFrame)
Ejemplo n.º 6
0
class PlayerPanel(QtGui.QWidget, Ui_playerWidget):
    def __init__(self, editorSession):
        """

        :type editorSession: mcedit2.editorsession.EditorSession
        :rtype: PlayerPanel
        """
        super(PlayerPanel, self).__init__(QtGui.qApp.mainWindow, f=Qt.Tool)
        self.setupUi(self)

        self.editorSession = editorSession
        self.selectedUUID = None
        self.nbtEditor.editorSession = self.editorSession

        self.inventoryEditor = InventoryEditor(PLAYER_SLOT_LAYOUT)
        self.inventoryGroupBox.setLayout(Row(self.inventoryEditor))

        self.movePlayerButton.clicked.connect(self.movePlayerToCamera)
        self.viewPlayerButton.clicked.connect(self.showPlayerView)
        playerUUIDs = list(editorSession.worldEditor.listPlayers())
        try:
            sp = editorSession.worldEditor.getPlayer("")
            singlePlayerUUID = sp.UUID
        except PlayerNotFound:
            log.info("No single-player.")
            singlePlayerUUID = None
        except KeyError:
            log.info("Failed to get single-player UUID.")
            singlePlayerUUID = None

        if "" in playerUUIDs:
            # Move singleplayer to beginning of list
            playerUUIDs.remove("")
            playerUUIDs.insert(0, "")

        for UUID in playerUUIDs:  # xxx live update?
            if UUID == "":
                displayName = "[Single-player](%s)" % singlePlayerUUID
            else:
                displayName = UUID  # xxx mojang api here
                try:
                    UUID = uuid.UUID(hex=UUID)
                    if UUID == singlePlayerUUID:
                        displayName = "[Multiplayer](%s)" % singlePlayerUUID
                except ValueError:  # badly formed uuid?
                    log.warn("Could not get a UUID from %s", UUID)
                    continue

            self.playerListBox.addItem(displayName, UUID)

        self.playerListBox.currentIndexChanged[int].connect(
            self.setSelectedPlayerIndex)
        if len(playerUUIDs):
            self.setSelectedPlayerIndex(0)

        icon = QtGui.QIcon(
            resourcePath("mcedit2/assets/mcedit2/icons/edit_player.png"))
        action = QtGui.QAction(icon, "Edit Player", self)
        action.setCheckable(True)
        action.triggered.connect(self.toggleView)
        self._toggleViewAction = action

        self.editorSession.revisionChanged.connect(self.revisionDidChange)
        self.initPropertiesWidget()

        centerWidgetInScreen(self)

    editorSession = weakrefprop()

    def initPropertiesWidget(self):
        if self.selectedPlayer is None:
            self.playerPropertiesWidget.setModel(None)
            return

        model = PropertyListModel(self.selectedPlayer.rootTag)
        addWidget = model.addNBTProperty

        addWidget("AbsorptionAmount")
        addWidget("Air")
        addWidget("DeathTime")
        addWidget("Dimension")
        addWidget("FallDistance", valueType=float)
        addWidget("Fire")
        addWidget("foodExhaustionLevel", valueType=float)
        addWidget("foodLevel")
        addWidget("foodSaturationLevel", valueType=float)
        addWidget("foodTickTimer")
        addWidget("HealF", valueType=float)
        addWidget("Health")
        addWidget("HurtByTimestamp")
        addWidget("HurtTime")
        addWidget("Invulnerable", bool)
        addWidget("OnGround", bool)
        addWidget("playerGameType", [(0, "Survival"), (1, "Creative"),
                                     (2, "Adventure")])
        addWidget("PortalCooldown")
        addWidget("Score")
        addWidget("SelectedItemSlot")  # xxx inventory
        addWidget("Sleeping", bool)
        addWidget("SleepTimer")
        addWidget("XpLevel")
        addWidget("XpP", float)
        addWidget("XpSeed")
        addWidget("XpTotal")

        self.playerPropertiesWidget.setModel(model)
        model.propertyChanged.connect(self.propertyDidChange)

    def updateNBTTree(self):
        self.nbtEditor.undoCommandPrefixText = (
            "Player %s: " %
            self.selectedUUID) if self.selectedUUID else "Single-player: "
        self.nbtEditor.setRootTagRef(self.selectedPlayer)

    def updateInventory(self):
        self.inventoryEditor.editorSession = self.editorSession
        self.inventoryEditor.inventoryRef = self.selectedPlayer.Inventory

    def revisionDidChange(self):
        self.initPropertiesWidget()
        self.updateNBTTree()

    def propertyDidChange(self, name, value):
        if self.selectedUUID != "":
            text = "Change player %s property %s" % (self.selectedUUID, name)
        else:
            text = "Change single-player property %s" % name

        command = PlayerPropertyChangeCommand(self.editorSession, text)
        with command.begin():
            self.selectedPlayer.dirty = True
            self.editorSession.worldEditor.syncToDisk()
        self.editorSession.pushCommand(command)

    def toggleView(self):
        if self.isHidden():
            self.show()
            self._toggleViewAction.setChecked(True)
        else:
            self.hide()
            self._toggleViewAction.setChecked(False)

    def closeEvent(self, event):
        self.toggleView()

    def toggleViewAction(self):
        return self._toggleViewAction

    def setSelectedPlayerIndex(self, index):
        UUID = self.playerListBox.itemData(index)
        self.setSelectedPlayerUUID(UUID)

    def setSelectedPlayerUUID(self, UUID):
        self.selectedUUID = UUID
        self.updateNBTTree()
        self.updateInventory()

    @property
    def selectedPlayer(self):
        try:
            return self.editorSession.worldEditor.getPlayer(self.selectedUUID)
        except PlayerNotFound:
            log.info("PlayerPanel: player %s not found!", self.selectedUUID)

    def movePlayerToCamera(self):
        view = self.editorSession.editorTab.currentView()
        if view.viewID == "Cam":
            command = SimpleRevisionCommand(self.editorSession, "Move Player")
            with command.begin():
                self.selectedPlayer.Position = view.centerPoint
                try:
                    self.selectedPlayer.Rotation = view.yawPitch
                except AttributeError:
                    pass

                self.selectedPlayer.dirty = True  # xxx do in AnvilPlayerRef
            self.editorSession.pushCommand(command)
        else:
            raise ValueError("Current view is not camera view.")

    def showPlayerView(self):
        self.editorSession.editorTab.showCameraView()
        view = self.editorSession.editorTab.cameraView
        view.setPerspective(False)
        view.centerPoint = self.selectedPlayer.Position
        view.yawPitch = self.selectedPlayer.Rotation
Ejemplo n.º 7
0
class NBTEditorWidget(QtGui.QWidget):
    """
    NBT Editor widget. Suitable for use as a custom QTreeView class in QDesigner.

    Attributes
    ----------

    editorSession: EditorSession

    """
    undoCommandPrefixText = ""
    editorSession = weakrefprop()
    proxyModel = None
    rootTagRef = None

    def __init__(self, *args, **kwargs):
        super(NBTEditorWidget, self).__init__(*args, **kwargs)
        self.model = None
        """:type : EditorSession"""
        self.editorSession = None
        self.treeView = QtGui.QTreeView()
        self.treeView.setAlternatingRowColors(True)
        self.treeView.clicked.connect(self.itemClicked)
        self.treeView.expanded.connect(self.itemExpanded)

        self.setLayout(Column(self.treeView))

        self.nbtTypesMenu = QtGui.QMenu()
        self.nbtTypesMenu.addAction(NBTIcon(1), self.tr("Byte"), self.addByte)
        self.nbtTypesMenu.addAction(NBTIcon(2), self.tr("Short"),
                                    self.addShort)
        self.nbtTypesMenu.addAction(NBTIcon(3), self.tr("Int"), self.addInt)
        self.nbtTypesMenu.addAction(NBTIcon(4), self.tr("Long"), self.addLong)
        self.nbtTypesMenu.addAction(NBTIcon(5), self.tr("Float"),
                                    self.addFloat)
        self.nbtTypesMenu.addAction(NBTIcon(6), self.tr("Double"),
                                    self.addDouble)
        self.nbtTypesMenu.addAction(NBTIcon(8), self.tr("String"),
                                    self.addString)
        self.nbtTypesMenu.addAction(NBTIcon(9), self.tr("List"), self.addList)
        self.nbtTypesMenu.addAction(NBTIcon(10), self.tr("Compound"),
                                    self.addCompound)

        self.nbtTypesMenu.addAction(NBTIcon(7), self.tr("Byte Array"),
                                    self.addByteArray)
        self.nbtTypesMenu.addAction(NBTIcon(11), self.tr("Int Array"),
                                    self.addIntArray)
        # self.nbtTypesMenu.addAction(NBTIcon(12), self.tr("Short Array"), self.addShortArray)

        self.treeView.setItemDelegate(NBTEditorItemDelegate())

    def setRootTagRef(self, rootTagRef, keepExpanded=False):
        if rootTagRef is self.rootTagRef:
            return
        self.rootTagRef = rootTagRef
        if rootTagRef is None:
            self.treeView.setModel(None)
            self.model = None
            return

        self.model = NBTTreeModel(rootTagRef.rootTag,
                                  self.editorSession.worldEditor.blocktypes)
        expanded = []
        current = None
        if keepExpanded and self.proxyModel:
            current = self.proxyModel.data(self.treeView.currentIndex(),
                                           NBTTreeModel.NBTPathRole)

            def addExpanded(parentIndex):
                for row in range(self.proxyModel.rowCount(parentIndex)):
                    index = self.proxyModel.index(row, 0, parentIndex)
                    if self.treeView.isExpanded(index):
                        expanded.append(
                            self.proxyModel.data(index,
                                                 NBTTreeModel.NBTPathRole))
                        addExpanded(index)

            addExpanded(QtCore.QModelIndex())

        self.model.dataChanged.connect(self.dataDidChange)
        self.model.rowsInserted.connect(self.rowsDidInsert)
        self.model.rowsRemoved.connect(self.rowsDidRemove)

        self.proxyModel = NBTFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.model)
        # self.proxyModel.setDynamicSortFilter(True)

        self.treeView.setModel(self.proxyModel)
        header = self.treeView.header()
        header.setStretchLastSection(False)
        header.setResizeMode(1, header.ResizeMode.Stretch)
        header.setResizeMode(2, header.ResizeMode.Fixed)
        header.setResizeMode(3, header.ResizeMode.Fixed)

        if keepExpanded:
            for path in expanded:
                matches = self.proxyModel.match(
                    self.proxyModel.index(0, 0, QtCore.QModelIndex()),
                    NBTTreeModel.NBTPathRole,
                    path,
                    flags=Qt.MatchExactly | Qt.MatchRecursive)
                for i in matches:
                    self.treeView.setExpanded(i, True)
            if current is not None:
                matches = self.proxyModel.match(
                    self.proxyModel.index(0, 0, QtCore.QModelIndex()),
                    NBTTreeModel.NBTPathRole,
                    current,
                    flags=Qt.MatchExactly | Qt.MatchRecursive)
                if len(matches):
                    self.treeView.setCurrentIndex(matches[0])
        else:
            self.treeView.expandToDepth(0)
        self.treeView.sortByColumn(0, Qt.AscendingOrder)
        self.treeView.resizeColumnToContents(0)
        self.treeView.resizeColumnToContents(1)
        self.treeView.resizeColumnToContents(2)
        self.treeView.resizeColumnToContents(3)

    def itemExpanded(self):
        self.treeView.resizeColumnToContents(0)

    indexAddingTo = None

    def itemClicked(self, index):
        index = self.proxyModel.mapToSource(index)
        item = self.model.getItem(index)
        if index.column() == 2:
            if item.isList and item.tag.list_type:
                row = item.childCount()
                self.model.insertRow(row, index)
                newItemIndex = self.model.index(row, 1, index)
                # self.treeView.setCurrentIndex(self.proxyModel.mapFromSource(newItemIndex))
                # self.treeView.edit(self.proxyModel.mapFromSource(newItemIndex))

            if item.isCompound or (item.isList and not item.tag.list_type):
                self.indexAddingTo = index
                self.nbtTypesMenu.move(QtGui.QCursor.pos())
                self.nbtTypesMenu.show()
        if index.column() == 3:
            parent = self.model.parent(index)
            self.doomedTagName = self.tagNameForUndo(index)
            self.model.removeRow(index.row(), parent)

    def addItemWithType(self, tagID):
        if not self.indexAddingTo:
            return
        item = self.model.getItem(self.indexAddingTo)
        row = item.childCount()
        self.model.insertRow(row, self.indexAddingTo, tagID)
        newItemIndex = self.model.index(row, 0 if item.isCompound else 1,
                                        self.indexAddingTo)
        # self.treeView.setCurrentIndex(self.proxyModel.mapFromSource(newItemIndex))
        # self.treeView.edit(self.proxyModel.mapFromSource(newItemIndex))
        self.indexAddingTo = None

    def addByte(self):
        self.addItemWithType(1)

    def addShort(self):
        self.addItemWithType(2)

    def addInt(self):
        self.addItemWithType(3)

    def addLong(self):
        self.addItemWithType(4)

    def addFloat(self):
        self.addItemWithType(5)

    def addDouble(self):
        self.addItemWithType(6)

    def addByteArray(self):
        self.addItemWithType(7)

    def addString(self):
        self.addItemWithType(8)

    def addList(self):
        self.addItemWithType(9)

    def addCompound(self):
        self.addItemWithType(10)

    def addIntArray(self):
        self.addItemWithType(11)

    def addShortArray(self):
        self.addItemWithType(12)

    def tagNameForUndo(self, index):
        parent = self.model.parent(index)
        item = self.model.getItem(index)
        parentItem = self.model.getItem(parent)
        name = "(root)"
        if parentItem is not None:
            if parentItem.isList:
                name = "%s #%d" % (self.tagNameForUndo(parent),
                                   parentItem.tag.index(item.tag))
            elif parentItem.isCompound:
                name = item.tag.name

        return name

    def dataDidChange(self, index):
        name = self.tagNameForUndo(index)
        if index.column() == 0:
            text = "%sRename NBT tag %s" % (self.undoCommandPrefixText, name)
        elif index.column() == 1:
            text = "%sChange value of NBT tag %s" % (
                self.undoCommandPrefixText, name)
        else:
            text = "Unknown data changed."

        command = NBTDataChangeCommand(self.editorSession, text)
        with command.begin():
            self.rootTagRef.dirty = True
            self.editorSession.worldEditor.syncToDisk()
        self.editorSession.pushCommand(command)
        self.tagValueChanged.emit(index.data(NBTTreeModel.NBTPathRole))

    def rowsDidInsert(self, index):
        name = self.tagNameForUndo(index.parent())
        text = "%sInsert NBT tag under %s" % (self.undoCommandPrefixText, name)

        command = NBTDataChangeCommand(self.editorSession, text)
        with command.begin():
            self.rootTagRef.dirty = True
            self.editorSession.worldEditor.syncToDisk()
        self.editorSession.pushCommand(command)

    doomedTagName = None

    def rowsDidRemove(self, index, start, end):
        name = self.tagNameForUndo(index)
        text = "%sRemove NBT tag %s from %s" % (self.undoCommandPrefixText,
                                                self.doomedTagName, name)

        command = NBTDataChangeCommand(self.editorSession, text)
        with command.begin():
            self.rootTagRef.dirty = True
            self.editorSession.worldEditor.syncToDisk()
        self.editorSession.pushCommand(command)

    tagValueChanged = QtCore.Signal(list)
    tagAdded = QtCore.Signal(list)
    tagRemoved = QtCore.Signal(list)