コード例 #1
0
ファイル: worldlist.py プロジェクト: KevinKelley/mcedit2
class WorldListWidget(QtGui.QDialog, Ui_worldList):
    def __init__(self, parent=None):
        super(WorldListWidget, self).__init__(parent, f=Qt.Tool)
        self.setWindowTitle("World List")
        self.setWindowModality(Qt.NonModal)
        self.setupUi(self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        self.chooseSavesFolderButton.clicked.connect(self.chooseSavesFolder)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(self.worldListView)  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        try:
            savesFolders = WorldListSettings.allSavesFolders.value()
            for filename in savesFolders:
                if not os.path.isdir(filename):
                    continue
                dirname, basename = os.path.split(filename)
                displayName = os.sep.join(dirname.split(os.sep)[-2:] + [basename])
                self.savesFolderComboBox.addItem(displayName, filename)
        except (ValueError, KeyError) as e:
            log.warn("Failed to load saves folder list.")

        currentFolder = WorldListSettings.currentSavesFolder.value()
        if os.path.isdir(currentFolder):
            index = self.savesFolderComboBox.findData(currentFolder)
            if index != -1:
                self.savesFolderComboBox.setCurrentIndex(index)

        self.savesFolderComboBox.currentIndexChanged.connect(self.savesFolderChanged)
        self.minecraftInstallBox.currentIndexChanged.connect(self.currentInstallChanged)
        self.minecraftVersionBox.currentIndexChanged[str].connect(minecraftinstall.currentVersionOption.setValue)
        self.resourcePackBox.currentIndexChanged.connect(self.resourcePackChanged)
        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def currentInstallChanged(self, index):
        path = self.minecraftInstallBox.itemData(index)
        minecraftinstall.currentInstallOption.setValue(path)

    def resourcePackChanged(self, index):
        if index == 0:
            minecraftinstall.currentResourcePackOption.setValue("")
        else:
            minecraftinstall.currentResourcePackOption.setValue(self.resourcePackBox.currentText())

    def _updateInstalls(self):
        self.minecraftInstallBox.clear()

        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name, install.path)
            for saveDir in install.getSaveDirs():
                self.savesFolderComboBox.addItem(install.name + os.sep + os.path.basename(saveDir), saveDir)

        for instance in minecraftinstall.GetInstalls().instances:
            saveDir = instance.saveFileDir
            self.savesFolderComboBox.addItem(instance.name + os.sep + os.path.basename(saveDir), saveDir)

        path = minecraftinstall.GetInstalls().selectedInstallPath()
        index = self.minecraftInstallBox.findData(path)
        self.minecraftInstallBox.setCurrentIndex(index)

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        self.minecraftVersionBox.clear()
        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))

        path = minecraftinstall.currentInstallOption.value()
        install = minecraftinstall.GetInstalls().getInstall(path)

        if install:
            for version in sorted(install.versions, reverse=True):
                self.minecraftVersionBox.addItem(version)

            for resourcePack in sorted(install.resourcePacks):
                self.resourcePackBox.addItem(resourcePack)

    def chooseSavesFolder(self):
        startingDir = WorldListSettings.lastChosenSavesFolder.value()
        if startingDir == '' or not os.path.isdir(startingDir):
            startingDir = os.path.expanduser(b"~")

        filename = QtGui.QFileDialog.getExistingDirectory(
            self, self.tr("Choose Saves Folder"), startingDir
        )

        if filename:
            log.info("Adding saves folder %s", filename)

            savesFolders = WorldListSettings.allSavesFolders.value()
            savesFolders.append(filename)
            WorldListSettings.allSavesFolders.setValue(savesFolders)

            dirname, basename = os.path.split(filename)
            displayName = os.sep.join(dirname.split(os.sep)[-2:] + [basename])
            WorldListSettings.lastChosenSavesFolder.setValue(filename)
            self.savesFolderComboBox.addItem(displayName, filename)
            self.savesFolderComboBox.setCurrentIndex(self.savesFolderComboBox.count()-1)

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)
            return triggered
        dead = []
        for filename in recentWorlds:
            if not os.path.exists(filename):
                dead.append(filename)
                continue
            try:
                displayName, lastPlayed, versionInfo = WorldEditor.getWorldInfo(filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        if len(dead):
            for f in dead:
                recentWorlds.remove(f)
            RecentFilesSetting.setValue(recentWorlds)

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def savesFolderChanged(self):
        currentFolder = self.savesFolderComboBox.itemData(self.savesFolderComboBox.currentIndex())
        WorldListSettings.currentSavesFolder.setValue(currentFolder)
        
        self.reloadList()
        if len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])
        else:
            self.removeWorldView()

    def reloadList(self):
        try:
            saveFileDir = self.savesFolderComboBox.itemData(self.savesFolderComboBox.currentIndex())
            if saveFileDir is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            if not os.path.isdir(saveFileDir):
                raise IOError(u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)".format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [os.path.join(saveFileDir, p) for p in potentialWorlds]
            worldFiles = [p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)

        except Exception as e:
            setWidgetError(self, e, "An error occurred while scanning the saves folder.")

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        if filename == self._currentFilename:
            return
        self._currentFilename = filename

        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(self.errorWidget, e, "An error occurred while reading the world %s." % filename)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                try:
                    player = worldEditor.getPlayer()
                    log.info("Centering on single-player player.")
                except PlayerNotFound:
                    try:
                        center = worldEditor.getWorldMetadata().Spawn
                        log.info("Centering on spawn position.")
                    except AttributeError:
                        log.info("Centering on world center")
                        center = dim.bounds.origin + (dim.bounds.size * 0.5)
                else:
                    if player.dimName == dim.dimName:
                        center = Vector(*player.Position)
                        self.worldView.centerOnPoint(center)
                    else:
                        center = dim.bounds.origin + (dim.bounds.size * 0.5)

                self.worldView.centerOnPoint(center)
            except Exception as e:
                log.exception("Error while centering view in world list: %s", e)

            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents()  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.dealloc()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

        # ensure WorldView gets freed now and not later
        # if it is freed later, it will call makeCurrent and ruin another view's render
        import gc; gc.collect()

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateInstalls()
コード例 #2
0
class WorldListWidget(QtGui.QDialog):
    def __init__(self, parent=None):
        super(WorldListWidget, self).__init__(parent, f=Qt.Tool)
        self.setWindowTitle("World List")
        self.setWindowModality(Qt.NonModal)
        load_ui('world_list.ui', baseinstance=self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)
        self.viewButton.setEnabled(False)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(
            self.worldListView
        )  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(
            self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        self.savesFolderComboBox.currentIndexChanged.connect(self.reloadList)
        self.minecraftInstallBox.currentIndexChanged.connect(
            minecraftinstall.currentInstallOption.setValue)
        self.minecraftVersionBox.currentIndexChanged[str].connect(
            minecraftinstall.currentVersionOption.setValue)
        self.resourcePackBox.currentIndexChanged.connect(
            self.resourcePackChanged)
        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def resourcePackChanged(self, index):
        if index == 0:
            minecraftinstall.currentResourcePackOption.setValue("")
        else:
            minecraftinstall.currentResourcePackOption.setValue(
                self.resourcePackBox.currentText())

    def _updateInstalls(self):
        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name)

        self.minecraftInstallBox.setCurrentIndex(
            minecraftinstall.GetInstalls().selectedInstallIndex())

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        self.minecraftVersionBox.clear()
        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))

        self.savesFolderComboBox.clear()

        if self.minecraftInstallBox.count():
            install = minecraftinstall.GetInstalls().getInstall(
                self.minecraftInstallBox.currentIndex())

            for version in sorted(install.versions, reverse=True):
                self.minecraftVersionBox.addItem(version)

            for resourcePack in sorted(install.resourcePacks):
                self.resourcePackBox.addItem(resourcePack)

            for filename in install.getSaveDirs():
                self.savesFolderComboBox.addItem(
                    os.path.basename(os.path.dirname(filename)),
                    (filename, None))

        for index, instance in enumerate(
                minecraftinstall.GetInstalls().instances):  # xxx instanceID?
            self.savesFolderComboBox.addItem(instance.name,
                                             (instance.saveFileDir, index))

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)

            return triggered

        dead = []
        for filename in recentWorlds:
            if not os.path.exists(filename):
                dead.append(filename)
                continue
            try:
                displayName, lastPlayed, versionInfo = getWorldInfo(filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        if len(dead):
            for f in dead:
                recentWorlds.remove(f)
            RecentFilesSetting.setValue(recentWorlds)

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def reloadList(self):
        try:
            itemData = self.savesFolderComboBox.itemData(
                self.savesFolderComboBox.currentIndex())
            if itemData is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            saveFileDir, instanceIndex = itemData
            if instanceIndex is not None:
                # disable version selector, update resource packs(?)
                pass
            if not os.path.isdir(saveFileDir):
                raise IOError(
                    u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)"
                    .format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [
                os.path.join(saveFileDir, p) for p in potentialWorlds
            ]
            worldFiles = [
                p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)
            ]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)

            if len(self.worldListModel.worlds):
                self.worldListView.setFocus()
                self.worldListView.setCurrentIndex(
                    self.worldListModel.createIndex(0, 0))
                self.showWorld(self.worldListModel.worlds[0][0])

        except EnvironmentError as e:
            setWidgetError(self, e)

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        if filename != self._currentFilename:
            self._currentFilename = filename
            self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)
            resLoader = QtGui.qApp.getResourceLoaderForFilename(filename)
            blockModels = BlockModels(worldEditor.blocktypes, resLoader)
            textureAtlas = TextureAtlas(worldEditor, resLoader, blockModels)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(self.errorWidget, e)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim, textureAtlas))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                player = worldEditor.getPlayer()
                log.info("Centering on single-player player.")
            except PlayerNotFound:
                try:
                    center = worldEditor.worldSpawnPosition()
                    log.info("Centering on spawn position.")
                except AttributeError:
                    log.info("Centering on world center")
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)
            else:
                if player.dimName == dim.dimName:
                    center = Vector(*player.Position)
                    self.worldView.centerOnPoint(center)
                else:
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)

            self.worldView.centerOnPoint(center)
            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents(
        )  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.destroy()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(
                self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateVersionsAndResourcePacks()
コード例 #3
0
class WorldListWidget(QtGui.QDialog, Ui_worldList):
    def __init__(self, parent=None):
        super(WorldListWidget, self).__init__(parent, f=Qt.Tool)
        self.setWindowTitle("World List")
        self.setWindowModality(Qt.NonModal)
        self.setupUi(self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        self.chooseSavesFolderButton.clicked.connect(self.chooseSavesFolder)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(
            self.worldListView
        )  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(
            self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        try:
            savesFolders = WorldListSettings.allSavesFolders.value()
            for filename in savesFolders:
                if not os.path.isdir(filename):
                    continue
                dirname, basename = os.path.split(filename)
                displayName = os.sep.join(
                    dirname.split(os.sep)[-2:] + [basename])
                self.savesFolderComboBox.addItem(displayName, filename)
        except (ValueError, KeyError) as e:
            log.warn("Failed to load saves folder list.")

        currentFolder = WorldListSettings.currentSavesFolder.value()
        if os.path.isdir(currentFolder):
            index = self.savesFolderComboBox.findData(currentFolder)
            if index != -1:
                self.savesFolderComboBox.setCurrentIndex(index)

        self.savesFolderComboBox.currentIndexChanged.connect(
            self.savesFolderChanged)
        self.minecraftInstallBox.currentIndexChanged.connect(
            self.currentInstallChanged)
        self.minecraftVersionBox.currentIndexChanged[str].connect(
            minecraftinstall.currentVersionOption.setValue)
        self.resourcePackBox.currentIndexChanged.connect(
            self.resourcePackChanged)
        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def currentInstallChanged(self, index):
        path = self.minecraftInstallBox.itemData(index)
        minecraftinstall.currentInstallOption.setValue(path)

    def resourcePackChanged(self, index):
        if index == 0:
            minecraftinstall.currentResourcePackOption.setValue("")
        else:
            minecraftinstall.currentResourcePackOption.setValue(
                self.resourcePackBox.currentText())

    def _updateInstalls(self):
        self.minecraftInstallBox.clear()

        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name, install.path)
            for saveDir in install.getSaveDirs():
                self.savesFolderComboBox.addItem(
                    install.name + os.sep + os.path.basename(saveDir), saveDir)

        for instance in minecraftinstall.GetInstalls().instances:
            saveDir = instance.saveFileDir
            self.savesFolderComboBox.addItem(
                instance.name + os.sep + os.path.basename(saveDir), saveDir)

        path = minecraftinstall.GetInstalls().selectedInstallPath()
        index = self.minecraftInstallBox.findData(path)
        self.minecraftInstallBox.setCurrentIndex(index)

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        self.minecraftVersionBox.clear()
        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))

        path = minecraftinstall.currentInstallOption.value()
        install = minecraftinstall.GetInstalls().getInstall(path)

        if install:
            for version in sorted(install.versions, reverse=True):
                self.minecraftVersionBox.addItem(version)

            for resourcePack in sorted(install.resourcePacks):
                self.resourcePackBox.addItem(resourcePack)

    def chooseSavesFolder(self):
        startingDir = WorldListSettings.lastChosenSavesFolder.value()
        if startingDir == '' or not os.path.isdir(startingDir):
            startingDir = os.path.expanduser(b"~")

        filename = QtGui.QFileDialog.getExistingDirectory(
            self, self.tr("Choose Saves Folder"), startingDir)

        if filename:
            log.info("Adding saves folder %s", filename)

            savesFolders = WorldListSettings.allSavesFolders.value()
            savesFolders.append(filename)
            WorldListSettings.allSavesFolders.setValue(savesFolders)

            dirname, basename = os.path.split(filename)
            displayName = os.sep.join(dirname.split(os.sep)[-2:] + [basename])
            WorldListSettings.lastChosenSavesFolder.setValue(filename)
            self.savesFolderComboBox.addItem(displayName, filename)
            self.savesFolderComboBox.setCurrentIndex(
                self.savesFolderComboBox.count() - 1)

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)

            return triggered

        dead = []
        for filename in recentWorlds:
            if not os.path.exists(filename):
                dead.append(filename)
                continue
            try:
                displayName, lastPlayed, versionInfo = WorldEditor.getWorldInfo(
                    filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        if len(dead):
            for f in dead:
                recentWorlds.remove(f)
            RecentFilesSetting.setValue(recentWorlds)

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def savesFolderChanged(self):
        currentFolder = self.savesFolderComboBox.itemData(
            self.savesFolderComboBox.currentIndex())
        WorldListSettings.currentSavesFolder.setValue(currentFolder)

        self.reloadList()
        if len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(
                self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])
        else:
            self.removeWorldView()

    def reloadList(self):
        try:
            saveFileDir = self.savesFolderComboBox.itemData(
                self.savesFolderComboBox.currentIndex())
            if saveFileDir is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            if not os.path.isdir(saveFileDir):
                raise IOError(
                    u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)"
                    .format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [
                os.path.join(saveFileDir, p) for p in potentialWorlds
            ]
            worldFiles = [
                p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)
            ]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)

        except Exception as e:
            setWidgetError(
                self, e, "An error occurred while scanning the saves folder.")

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        if filename == self._currentFilename:
            return
        self._currentFilename = filename

        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(
                self.errorWidget, e,
                "An error occurred while reading the world %s." % filename)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                try:
                    player = worldEditor.getPlayer()
                    log.info("Centering on single-player player.")
                except (PlayerNotFound, NBTFormatError):
                    try:
                        center = worldEditor.getWorldMetadata().Spawn
                        log.info("Centering on spawn position.")
                    except AttributeError:
                        log.info("Centering on world center")
                        center = dim.bounds.origin + (dim.bounds.size * 0.5)
                else:
                    if player.dimName == dim.dimName:
                        center = Vector(*player.Position)
                        self.worldView.centerOnPoint(center)
                    else:
                        center = dim.bounds.origin + (dim.bounds.size * 0.5)

                self.worldView.centerOnPoint(center)
            except Exception as e:
                log.exception("Error while centering view in world list: %s",
                              e)

            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents(
        )  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.dealloc()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

        # ensure WorldView gets freed now and not later
        # if it is freed later, it will call makeCurrent and ruin another view's render
        import gc
        gc.collect()

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(
                self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateInstalls()
コード例 #4
0
ファイル: worldlist.py プロジェクト: Fiskmans/mcedit2
class WorldListWidget(QtGui.QDialog):
    def __init__(self, parent=None, f=0):
        super(WorldListWidget, self).__init__(parent, f)
        self.setWindowTitle("World List")

        self.saveFileDir = None
        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = QtGui.QWidget()

        load_ui('world_list.ui', baseinstance=self)

        self.setLayout(Row(self))

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)
        self.viewButton.setEnabled(False)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        screen = QtGui.QApplication.desktop().availableGeometry()
        w = screen.width()
        h = screen.height()
        margin = 0.125
        r = QtCore.QRect(screen.x() + margin * w,
                         screen.y() + margin * h, w - w * 2 * margin,
                         h - h * 2 * margin)

        self.setGeometry(r)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        for install in minecraftinstall.listInstalls():
            self.minecraftInstallBox.addItem(install.name)
        self.minecraftInstallBox.setCurrentIndex(
            minecraftinstall.selectedInstallIndex())
        self._updateVersionsAndResourcePacks()
        self.reloadList()

    def _updateVersionsAndResourcePacks(self):
        install = minecraftinstall.getInstall(
            self.minecraftInstallBox.currentIndex())
        for version in sorted(install.versions, reverse=True):
            self.minecraftVersionBox.addItem(version)
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))
        for resourcePack in sorted(install.resourcePacks):
            self.resourcePackBox.addItem(resourcePack)
        self.saveFileDir = install.getSaveFileDir()

    def getSelectedIVP(self):
        i = self.minecraftInstallBox.currentIndex()
        install = minecraftinstall.getInstall(i)
        v = self.minecraftVersionBox.currentText()
        if self.resourcePackBox.currentIndex() > 0:
            p = self.resourcePackBox.currentText()
        else:
            p = None
        return install, v, p

    def reloadList(self):
        self.selectedWorldIndex = -1

        self.itemWidgets = []

        try:
            if not os.path.isdir(self.saveFileDir):
                raise IOError(
                    u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)"
                    .format(self.saveFileDir))

            log.info("Scanning %s for worlds...", self.saveFileDir)
            potentialWorlds = os.listdir(self.saveFileDir)
            potentialWorlds = [
                os.path.join(self.saveFileDir, p) for p in potentialWorlds
            ]
            worldFiles = [
                p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)
            ]
            worldAdapters = []
            for f in worldFiles:
                try:
                    adapter = findAdapter(f, readonly=True)
                except Exception as e:
                    log.exception("Could not find adapter for %s: %r", f, e)
                    continue
                else:
                    worldAdapters.append(adapter)

            if len(worldAdapters) == 0:
                raise IOError(
                    "No worlds found! You should probably play Minecraft to create your first world."
                )

            column = QtGui.QVBoxLayout()
            column.setContentsMargins(0, 0, 0, 0)
            column.setSpacing(0)

            worldGroup = QtGui.QButtonGroup(self)
            #worldGroup.setExclusive(True)

            for adapter in worldAdapters:
                item = WorldListItemWidget(adapter)
                self.itemWidgets.append(item)

            self.itemWidgets.sort(key=lambda i: i.lastPlayed, reverse=True)

            for i, item in enumerate(self.itemWidgets):
                worldGroup.addButton(item, i)
                column.addWidget(item)
                item.doubleClicked.connect(self.worldListItemDoubleClicked)

            worldGroup.buttonClicked[int].connect(self.worldListItemClicked)

            self.scrollAreaWidgetContents.setLayout(column)

        except EnvironmentError as e:
            setWidgetError(self, e)

    def worldListItemClicked(self, i):
        if self.selectedWorldIndex == i:
            return
        self.selectedWorldIndex = i
        import gc
        gc.collect()
        models = {}
        try:
            worldEditor = worldeditor.WorldEditor(self.itemWidgets[i].filename,
                                                  readonly=True)
        except (EnvironmentError, LevelFormatError) as e:
            setWidgetError(self.errorWidget, e)
            while self.stackedWidget.count():
                self.stackedWidget.removeWidget(self.stackedWidget.widget(0))

            self.worldViewBox.addWidget(self.errorWidget)
        else:
            i, v, p = self.getSelectedIVP()
            blockModels = models.get(worldEditor.blocktypes)
            resLoader = i.getResourceLoader(v, p)
            if blockModels is None:
                models[worldEditor.blocktypes] = blockModels = BlockModels(
                    worldEditor.blocktypes, resLoader)
            textureAtlas = TextureAtlas(worldEditor, resLoader, blockModels)

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim, textureAtlas))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                player = worldEditor.getPlayer()
                log.info("Centering on single-player player.")
            except PlayerNotFound:
                try:
                    center = worldEditor.worldSpawnPosition()
                    log.info("Centering on spawn position.")
                except AttributeError:
                    log.info("Centering on world center")
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)
            else:
                if player.dimName == dim.dimName:
                    center = Vector(*player.Position)
                    self.worldView.centerOnPoint(center)
                else:
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)

            self.worldView.centerOnPoint(center)
            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)

    def removeWorldView(self):
        if self.worldView:
            self.worldView.textureAtlas.dispose()
            self.worldView.destroy()
            self.worldView.setParent(None)
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView = None

        self.chunkLoader = None

    def closeEvent(self, event):
        self.removeWorldView()
        self.selectedWorldIndex = -1
        #import gc; gc.collect()

    def showEvent(self, event):
        if len(self.itemWidgets):
            self.itemWidgets[0].click()

    def worldListItemDoubleClicked(self):
        self.editClicked()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        self.editWorldClicked.emit(
            self.itemWidgets[self.selectedWorldIndex].filename)
        self.accept()

    def viewClicked(self):
        self.viewWorldClicked.emit(
            self.itemWidgets[self.selectedWorldIndex].filename)
        self.accept()

    def repairClicked(self):
        self.repairWorldClicked.emit(
            self.itemWidgets[self.selectedWorldIndex].filename)
        self.accept()

    def backupClicked(self):
        self.backupWorldClicked.emit(
            self.itemWidgets[self.selectedWorldIndex].filename)
        self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateVersionsAndResourcePacks()
コード例 #5
0
ファイル: worldlist.py プロジェクト: funplayer123456/mcedit2
class WorldListWidget(QtGui.QDialog):
    def __init__(self, parent=None, f=0):
        super(WorldListWidget, self).__init__(parent, f)
        self.setWindowTitle("World List")
        load_ui('world_list.ui', baseinstance=self)

        self.worldView = None
        self.chunkLoader = None

        self.errorWidget = None
        self.blankWidget = QtGui.QWidget()
        self.stackedWidget.addWidget(self.blankWidget)

        self.editButton.clicked.connect(self.editClicked)
        self.cancelButton.clicked.connect(self.reject)
        self.showListAgainInput.setEnabled(False)

        self.viewButton.clicked.connect(self.viewClicked)
        self.viewButton.setEnabled(False)

        self.openWorldButton.clicked.connect(self.openWorldClicked)

        self.repairButton.clicked.connect(self.repairClicked)
        self.repairButton.setEnabled(False)
        self.backupButton.clicked.connect(self.backupClicked)
        self.backupButton.setEnabled(False)
        self.configureButton.clicked.connect(self.configureClicked)

        centerWidgetInScreen(self, 0.75)

        delegate = WorldListItemDelegate()
        self.worldListView.setItemDelegate(delegate)
        delegate.setParent(self.worldListView)  # PYSIDE-152: get the view widget to the drawPrimitive call

        self.worldListView.clicked.connect(self.worldListItemClicked)
        self.worldListView.doubleClicked.connect(self.worldListItemDoubleClicked)

        self.loadTimer = LoaderTimer(interval=0, timeout=self.loadTimerFired)
        self.loadTimer.start()

        self._updateInstalls()

        self.savesFolderComboBox.currentIndexChanged.connect(self.reloadList)

        self.worldListModel = None
        self.reloadList()
        self.reloadRecentWorlds()

    def _updateInstalls(self):
        for install in minecraftinstall.GetInstalls().installs:
            self.minecraftInstallBox.addItem(install.name)

        self.minecraftInstallBox.setCurrentIndex(minecraftinstall.GetInstalls().selectedInstallIndex())

        self._updateVersionsAndResourcePacks()

    def _updateVersionsAndResourcePacks(self):
        install = minecraftinstall.GetInstalls().getInstall(self.minecraftInstallBox.currentIndex())

        self.minecraftVersionBox.clear()
        for version in sorted(install.versions, reverse=True):
            self.minecraftVersionBox.addItem(version)

        self.resourcePackBox.clear()
        self.resourcePackBox.addItem(self.tr("(No resource pack)"))
        for resourcePack in sorted(install.resourcePacks):
            self.resourcePackBox.addItem(resourcePack)

        self.saveDirs = install.getSaveDirs()
        self.savesFolderComboBox.clear()
        for filename in self.saveDirs:
            self.savesFolderComboBox.addItem(os.path.basename(os.path.dirname(filename)), (filename, None))
        for index, instance in enumerate(minecraftinstall.GetInstalls().instances):  # xxx instanceID?
            self.savesFolderComboBox.addItem(instance.name, (instance.saveFileDir, index))

    def getSelectedIVP(self):
        i = self.minecraftInstallBox.currentIndex()
        install = minecraftinstall.GetInstalls().getInstall(i)
        v = self.minecraftVersionBox.currentText()
        if self.resourcePackBox.currentIndex() > 0:
            p = self.resourcePackBox.currentText()
        else:
            p = None
        return install, v, p

    def reloadRecentWorlds(self):
        recentWorlds = RecentFilesSetting.value()
        self.recentWorldsMenu = QtGui.QMenu()

        def _triggered(f):
            def triggered():
                self.accept()
                self.editWorldClicked.emit(f)
            return triggered

        for filename in recentWorlds:
            try:
                displayName, lastPlayed = getWorldInfo(filename)
                action = self.recentWorldsMenu.addAction(displayName)
                action._editWorld = _triggered(filename)
                action.triggered.connect(action._editWorld)
            except EnvironmentError as e:
                log.exception("Failed to load world info")

        self.recentWorldsButton.setMenu(self.recentWorldsMenu)

    def reloadList(self):
        try:
            itemData = self.savesFolderComboBox.itemData(self.savesFolderComboBox.currentIndex())
            if itemData is None:
                log.error("No item selected in savesFolderComboBox!!(?)")
                return
            saveFileDir, instanceIndex = itemData
            if instanceIndex is not None:
                # disable version selector, update resource packs(?)
                pass
            if not os.path.isdir(saveFileDir):
                raise IOError(u"Could not find the Minecraft saves directory!\n\n({0} was not found or is not a directory)".format(saveFileDir))

            log.info("Scanning %s for worlds...", saveFileDir)
            potentialWorlds = os.listdir(saveFileDir)
            potentialWorlds = [os.path.join(saveFileDir, p) for p in potentialWorlds]
            worldFiles = [p for p in potentialWorlds if isLevel(AnvilWorldAdapter, p)]

            self.worldListModel = WorldListModel(worldFiles)
            self.worldListView.setModel(self.worldListModel)



            if len(self.worldListModel.worlds):
                self.worldListView.setFocus()
                self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
                self.showWorld(self.worldListModel.worlds[0][0])

        except EnvironmentError as e:
            setWidgetError(self, e)

    def openWorldClicked(self):
        QtGui.qApp.chooseOpenWorld()

    _currentFilename = None

    def worldListItemClicked(self, index):
        filename = index.data()
        if filename != self._currentFilename:
            self._currentFilename = filename
            self.showWorld(filename)

    def worldListItemDoubleClicked(self, index):
        row = index.row()
        self.accept()
        self.editWorldClicked.emit(self.worldListModel.worlds[row][0])

    def showWorld(self, filename):
        self.removeWorldView()

        try:
            worldEditor = worldeditor.WorldEditor(filename, readonly=True)
            i, v, p = self.getSelectedIVP()
            resLoader = i.getResourceLoader(v, p)
            blockModels = BlockModels(worldEditor.blocktypes, resLoader)
            textureAtlas = TextureAtlas(worldEditor, resLoader, blockModels)

        except (EnvironmentError, LevelFormatError, zipfile.BadZipfile) as e:
            self.errorWidget = QtGui.QWidget()
            setWidgetError(self.errorWidget, e)
            self.stackedWidget.addWidget(self.errorWidget)
            self.stackedWidget.setCurrentWidget(self.errorWidget)

        else:

            dim = worldEditor.getDimension()
            self.setWorldView(MinimapWorldView(dim, textureAtlas))
            self.chunkLoader = ChunkLoader(dim)
            self.chunkLoader.addClient(self.worldView)
            self.chunkLoader.chunkCompleted.connect(self.worldView.update)

            try:
                player = worldEditor.getPlayer()
                log.info("Centering on single-player player.")
            except PlayerNotFound:
                try:
                    center = worldEditor.worldSpawnPosition()
                    log.info("Centering on spawn position.")
                except AttributeError:
                    log.info("Centering on world center")
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)
            else:
                if player.dimName == dim.dimName:
                    center = Vector(*player.Position)
                    self.worldView.centerOnPoint(center)
                else:
                    center = dim.bounds.origin + (dim.bounds.size * 0.5)

            self.worldView.centerOnPoint(center)
            log.info("Switched world view")

    def setWorldView(self, worldView):
        if self.worldView:
            self.removeWorldView()
        self.worldView = worldView
        self.stackedWidget.addWidget(worldView)
        self.stackedWidget.setCurrentWidget(worldView)

    def removeWorldView(self):
        self.stackedWidget.setCurrentWidget(self.blankWidget)
        QtGui.qApp.processEvents()  # force repaint of stackedWidget to hide old error widget
        if self.worldView:
            log.info("Removing view from WorldListWidget")
            self.worldView.textureAtlas.dispose()
            self.worldView.destroy()
            self.stackedWidget.removeWidget(self.worldView)
            self.worldView.setParent(None)
            self.worldView = None
        if self.errorWidget:
            self.stackedWidget.removeWidget(self.errorWidget)
            self.errorWidget = None

        self.chunkLoader = None

    def hide(self):
        self.removeWorldView()
        super(WorldListWidget, self).hide()

    def close(self):
        self.removeWorldView()
        super(WorldListWidget, self).close()

    def reject(self):
        self.removeWorldView()
        super(WorldListWidget, self).reject()

    def showEvent(self, event):
        if self.worldListModel and len(self.worldListModel.worlds):
            self.worldListView.setFocus()
            self.worldListView.setCurrentIndex(self.worldListModel.createIndex(0, 0))
            self.showWorld(self.worldListModel.worlds[0][0])

        self.reloadRecentWorlds()

    @profiler.function("worldListLoadTimer")
    def loadTimerFired(self):
        if not self.isVisible():
            self.loadTimer.setInterval(1000)
            return

        if self.chunkLoader:
            try:
                self.chunkLoader.next()
                self.loadTimer.setInterval(0)
            except StopIteration:
                self.loadTimer.setInterval(1000)
        else:
            self.loadTimer.setInterval(1000)

    @property
    def selectedWorldIndex(self):
        indexes = self.worldListView.selectedIndexes()
        if len(indexes):
            return indexes[0]

    editWorldClicked = QtCore.Signal(unicode)
    viewWorldClicked = QtCore.Signal(unicode)
    repairWorldClicked = QtCore.Signal(unicode)
    backupWorldClicked = QtCore.Signal(unicode)

    def editClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.editWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def viewClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.viewWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def repairClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.repairWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def backupClicked(self):
        index = self.selectedWorldIndex
        if index is not None:
            self.backupWorldClicked.emit(index.data(Qt.DisplayRole))
            self.accept()

    def configureClicked(self):
        installsWidget = MinecraftInstallsDialog()
        installsWidget.exec_()
        self._updateVersionsAndResourcePacks()