예제 #1
0
class PinStatusWidget(GalacteekTab):
    COL_TS = 0
    COL_QUEUE = 1
    COL_PATH = 2
    COL_STATUS = 3
    COL_PROGRESS = 4
    COL_CTRL = 5

    def __init__(self, gWindow, **kw):
        super(PinStatusWidget, self).__init__(gWindow, **kw)

        self.tree = QTreeView()
        self.tree.setObjectName('pinStatusWidget')
        self.boxLayout = QVBoxLayout()
        self.boxLayout.addWidget(self.tree)

        self.ctrlLayout = QHBoxLayout()
        self.btnPin = QPushButton(iPin())
        self.pathLabel = QLabel(iCidOrPath())
        self.pathEdit = QLineEdit()
        self.ctrlLayout.addWidget(self.pathLabel)
        self.ctrlLayout.addWidget(self.pathEdit)
        self.ctrlLayout.addWidget(self.btnPin)
        self.vLayout.addLayout(self.ctrlLayout)
        self.vLayout.addLayout(self.boxLayout)

        self.app.ipfsCtx.pinItemStatusChanged.connect(self.onPinStatusChanged)
        self.app.ipfsCtx.pinFinished.connect(self.onPinFinished)
        self.app.ipfsCtx.pinItemRemoved.connect(self.onItemRemoved)
        self.pathEdit.returnPressed.connect(self.onPathEntered)
        self.btnPin.clicked.connect(self.onPathEntered)

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(
            ['TS', iQueue(),
             iPath(),
             iStatus(),
             iNodesProcessed(), ''])

        self.tree.setSortingEnabled(True)
        self.tree.setModel(self.model)
        self.tree.sortByColumn(self.COL_TS, Qt.DescendingOrder)

        for col in [self.COL_QUEUE, self.COL_PATH, self.COL_PROGRESS]:
            self.tree.header().setSectionResizeMode(
                col, QHeaderView.ResizeToContents)

        self.tree.hideColumn(self.COL_TS)

    def resort(self):
        self.model.sort(self.COL_TS, Qt.DescendingOrder)

    def onPathEntered(self):
        text = self.pathEdit.text()
        self.pathEdit.clear()

        path = IPFSPath(text)
        if path.valid:
            ensure(self.app.ipfsCtx.pinner.queue(path.objPath, True, None))
        else:
            messageBox(iInvalidInput())

    def removeItem(self, path):
        modelSearch(self.model,
                    search=path,
                    columns=[self.COL_PATH],
                    delete=True)

    def onItemRemoved(self, qname, path):
        self.removeItem(path)

    def getIndexFromPath(self, path):
        idxList = self.model.match(self.model.index(0, self.COL_PATH),
                                   PinObjectPathRole, path, 1,
                                   Qt.MatchFixedString | Qt.MatchWrap)
        if len(idxList) > 0:
            return idxList.pop()

    def findPinItems(self, path):
        idx = self.getIndexFromPath(path)

        if not idx:
            return None

        itemP = self.model.itemFromIndex(idx)

        if not itemP:
            return None

        idxQueue = self.model.index(itemP.row(), self.COL_QUEUE,
                                    itemP.index().parent())
        idxProgress = self.model.index(itemP.row(), self.COL_PROGRESS,
                                       itemP.index().parent())
        idxStatus = self.model.index(itemP.row(), self.COL_STATUS,
                                     itemP.index().parent())
        idxC = self.model.index(itemP.row(), self.COL_CTRL,
                                itemP.index().parent())
        cancelButton = self.tree.indexWidget(idxC)

        return {
            'itemPath': itemP,
            'itemQname': self.model.itemFromIndex(idxQueue),
            'itemProgress': self.model.itemFromIndex(idxProgress),
            'itemStatus': self.model.itemFromIndex(idxStatus),
            'cancelButton': cancelButton
        }

    def updatePinStatus(self, path, status, progress):
        idx = self.getIndexFromPath(path)
        if not idx:
            return

        try:
            itemPath = self.model.itemFromIndex(idx)
            if itemPath and time.time() - itemPath.lastProgressUpdate < 5:
                return

            itemProgress = self.model.itemFromIndex(
                self.model.index(idx.row(), self.COL_PROGRESS, idx.parent()))

            itemStatus = self.model.itemFromIndex(
                self.model.index(idx.row(), self.COL_STATUS, idx.parent()))

            itemStatus.setText(status)
            itemProgress.setText(progress)
            itemPath.lastProgressUpdate = time.time()
        except:
            pass

    def onPinFinished(self, path):
        items = self.findPinItems(path)

        if items:
            items['itemStatus'].setText(iPinned())
            items['itemProgress'].setText('OK')

            color1 = QBrush(QColor('#4a9ea1'))
            color2 = QBrush(QColor('#66a56e'))

            for item in [
                    items['itemQname'], items['itemPath'], items['itemStatus'],
                    items['itemProgress']
            ]:
                item.setBackground(color1)

            for item in [items['itemStatus'], items['itemProgress']]:
                item.setBackground(color2)

            if items['cancelButton']:
                items['cancelButton'].setEnabled(False)

        self.resort()
        self.purgeFinishedItems()

    def purgeFinishedItems(self):
        maxFinished = 16
        ret = modelSearch(self.model,
                          search=iPinned(),
                          columns=[self.COL_STATUS])

        if len(ret) > maxFinished:
            rows = []
            for idx in ret:
                item = self.model.itemFromIndex(idx)
                if not item:
                    continue
                rows.append(item.row())

            try:
                for row in list(sorted(rows))[int(maxFinished / 2):]:
                    self.model.removeRow(row)
            except:
                pass

    async def onCancel(self, qname, path, *a):
        self.removeItem(path)
        await self.app.ipfsCtx.pinner.cancel(qname, path)

    def onPinStatusChanged(self, qname, path, statusInfo):
        nodesProcessed = statusInfo['status'].get('Progress', iUnknown())

        idx = self.getIndexFromPath(path)

        if not idx:
            # Register it
            btnCancel = QToolButton()
            btnCancel.setIcon(getIcon('cancel.png'))
            btnCancel.setText(iCancel())
            btnCancel.clicked.connect(partialEnsure(self.onCancel, qname,
                                                    path))
            btnCancel.setFixedWidth(140)

            displayPath = path
            if len(displayPath) > 64:
                displayPath = displayPath[0:64] + ' ..'

            itemTs = UneditableItem(str(statusInfo['ts_queued']))
            itemQ = UneditableItem(qname)
            itemP = UneditableItem(displayPath)
            itemP.setData(path, PinObjectPathRole)
            itemP.setToolTip(path)
            itemP.lastProgressUpdate = time.time()

            itemStatus = UneditableItem(iPinning())
            itemProgress = UneditableItem(str(nodesProcessed))

            itemC = UneditableItem('')

            self.model.invisibleRootItem().appendRow(
                [itemTs, itemQ, itemP, itemStatus, itemProgress, itemC])
            idx = self.model.indexFromItem(itemC)
            self.tree.setIndexWidget(idx, btnCancel)
            self.resort()
        else:
            self.updatePinStatus(path, iPinning(), str(nodesProcessed))