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))