class DSManagerModel(QAbstractItemModel):
    __metaclass__ = QSingleton

    COLUMN_GROUP_DS = 0
    COLUMN_VISIBILITY = 1
    COLUMN_SOURCE = 2

    # instance = None

    # @classmethod
    # def getInstance(cls):
    #     if cls.instance

    def __init__(self, parent=None):
        super(DSManagerModel, self).__init__(parent)

        self.columnNames = []
        self.columnNames.insert(self.COLUMN_GROUP_DS, self.tr("Group/DS"))
        self.columnNames.insert(self.COLUMN_VISIBILITY, self.tr("Visible"))
        self.columnNames.insert(self.COLUMN_SOURCE, self.tr("Source"))

        self.rootItem = QTreeWidgetItem(self.columnNames)
        self.__setupModelData()

    def resetModel(self):
        self.beginResetModel()
        self.__clear()
        self.__setupModelData()
        self.endResetModel()
        self.modelReset.emit()

    def __clear(self):
        for groupIndex in range(self.rootItem.childCount() - 1, -1, -1):
            groupItem = self.rootItem.child(groupIndex)
            for dsIndex in range(groupItem.childCount() - 1, -1, -1):
                dsItem = groupItem.child(dsIndex)
                groupItem.removeChild(dsItem)
            self.rootItem.removeChild(groupItem)

    def __setupModelData(self):
        dsList = DataSourcesList().data_sources.values()
        groupInfoList = GroupsList().groups
        groupsItems = []
        groups = []
        for ds in dsList:
            if ds.group in groups:
                group_item = groupsItems[groups.index(ds.group)]
            else:
                group_item = QTreeWidgetItem()
                group_item.setData(self.COLUMN_GROUP_DS, Qt.DisplayRole, ds.group)
                group_item.setData(self.COLUMN_VISIBILITY, Qt.DisplayRole, "")
                group_item.setData(self.COLUMN_SOURCE, Qt.DisplayRole, ds.category)
                group_item.setCheckState(self.COLUMN_VISIBILITY, Qt.Unchecked)

                groupInfo = groupInfoList.get(ds.group)
                if groupInfo is not None:
                    group_item.setIcon(self.COLUMN_GROUP_DS, QIcon(groupInfo.icon))
                else:
                    group_item.setData(self.COLUMN_GROUP_DS, Qt.DisplayRole, ds.group + " (%s!)" % self.tr("group not found"))
                group_item.setData(self.COLUMN_GROUP_DS, Qt.UserRole, groupInfo)

                groups.append(ds.group)
                groupsItems.append(group_item)
                self.rootItem.addChild(group_item)

            ds_item = QTreeWidgetItem()
            ds_item.setData(self.COLUMN_GROUP_DS, Qt.DisplayRole, ds.alias)
            ds_item.setIcon(self.COLUMN_GROUP_DS, QIcon(ds.icon_path))
            ds_item.setData(self.COLUMN_GROUP_DS, Qt.UserRole, ds)
            ds_item.setData(self.COLUMN_VISIBILITY, Qt.DisplayRole, "")
            ds_item.setData(self.COLUMN_SOURCE, Qt.DisplayRole, ds.category)

            ds_check_state = Qt.Checked
            if ds.id in PluginSettings.get_hide_ds_id_list():
                ds_check_state = Qt.Unchecked
            ds_item.setCheckState(self.COLUMN_VISIBILITY, ds_check_state)

            if group_item.childCount() != 0 and group_item.checkState(1) != ds_check_state:
                group_item.setCheckState(self.COLUMN_VISIBILITY, Qt.PartiallyChecked)
            else:
                group_item.setCheckState(self.COLUMN_VISIBILITY, ds_check_state)

            group_item.addChild(
                ds_item
            )

    def setData(self, index, value, role):
        if not index.isValid():
            return False
        else:
            item = index.internalPointer()

        if role == Qt.CheckStateRole:
            item.setData(self.COLUMN_VISIBILITY, role, value)

            self.dataChanged.emit(
                index,
                index
            )

            self.updateChecks(index, value)
        return True

    def updateChecks(self, index, checkState):
        if self.hasChildren(index):
            for row in range(0, self.rowCount(index)):
                childItem = index.internalPointer().child(row)
                childItem.setCheckState(index.column(), checkState)

            self.dataChanged.emit(
                self.index(0, index.column(), index),
                self.index(row, index.column(), index)
            )
        else:
            parentIndex = self.parent(index)
            parentItem = parentIndex.internalPointer()

            diff = False
            for row in range(0, self.rowCount(parentIndex)):
                childItem = parentItem.child(row)
                if childItem.checkState(index.column()) != checkState:
                    diff = True
                    break

            if diff:
                parentItem.setCheckState(index.column(), Qt.PartiallyChecked)
            else:
                parentItem.setCheckState(index.column(), checkState)

            self.dataChanged.emit(
                parentIndex,
                parentIndex
            )

    def columnCount(self, parent):
        if parent.isValid():
            return parent.internalPointer().columnCount()
        else:
            return self.rootItem.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return None

        if role not in [Qt.DisplayRole, Qt.CheckStateRole, Qt.DecorationRole, Qt.UserRole]:
            return None

        item = index.internalPointer()
        return item.data(index.column(), role)

    def flags(self, index):
        if not index.isValid():
            item = self.rootItem
        else:
            item = index.internalPointer()

        return item.flags()

    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section, Qt.DisplayRole)

        return None

    def index(self, row, column, parent):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()
        childItem = index.internalPointer()
        parentItem = childItem.parent()
        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.parent().indexOfChild(parentItem), index.column(), parentItem)

    def rowCount(self, parent):
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    def sort(self, column, order=Qt.AscendingOrder):
        self.layoutAboutToBeChanged.emit()
        if column == self.COLUMN_VISIBILITY:
            role = Qt.CheckStateRole
        else:
            role = Qt.DisplayRole

        if order == Qt.AscendingOrder:
            # compareFunc = lambda a, b: True if cmp(a, b) < 0 else False
            compareFunc = lambda a, b: a < b # need to check
        else:
            # compareFunc = lambda a, b: True if cmp(a, b) > 0 else False
            compareFunc = lambda a, b: a >= b # need to check

        for groupIndexI in range(0, self.rootItem.childCount()):
            for groupIndexJ in range(0, groupIndexI):
                groupItemI = self.rootItem.child(groupIndexI)
                groupItemJ = self.rootItem.child(groupIndexJ)
                if compareFunc(groupItemI.data(column, role), groupItemJ.data(column, role)):
                    self.rootItem.insertChild(groupIndexJ, self.rootItem.takeChild(groupIndexI))
                    break

        self.layoutChanged.emit()

    def checkAll(self):
        for row in range(0, self.rootItem.childCount()):
            groupItem = self.rootItem.child(row)
            groupIndex = self.createIndex(row, self.COLUMN_VISIBILITY, groupItem)
            self.setData(groupIndex, Qt.Checked, Qt.CheckStateRole)

    def uncheckAll(self):
        for row in range(0, self.rootItem.childCount()):
            groupItem = self.rootItem.child(row)
            groupIndex = self.createIndex(row, self.COLUMN_VISIBILITY, groupItem)
            self.setData(groupIndex, Qt.Unchecked, Qt.CheckStateRole)

    def saveSettings(self):
        hideDSidList = []
        for groupIndex in range(0, self.rootItem.childCount()):
            groupItem = self.rootItem.child(groupIndex)
            for dsIndex in range(0, groupItem.childCount()):
                dsItem = groupItem.child(dsIndex)
                if dsItem.checkState(self.COLUMN_VISIBILITY) == Qt.Unchecked:
                    hideDSidList.append(dsItem.data(self.COLUMN_GROUP_DS, Qt.UserRole).id)
        PluginSettings.set_hide_ds_id_list(hideDSidList)

    def isGroup(self, index):
        childItem = index.internalPointer()
        parentItem = childItem.parent()

        if parentItem == self.rootItem:
            return True

        return False
class GetScriptsAndModelsDialog(BASE, WIDGET):

    HELP_TEXT = QCoreApplication.translate('GetScriptsAndModelsDialog',
                                           '<h3> Processing resources manager </h3>'
                                           '<p>Check/uncheck algorithms in the tree to select the ones that you '
                                           'want to install or remove</p>'
                                           '<p>Algorithms are divided in 3 groups:</p>'
                                           '<ul><li><b>Installed:</b> Algorithms already in your system, with '
                                           'the latest version available</li>'
                                           '<li><b>Updatable:</b> Algorithms already in your system, but with '
                                           'a newer version available in the server</li>'
                                           '<li><b>Not installed:</b> Algorithms not installed in your '
                                           'system</li></ul>')
    MODELS = 0
    SCRIPTS = 1
    RSCRIPTS = 2

    tr_disambiguation = {0: 'GetModelsAction',
                         1: 'GetScriptsAction',
                         2: 'GetRScriptsAction'}

    def __init__(self, resourceType):
        super(GetScriptsAndModelsDialog, self).__init__(iface.mainWindow())
        self.setupUi(self)
        self.manager = QgsNetworkAccessManager.instance()

        repoUrl = ProcessingConfig.getSetting(ProcessingConfig.MODELS_SCRIPTS_REPO)

        self.resourceType = resourceType
        if self.resourceType == self.MODELS:
            self.folder = ModelerUtils.modelsFolders()[0]
            self.urlBase = '{}/models/'.format(repoUrl)
            self.icon = QIcon(os.path.join(pluginPath, 'images', 'model.png'))
        elif self.resourceType == self.SCRIPTS:
            self.folder = ScriptUtils.scriptsFolders()[0]
            self.urlBase = '{}/scripts/'.format(repoUrl)
            self.icon = QIcon(os.path.join(pluginPath, 'images', 'script.png'))
        else:
            self.folder = RUtils.RScriptsFolders()[0]
            self.urlBase = '{}/rscripts/'.format(repoUrl)
            self.icon = QIcon(os.path.join(pluginPath, 'images', 'r.svg'))

        self.lastSelectedItem = None
        self.updateProvider = False
        self.populateTree()
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        self.tree.currentItemChanged.connect(self.currentItemChanged)

    def popupError(self, error=None, url=None):
        """Popups an Error message bar for network errors."""
        disambiguation = self.tr_disambiguation[self.resourceType]
        widget = iface.messageBar().createMessage(self.tr('Connection problem', disambiguation),
                                                  self.tr('Could not connect to scripts/models repository', disambiguation))
        if error and url:
            QgsMessageLog.logMessage(self.tr(u"Network error code: {} on URL: {}").format(error, url), self.tr(u"Processing"), QgsMessageLog.CRITICAL)
            button = QPushButton(QCoreApplication.translate("Python", "View message log"), pressed=show_message_log)
            widget.layout().addWidget(button)

        iface.messageBar().pushWidget(widget, level=QgsMessageBar.CRITICAL, duration=5)

    def grabHTTP(self, url, loadFunction, arguments=None):
        """Grab distant content via QGIS internal classes and QtNetwork."""
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        request = QUrl(url)
        reply = self.manager.get(QNetworkRequest(request))
        if arguments:
            reply.finished.connect(partial(loadFunction, reply, arguments))
        else:
            reply.finished.connect(partial(loadFunction, reply))

    def populateTree(self):
        self.uptodateItem = QTreeWidgetItem()
        self.uptodateItem.setText(0, self.tr('Installed'))
        self.toupdateItem = QTreeWidgetItem()
        self.toupdateItem.setText(0, self.tr('Updatable'))
        self.notinstalledItem = QTreeWidgetItem()
        self.notinstalledItem.setText(0, self.tr('Not installed'))
        self.toupdateItem.setIcon(0, self.icon)
        self.uptodateItem.setIcon(0, self.icon)
        self.notinstalledItem.setIcon(0, self.icon)
        self.grabHTTP(self.urlBase + 'list.txt', self.treeLoaded)

    def treeLoaded(self, reply):
        """
        update the tree of scripts/models whenever
        HTTP request is finished
        """
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            self.popupError(reply.error(), reply.request().url().toString())
        else:
            resources = unicode(reply.readAll()).splitlines()
            resources = [r.split(',') for r in resources]
            self.resources = {f: (v, n) for f, v, n in resources}
            for filename, version, name in sorted(resources, key=lambda kv: kv[2].lower()):
                treeBranch = self.getTreeBranchForState(filename, float(version))
                item = TreeItem(filename, name, self.icon)
                treeBranch.addChild(item)
                if treeBranch != self.notinstalledItem:
                    item.setCheckState(0, Qt.Checked)

        reply.deleteLater()
        self.tree.addTopLevelItem(self.toupdateItem)
        self.tree.addTopLevelItem(self.notinstalledItem)
        self.tree.addTopLevelItem(self.uptodateItem)

        self.txtHelp.setHtml(self.HELP_TEXT)

    def setHelp(self, reply, item):
        """Change the HTML content"""
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            html = self.tr('<h2>No detailed description available for this script</h2>')
        else:
            content = unicode(reply.readAll())
            descriptions = json.loads(content)
            html = '<h2>%s</h2>' % item.name
            html += self.tr('<p><b>Description:</b> %s</p>') % getDescription(ALG_DESC, descriptions)
            html += self.tr('<p><b>Created by:</b> %s') % getDescription(ALG_CREATOR, descriptions)
            html += self.tr('<p><b>Version:</b> %s') % getDescription(ALG_VERSION, descriptions)
        reply.deleteLater()
        self.txtHelp.setHtml(html)

    def currentItemChanged(self, item, prev):
        if isinstance(item, TreeItem):
            url = self.urlBase + item.filename.replace(' ', '%20') + '.help'
            self.grabHTTP(url, self.setHelp, item)
        else:
            self.txtHelp.setHtml(self.HELP_TEXT)

    def getTreeBranchForState(self, filename, version):
        if not os.path.exists(os.path.join(self.folder, filename)):
            return self.notinstalledItem
        else:
            helpFile = os.path.join(self.folder, filename + '.help')
            try:
                with open(helpFile) as f:
                    helpContent = json.load(f)
                    currentVersion = float(helpContent[Help2Html.ALG_VERSION])
            except Exception:
                currentVersion = 0
            if version > currentVersion:
                return self.toupdateItem
            else:
                return self.uptodateItem

    def cancelPressed(self):
        super(GetScriptsAndModelsDialog, self).reject()

    def storeFile(self, reply, filename):
        """store a script/model that has been downloaded"""
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            if os.path.splitext(filename)[1].lower() == '.help':
                content = '{"ALG_VERSION" : %s}' % self.resources[filename[:-5]][0]
            else:
                self.popupError(reply.error(), reply.request().url().toString())
                content = None
        else:
            content = reply.readAll()

        reply.deleteLater()
        if content:
            path = os.path.join(self.folder, filename)
            with open(path, 'w') as f:
                f.write(content)

        self.progressBar.setValue(self.progressBar.value() + 1)

    def okPressed(self):
        toDownload = []
        for i in xrange(self.toupdateItem.childCount()):
            item = self.toupdateItem.child(i)
            if item.checkState(0) == Qt.Checked:
                toDownload.append(item.filename)
        for i in xrange(self.notinstalledItem.childCount()):
            item = self.notinstalledItem.child(i)
            if item.checkState(0) == Qt.Checked:
                toDownload.append(item.filename)

        if toDownload:
            self.progressBar.setMaximum(len(toDownload) * 2)
            for i, filename in enumerate(toDownload):
                QCoreApplication.processEvents()
                url = self.urlBase + filename.replace(' ', '%20')
                self.grabHTTP(url, self.storeFile, filename)

                url += '.help'
                self.grabHTTP(url, self.storeFile, filename + '.help')

        toDelete = []
        for i in xrange(self.uptodateItem.childCount()):
            item = self.uptodateItem.child(i)
            if item.checkState(0) == Qt.Unchecked:
                toDelete.append(item.filename)

        # Remove py and help files if they exist
        for filename in toDelete:
            for pathname in (filename, filename + u".help"):
                path = os.path.join(self.folder, pathname)
                if os.path.exists(path):
                    os.remove(path)

        self.updateProvider = len(toDownload) + len(toDelete) > 0
        super(GetScriptsAndModelsDialog, self).accept()
예제 #3
0
class GetScriptsAndModelsDialog(BASE, WIDGET):

    HELP_TEXT = QCoreApplication.translate('GetScriptsAndModelsDialog',
                                           '<h3> Processing resources manager </h3>'
                                           '<p>Check/uncheck algorithms in the tree to select the ones that you '
                                           'want to install or remove</p>'
                                           '<p>Algorithms are divided in 3 groups:</p>'
                                           '<ul><li><b>Installed:</b> Algorithms already in your system, with '
                                           'the latest version available</li>'
                                           '<li><b>Updatable:</b> Algorithms already in your system, but with '
                                           'a newer version available in the server</li>'
                                           '<li><b>Not installed:</b> Algorithms not installed in your '
                                           'system</li></ul>')
    MODELS = 0
    SCRIPTS = 1

    tr_disambiguation = {0: 'GetModelsAction',
                         1: 'GetScriptsAction'}

    def __init__(self, resourceType):
        super(GetScriptsAndModelsDialog, self).__init__(iface.mainWindow())
        self.setupUi(self)

        if hasattr(self.leFilter, 'setPlaceholderText'):
            self.leFilter.setPlaceholderText(self.tr('Search...'))

        self.manager = QgsNetworkAccessManager.instance()

        repoUrl = ProcessingConfig.getSetting(ProcessingConfig.MODELS_SCRIPTS_REPO)

        self.resourceType = resourceType
        if self.resourceType == self.MODELS:
            self.folder = ModelerUtils.modelsFolders()[0]
            self.urlBase = '{}/models/'.format(repoUrl)
            self.icon = QgsApplication.getThemeIcon("/processingModel.svg")
        elif self.resourceType == self.SCRIPTS:
            self.folder = ScriptUtils.scriptsFolders()[0]
            self.urlBase = '{}/scripts/'.format(repoUrl)
            self.icon = QgsApplication.getThemeIcon("/processingScript.svg")

        self.lastSelectedItem = None
        self.updateProvider = False
        self.data = None

        self.populateTree()
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        self.tree.currentItemChanged.connect(self.currentItemChanged)
        self.leFilter.textChanged.connect(self.fillTree)

    def popupError(self, error=None, url=None):
        """Popups an Error message bar for network errors."""
        disambiguation = self.tr_disambiguation[self.resourceType]
        widget = iface.messageBar().createMessage(self.tr('Connection problem', disambiguation),
                                                  self.tr('Could not connect to scripts/models repository', disambiguation))
        if error and url:
            QgsMessageLog.logMessage(self.tr(u"Network error code: {} on URL: {}").format(error, url), self.tr(u"Processing"), QgsMessageLog.CRITICAL)
            button = QPushButton(QCoreApplication.translate("Python", "View message log"), pressed=show_message_log)
            widget.layout().addWidget(button)

        iface.messageBar().pushWidget(widget, level=QgsMessageBar.CRITICAL, duration=5)

    def grabHTTP(self, url, loadFunction, arguments=None):
        """Grab distant content via QGIS internal classes and QtNetwork."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        request = QUrl(url)
        reply = self.manager.get(QNetworkRequest(request))
        if arguments:
            reply.finished.connect(partial(loadFunction, reply, arguments))
        else:
            reply.finished.connect(partial(loadFunction, reply))

        while not reply.isFinished():
            QCoreApplication.processEvents()

    def populateTree(self):
        self.grabHTTP(self.urlBase + 'list.txt', self.treeLoaded)

    def treeLoaded(self, reply):
        """
        update the tree of scripts/models whenever
        HTTP request is finished
        """
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            self.popupError(reply.error(), reply.request().url().toString())
        else:
            resources = bytes(reply.readAll()).decode('utf8').splitlines()
            resources = [r.split(',', 2) for r in resources]
            self.resources = {f: (v, n) for f, v, n in resources}

        reply.deleteLater()
        self.fillTree()

    def fillTree(self):
        self.tree.clear()

        self.uptodateItem = QTreeWidgetItem()
        self.uptodateItem.setText(0, self.tr('Installed'))
        self.toupdateItem = QTreeWidgetItem()
        self.toupdateItem.setText(0, self.tr('Updatable'))
        self.notinstalledItem = QTreeWidgetItem()
        self.notinstalledItem.setText(0, self.tr('Not installed'))
        self.toupdateItem.setIcon(0, self.icon)
        self.uptodateItem.setIcon(0, self.icon)
        self.notinstalledItem.setIcon(0, self.icon)

        text = str(self.leFilter.text())

        for i in sorted(list(self.resources.keys()), key=lambda kv: kv[2].lower()):
            filename = i
            version = self.resources[filename][0]
            name = self.resources[filename][1]
            treeBranch = self.getTreeBranchForState(filename, float(version))
            if text == '' or text.lower() in filename.lower():
                item = TreeItem(filename, name, self.icon)
                treeBranch.addChild(item)
                if treeBranch != self.notinstalledItem:
                    item.setCheckState(0, Qt.Checked)

        self.tree.addTopLevelItem(self.toupdateItem)
        self.tree.addTopLevelItem(self.notinstalledItem)
        self.tree.addTopLevelItem(self.uptodateItem)

        if text != '':
            self.tree.expandAll()

        self.txtHelp.setHtml(self.HELP_TEXT)

    def setHelp(self, reply, item):
        """Change the HTML content"""
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            html = self.tr('<h2>No detailed description available for this script</h2>')
        else:
            content = bytes(reply.readAll()).decode('utf8')
            try:
                descriptions = json.loads(content)
            except json.decoder.JSONDecodeError:
                html = self.tr('<h2>JSON Decoding Error - could not load help</h2>')
            except Exception:
                html = self.tr('<h2>Unspecified Error - could not load help</h2>')

            html = '<h2>%s</h2>' % item.name
            html += self.tr('<p><b>Description:</b> {0}</p>').format(getDescription(ALG_DESC, descriptions))
            html += self.tr('<p><b>Created by:</b> {0}').format(getDescription(ALG_CREATOR, descriptions))
            html += self.tr('<p><b>Version:</b> {0}').format(getDescription(ALG_VERSION, descriptions))
        reply.deleteLater()
        self.txtHelp.setHtml(html)

    def currentItemChanged(self, item, prev):
        if isinstance(item, TreeItem):
            url = self.urlBase + item.filename.replace(' ', '%20') + '.help'
            self.grabHTTP(url, self.setHelp, item)
        else:
            self.txtHelp.setHtml(self.HELP_TEXT)

    def getTreeBranchForState(self, filename, version):
        if not os.path.exists(os.path.join(self.folder, filename)):
            return self.notinstalledItem
        else:
            helpFile = os.path.join(self.folder, filename + '.help')
            try:
                with open(helpFile) as f:
                    helpContent = json.load(f)
                    currentVersion = float(helpContent[Help2Html.ALG_VERSION])
            except Exception:
                currentVersion = 0
            if version > currentVersion:
                return self.toupdateItem
            else:
                return self.uptodateItem

    def cancelPressed(self):
        super(GetScriptsAndModelsDialog, self).reject()

    def storeFile(self, reply, filename):
        """store a script/model that has been downloaded"""
        QApplication.restoreOverrideCursor()
        if reply.error() != QNetworkReply.NoError:
            if os.path.splitext(filename)[1].lower() == '.help':
                content = '{"ALG_VERSION" : %s}' % self.resources[filename[:-5]][0]
            else:
                self.popupError(reply.error(), reply.request().url().toString())
                content = None
        else:
            content = bytes(reply.readAll()).decode('utf8')

        reply.deleteLater()
        if content:
            path = os.path.join(self.folder, filename)
            with open(path, 'w') as f:
                f.write(content)

        self.progressBar.setValue(self.progressBar.value() + 1)

    def okPressed(self):
        toDownload = []
        for i in range(self.toupdateItem.childCount()):
            item = self.toupdateItem.child(i)
            if item.checkState(0) == Qt.Checked:
                toDownload.append(item.filename)
        for i in range(self.notinstalledItem.childCount()):
            item = self.notinstalledItem.child(i)
            if item.checkState(0) == Qt.Checked:
                toDownload.append(item.filename)

        if toDownload:
            self.progressBar.setMaximum(len(toDownload) * 2)
            for i, filename in enumerate(toDownload):
                QCoreApplication.processEvents()
                url = self.urlBase + filename.replace(' ', '%20')
                self.grabHTTP(url, self.storeFile, filename)

                url += '.help'
                self.grabHTTP(url, self.storeFile, filename + '.help')

        toDelete = []
        for i in range(self.uptodateItem.childCount()):
            item = self.uptodateItem.child(i)
            if item.checkState(0) == Qt.Unchecked:
                toDelete.append(item.filename)

        # Remove py and help files if they exist
        for filename in toDelete:
            for pathname in (filename, filename + u".help"):
                path = os.path.join(self.folder, pathname)
                if os.path.exists(path):
                    os.remove(path)

        self.updateProvider = len(toDownload) + len(toDelete) > 0
        super(GetScriptsAndModelsDialog, self).accept()