def __init__(self, database, main_spectrum = None): super(ReferenceSpectraDialog, self).__init__() self.main_spectrum = main_spectrum self.ui = Ui_ReferenceSpectraDialog() self.ui.setupUi(self) self.reference_catalogues = ReferenceCatalogues(database) self.full_model = QStandardItemModel() self.catalogues_model = QStandardItemModel() self.ui.catalogue.setModel(self.catalogues_model) self.ui.catalogue.currentTextChanged.connect(lambda txt: self.populate()) for catname, cat in self.reference_catalogues.catalogues.items(): row = QStandardItem(catname) row.setData(cat) self.catalogues_model.appendRow(row) self.model = QSortFilterProxyModel() self.model.setSourceModel(self.full_model) self.model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.model.setFilterKeyColumn(0) self.ui.entries.setModel(self.model) self.ui.type_filter.currentTextChanged.connect(lambda txt: self.model.setFilterWildcard("{}*".format(txt) ) ) self.ui.buttonBox.button(QDialogButtonBox.Open).setEnabled(False) self.ui.entries.selectionModel().selectionChanged.connect(lambda selected, deselected: self.ui.buttonBox.button(QDialogButtonBox.Open).setEnabled(len(selected.indexes()) > 0) ) self.accepted.connect(self.load_fits) self.populate()
def on_add_group(self): """ Create a popup dialog that has a single list view of all the groups that are not yet added. """ # figure out who is added. groups_added = set() model = self.groupsListView.model() for i in range(model.rowCount()): groups_added.add(model.data(model.index(i, 0), Qt.UserRole)) # Add rows for each unadded group model = QStandardItemModel() for g in Groups: if g in groups_added: continue model.appendRow(GroupItem(g)) dialog = GetItemDialog( title="Choose a Group to Add", labelText="Groups", createText="Create a new Group", new_dialog_cls=CreateGroupWidget, item_cls=GroupItem, model=model ) if dialog.exec() == QDialog.Accepted: model = self.groupsListView.model() model.appendRow(GroupItem(dialog.selection))
class ConfigTableViewWidget(QDialog, Ui_ConfigTableViewWidget): """ Class documentation goes here. """ def __init__(self, availableScalars, scalarsToShow, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super().__init__(parent) self.setupUi(self) self.ValueListModel = QStandardItemModel() for value in availableScalars: item = QStandardItem(value) check = Qt.Checked if value in scalarsToShow else Qt.Unchecked item.setCheckState(check) item.setCheckable(True) self.ValueListModel.appendRow(item) self.ValueListView.setModel(self.ValueListModel) def setVisibleValues(self): setVisible = [] for row in range(self.ValueListModel.rowCount()): item = self.ValueListModel.item(row) if item.checkState() == Qt.Checked: setVisible.append(item.text()) return setVisible
class FileListView(QListView): def __init__(self): super().__init__() self.setEditTriggers(QAbstractItemView.NoEditTriggers) """画像ファイル抽出&リスト追加処理""" def addFiles(self, files): itemCount = 0 imageFiles = [] self.model = QStandardItemModel() for file in files: if self.__isImage(file): imageFiles.append(file) item = QStandardItem(file) if itemCount % 2 == 0: item.setBackground(QBrush(QColor(221, 222, 211))) self.model.appendRow(QStandardItem(item)) itemCount += 1 if itemCount == 0: QMessageBox.information(None, "No Image Files!", "指定ディレクトリには画像がありません。") self.setModel(self.model) return imageFiles """画像ファイル選別処理(拡張子より選別)""" def __isImage(self, file): ext = os.path.splitext(file)[1].lower() return ext in [".jpg", ".jpeg", ".png", ".gif"]
def __init__(self, parent=None): super(UniverseTreeView, self).__init__(parent) model = QStandardItemModel() self.setModel(model) root_item = model.invisibleRootItem() self.areas_item = QStandardItem("Areas") self.areas_item.setData(Areas, Qt.UserRole) self.areas_item.setEditable(False) root_item.appendRow(self.areas_item) Areas.added.connect(self.init_areas) Areas.removed.connect(self.init_areas) Areas.reset.connect(self.init_areas) self.characters_item = QStandardItem("Characters") self.characters_item.setData(Characters, Qt.UserRole) self.characters_item.setEditable(False) root_item.appendRow(self.characters_item) Characters.added.connect(self.init_characters) Characters.removed.connect(self.init_characters) Characters.reset.connect(self.init_characters) self.races_item = QStandardItem("Races") self.races_item.setEditable(False) self.races_item.setData(Races, Qt.UserRole) root_item.appendRow(self.races_item) Races.added.connect(self.init_races) Races.removed.connect(self.init_races) Races.reset.connect(self.init_races) self.item_prototypes_item = QStandardItem("Item Prototypes") self.item_prototypes_item.setData(ItemPrototypes, Qt.UserRole) self.item_prototypes_item.setEditable(False) root_item.appendRow(self.item_prototypes_item) ItemPrototypes.added.connect(self.init_item_prototypes) ItemPrototypes.removed.connect(self.init_item_prototypes) ItemPrototypes.reset.connect(self.init_item_prototypes) self.groups_item = QStandardItem("Groups") self.groups_item.setData(Groups, Qt.UserRole) self.groups_item.setEditable(False) root_item.appendRow(self.groups_item) Groups.added.connect(self.init_groups) Groups.removed.connect(self.init_groups) Groups.reset.connect(self.init_groups) self.init_all() self.activated.connect(self.item_activated)
def main(args): def split_and_strip(s, splitter): return [s.strip() for s in line.split(splitter)] app = QApplication(args) model = QStandardItemModel() file = QFile(QFileInfo(__file__).absolutePath() + '/grades.txt') if file.open(QFile.ReadOnly): line = file.readLine(200).decode('utf-8') header = split_and_strip(line, ',') model.setHorizontalHeaderLabels(header) row = 0 while file.canReadLine(): line = file.readLine(200).decode('utf-8') if not line.startswith('#') and ',' in line: fields = split_and_strip(line, ',') for col, field in enumerate(fields): newItem = QStandardItem(field) model.setItem(row, col, newItem) row += 1 file.close() tableView = FreezeTableWidget(model) tableView.setWindowTitle("Frozen Column Example") tableView.resize(560, 680) tableView.show() return app.exec_()
def onFileDropped(self, filename): filename = parse.unquote(filename) if filename.startswith('file:/'): filename = filename[6:] print(filename) if os.path.isfile(filename) is not True: return tree = ET.parse(filename) root = tree.getroot() self.currentDict = XmlDictConfig(root) ''' QList<QStandardItem *> preparedRow =prepareRow("first", "second", "third"); QStandardItem *item = standardModel->invisibleRootItem(); // adding a row to the invisible root item produces a root element item->appendRow(preparedRow); QList<QStandardItem *> secondRow =prepareRow("111", "222", "333"); // adding a row to an item starts a subtree preparedRow.first()->appendRow(secondRow); treeView->setModel(standardModel); treeView->expandAll(); ''' standardModel = QStandardItemModel() preparedRow = (QStandardItem("Title"), QStandardItem("Description")) item = standardModel.invisibleRootItem() item.appendRow(preparedRow) self.addDictTree(self.currentDict, item) self.contents.setModel(standardModel) self.contents.expandAll() print("dict reading finished")
def setupModel(self): self.model = QStandardItemModel(3, 2, self) self.model.setHeaderData(0, Qt.Horizontal, "목록") self.model.setHeaderData(1, Qt.Horizontal, "읽기여부") self.model2 = QStandardItemModel(3, 2, self) self.model2.setHeaderData(0, Qt.Horizontal, "학습여부") self.model2.setHeaderData(1, Qt.Horizontal, "개수")
class FileInspector(QTreeView): """docstring for FileInspector""" def __init__(self, parent=None): super(FileInspector, self).__init__(parent) self.model = QStandardItemModel(self) self.setModel(self.model) self.file_info = None header = QStandardItem('') self.model.setHorizontalHeaderItem(0, header) def populate(self, file_info=None, db_file=None): if file_info is not None: self.file_info = file_info db_file = FileInspectorHelper.get_or_insert_file(file_info) self.model.clear() if db_file: for classe in db_file.classes: parent = QStandardItem("{0}:".format(classe.name)) for method in classe.methods: parent.appendRow(QStandardItem("{0}()".\ format(method.name))) self.model.appendRow(parent) for function in db_file.functions: self.model.appendRow(QStandardItem("{0}()".\ format(function.name))) name = db_file.name if db_file else file_info.fileName() header = QStandardItem(name) self.model.setHorizontalHeaderItem(0, header) self.expandAll() @pyqtSlot(QFileInfo) def onFileItemActivated(self, file_info): self.populate(file_info)
def test_replace_tape_widget_should_destroy_old_tape_and_put_a_new_one_on_the_panel(self): old_tape_widget = self.window.tape_widget assert isinstance(old_tape_widget, TapeWidget) assert self.window.centralWidget() == old_tape_widget old_tape_widget.add_note() old_tape_widget.add_note() old_note1 = item_to_note(old_tape_widget.model().item(0)) old_note2 = item_to_note(old_tape_widget.model().item(1)) new_note = Note( body = "Y", tags = ["Z"], created_at = datetime.utcnow() ) new_model = QStandardItemModel() new_item = QStandardItem() set_item_note(new_item, new_note) new_model.appendRow(new_item) self.window._replace_tape_widget(new_model) self.assertTrue(isinstance(self.window.tape_widget, TapeWidget)) self.assertNotEqual(self.window.tape_widget, old_tape_widget) self.assertEqual(len(list(self.window.tape_widget.notes())), 1) self.assertEqual(self.window.tape_widget.model(), new_model) self.assertEqual(item_to_note(self.window.tape_widget.model().item(0)), new_note) self.assertTrue(self.window.centralWidget() == self.window.tape_widget)
def __init__(self, database, settings, plot_widget, axes = None, enable_picker = True, selection_mode = 'multi'): super(LinesDialog, self).__init__() self.axes = axes if axes else plot_widget.axes self.database = database self.plot_widget = plot_widget self.settings = settings self.ui = Ui_LinesDialog() self.ui.setupUi(self) self.restoreGeometry(self.settings.value('pick_lines_geometry', QByteArray())) self.model = QStandardItemModel() self.elements_model = QStandardItemModel() self.ui.lines.setModel(self.model) self.ui.elements.setModel(self.elements_model) c = self.database.cursor() self.elements_model.appendRow(LinesDialog.__element_item([0, '', 'All'])) elements = c.execute("SELECT z, code, name FROM elements ORDER BY z ASC") for element in elements: self.elements_model.appendRow(LinesDialog.__element_item(element)) self.ui.elements.currentTextChanged.connect(lambda t: self.populate()) self.ui.lambda_from.editingFinished.connect(self.populate) self.ui.name.editingFinished.connect(self.populate) self.ui.sp_types.toggled.connect(self.populate) self.ui.lambda_to.editingFinished.connect(self.populate) self.accepted.connect(self.collect_selected_lines) self.populate() self.ui.pick_wavelengths.setEnabled(enable_picker) self.ui.pick_wavelengths.clicked.connect(self.pick_wavelengths_clicked) self.ui.lines.setSelectionMode({'multi':QTableView.MultiSelection, 'single':QTableView.SingleSelection}[selection_mode])
def __init_tree_view(self): self.__treeView = QTreeView() self.__treeView.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) rect = self.__treeView.geometry() rect.setWidth(self.__WINDOW_WIDTH / 4) self.__treeView.setGeometry(rect) model = QStandardItemModel() model.setHorizontalHeaderItem(0, QStandardItem(self.__DATABASE)) self.__treeView.setModel(model)
def __init__(self, stack, references, stackname, settings, getcri, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super().__init__(parent) self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) self.originalStack = stack self.stack = copy.deepcopy(stack) self.references = references self.StackName = stackname self.settings = settings self.getCRI = getcri self.referenceDataSelected = {} self.referenceList = [] for key, value in self.references.items(): if value[0]: self.referenceList.append([key, False]) # name and selection for fitting self.referenceListModel = QStandardItemModel() self.referenceListModel.itemChanged.connect(self.updateReferences) self.referenceListView.setModel(self.referenceListModel) self.fillReferences() self.parameterModel = QStandardItemModel() #TreeOfParametersModel() self.parameterTreeView.setModel(self.parameterModel) self.parameterModel.setHorizontalHeaderLabels(['Parameter', 'Value']) self.root = self.parameterModel.invisibleRootItem() self.fillParameterTree() # configurations self.noOfFitIterations = 100 methods = ['Nelder-Mead', 'Powell', 'CG', 'BFGS', 'L-BFGS-B', 'TNC', 'COBYLA', 'SLSQP'] self.tolerance = 1e-3 # with Jacobian necessary: 'Newton-CG', 'dogleg', 'trust-ncg' self.configuration = dict([ ('method', methods[0]), ('noOfIterations', self.noOfFitIterations), ('tolerance', self.tolerance), ('plotInBetween', True) ]) self.methodCB.addItems(methods) self.noOfIterationsSB.setValue(self.noOfFitIterations) self.toleranceSB.setValue(self.tolerance) try: self.runOptics() except: self.done(0) QMessageBox.warning(self, "error", 'Error - could not calculate current stack.\nPlease check stack definition until simple simulation is running.', QMessageBox.StandardButtons(QMessageBox.Close))
def _get_config_model(): data = DataStorage() configurations_order = data.get_configurations_order() model = QStandardItemModel() for name in configurations_order: item = create_new_list_item(name) model.appendRow(item) return model
def __init__(self, networkAccessManager, parent=None): """ Constructor @param networkAccessManager reference to the network access manager (QNetworkAccessManager) @param parent reference to the parent widget (QWidget) """ super(E5NetworkMonitor, self).__init__(parent) self.setupUi(self) self.setWindowFlags(Qt.Window) self.__requestHeaders = QStandardItemModel(self) self.__requestHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.requestHeadersList.setModel(self.__requestHeaders) self.requestHeadersList.horizontalHeader().setStretchLastSection(True) self.requestHeadersList.doubleClicked.connect(self.__showHeaderDetails) self.__replyHeaders = QStandardItemModel(self) self.__replyHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.responseHeadersList.setModel(self.__replyHeaders) self.responseHeadersList.horizontalHeader().setStretchLastSection(True) self.responseHeadersList.doubleClicked.connect( self.__showHeaderDetails) self.requestsList.horizontalHeader().setStretchLastSection(True) self.requestsList.verticalHeader().setMinimumSectionSize(-1) self.__proxyModel = QSortFilterProxyModel(self) self.__proxyModel.setFilterKeyColumn(-1) self.searchEdit.textChanged.connect( self.__proxyModel.setFilterFixedString) self.removeButton.clicked.connect(self.requestsList.removeSelected) self.removeAllButton.clicked.connect(self.requestsList.removeAll) self.__model = E5RequestModel(networkAccessManager, self) self.__proxyModel.setSourceModel(self.__model) self.requestsList.setModel(self.__proxyModel) self.__proxyModel.rowsInserted.connect( self.requestsList.scrollToBottom) self.requestsList.selectionModel()\ .currentChanged[QModelIndex, QModelIndex]\ .connect(self.__currentChanged) fm = self.fontMetrics() em = fm.width("m") self.requestsList.horizontalHeader().resizeSection(0, em * 5) self.requestsList.horizontalHeader().resizeSection(1, em * 20) self.requestsList.horizontalHeader().resizeSection(3, em * 5) self.requestsList.horizontalHeader().resizeSection(4, em * 15) self.__headersDlg = None
def set_data(self): group = self.obj self.setWindowTitle("{} (Group)".format(group.name)) self.nameValueLabel.setText(group.name) model = QStandardItemModel() self.charactersListView.setModel(model) for c in group.characters: item = CharacterItem(c) model.appendRow(item)
def createModel(parent,rows,cols,colNames): model=QStandardItemModel(rows, cols+1, parent) i=0 for c in colNames: model.setHeaderData(i, Qt.Horizontal, c) i+=1 proxyModel=QSortFilterProxyModel() proxyModel.setDynamicSortFilter(True) proxyModel.setSourceModel(model) proxyModel.setFilterKeyColumn(0) return proxyModel
def set_table_data(self, data): table_model = QStandardItemModel() table_model.setHorizontalHeaderLabels(['Keyword', 'Count']) for row in data: qrow = [] for item in row: qitem = QStandardItem(str(item)) qrow.append(qitem) table_model.appendRow(qrow) self.table.setModel(table_model) self.table.resizeColumnsToContents() self.table.resizeRowsToContents()
def fillUserList(newUser=None): model = QStandardItemModel() mylist = ['asd', 'wqe', 'wqra', 'tewt4'] if newUser: mylist += newUser print(mylist) for item in mylist: myitem = QStandardItem(item) myitem.setEditable(0) model.appendRow(myitem) myapp.listView.setModel(model) myapp.listView.doubleClicked.connect(openConversationWindow)
class SettingWindow(QWidget): # on_addButtonClicked=pyqtSignal() # on_removeButtonClicked=pyqtSignal() # on_okButtonClicked=pyqtSignal() finished=pyqtSignal() def __init__(self): QWidget.__init__(self) self.listview=QListView(self) self.addButton=QPushButton(self) self.removeButton=QPushButton(self) self.resize(630,440) self.okButton=QPushButton(self) self.listview.setGeometry(30,30,410,351) self.addButton.setGeometry(490,40,80,22) self.addButton.setText("add") self.addButton.clicked.connect(self.click_add) self.removeButton.setGeometry(490,80,80,22) self.removeButton.setText("remove") self.removeButton.clicked.connect(self.click_remove) self.okButton.setGeometry(490,150,80,22) self.okButton.setText("ok") self.okButton.clicked.connect(self.click_ok) # self.aw=null self.fresh() def click_ok(self): self.finished.emit() self.close() def click_add(self): self.aw=AddWindow() self.aw.show() self.aw.okSig.connect(self.fresh) def click_remove(self): self.remove() def fresh(self): confFile=open("conf","r") self.listModel=QStandardItemModel() self.itemList=cPickle.load(confFile) confFile.close() for item in self.itemList: itemView=QStandardItem(QIcon(item.path),item.name) itemView.setEditable(False) self.listModel.appendRow(itemView) self.listview.setModel(self.listModel) def remove(self): index=self.listview.currentIndex().row() self.itemList.pop(index) self.listModel.removeRow(index) confFile=open("conf","w") cPickle.dump(self.itemList,confFile) confFile.close()
def createModel(self): model = QStandardItemModel(0, 3) model.setHeaderData(0, Qt.Horizontal, "Name") model.setHeaderData(1, Qt.Horizontal, "Phone") model.setHeaderData(2, Qt.Horizontal, "Address") model.setHeaderData(3, Qt.Horizontal, "") return model
def create_table(self, rela): table = custom_table.Table() model = QStandardItemModel() table.setModel(model) model.setHorizontalHeaderLabels(rela.header) for row_count, row in enumerate(rela.content): for col_count, data in enumerate(row): item = QStandardItem(data) item.setFlags(item.flags() & ~Qt.ItemIsEditable) model.setItem(row_count, col_count, item) return table
def data(self, index, role=Qt.DisplayRole): if index.parent().isValid() and \ index.parent().column() == Plot.steps and \ index.column() == PlotStep.meta: if role == Qt.TextAlignmentRole: return Qt.AlignRight | Qt.AlignVCenter elif role == Qt.ForegroundRole: return QBrush(Qt.gray) else: return QStandardItemModel.data(self, index, role) else: return QStandardItemModel.data(self, index, role)
def __init__(self, parent=None): super(UniverseTreeView, self).__init__(parent) model = QStandardItemModel() self.setModel(model) root_item = model.invisibleRootItem() self.characters_item = QStandardItem("Characters") self.characters_item.setEditable(False) self.races_item = QStandardItem("Races") self.races_item.setEditable(False) self.skills_item = QStandardItem("Skills") self.skills_item.setEditable(False) self.personalities_item = QStandardItem("Personalities") self.personalities_item.setEditable(False) self.backgrounds_item = QStandardItem("Backgrounds") self.backgrounds_item.setEditable(False) root_item.appendRow(self.characters_item) root_item.appendRow(self.races_item) root_item.appendRow(self.skills_item) root_item.appendRow(self.personalities_item) root_item.appendRow(self.backgrounds_item) self.init_all() GlobalData.character_added.connect(self.init_characters) GlobalData.character_removed.connect(self.init_characters) GlobalData.characters_reset.connect(self.init_characters) GlobalData.race_added.connect(self.init_races) GlobalData.race_removed.connect(self.init_races) GlobalData.races_reset.connect(self.init_races) GlobalData.skill_added.connect(self.init_skills) GlobalData.skill_removed.connect(self.init_skills) GlobalData.skills_reset.connect(self.init_skills) GlobalData.personality_added.connect(self.init_personalities) GlobalData.personality_removed.connect(self.init_personalities) GlobalData.personalities_reset.connect(self.init_personalities) GlobalData.background_added.connect(self.init_backgrounds) GlobalData.background_removed.connect(self.init_backgrounds) GlobalData.backgrounds_reset.connect(self.init_backgrounds) self.activated.connect(self.item_activated)
class RefsUI(object): def __init__(self, window, uaclient): self.window = window self.uaclient = uaclient self.model = QStandardItemModel() self.window.ui.refView.setModel(self.model) self.window.ui.refView.horizontalHeader().setSectionResizeMode(1) self.window.ui.treeView.activated.connect(self.show_refs) self.window.ui.treeView.clicked.connect(self.show_refs) def clear(self): self.model.clear() def show_refs(self, idx): node = self.window.get_current_node(idx) self.model.clear() if node: self._show_refs(node) def _show_refs(self, node): self.model.setHorizontalHeaderLabels(['ReferenceType', 'NodeId', "BrowseName", "TypeDefinition"]) try: refs = self.uaclient.get_all_refs(node) except Exception as ex: self.window.show_error(ex) raise for ref in refs: self.model.appendRow([QStandardItem(str(ref.ReferenceTypeId)), QStandardItem(str(ref.NodeId)), QStandardItem(str(ref.BrowseName)), QStandardItem(str(ref.TypeDefinition))])
def test_set_model_replace_the_model_with_a_new_one(self): new_model = QStandardItemModel() item = QStandardItem() set_item_note(item, self.notes[0]) new_model.appendRow(item) assert self.tape_widget.model().rowCount() == 0 self.tape_widget.set_model(new_model) self.assertEqual(self.tape_widget.model(), new_model) self.assertEqual(self.tape_widget.proxy_model().sourceModel(), new_model) self.assertEqual(self.tape_widget.model().rowCount(), 1) self.assertEqual(self.tape_widget.model().item(0, 0), item)
def setup_table(self, rela): # Table model model = QStandardItemModel() self.table.setModel(model) # Set header model.setHorizontalHeaderLabels(rela.header) # Populate table for row_count, row in enumerate(rela.content): for col_count, data in enumerate(row): item = QStandardItem() item.setText(data) item.setToolTip(data) model.setItem(row_count, col_count, item)
class ListCategory(QSortFilterProxyModel): """Expose a list of items as a category for the CompletionModel.""" def __init__(self, name, items, delete_func=None, parent=None): super().__init__(parent) self.name = name self.srcmodel = QStandardItemModel(parent=self) self._pattern = '' # ListCategory filters all columns self.columns_to_filter = [0, 1, 2] self.setFilterKeyColumn(-1) for item in items: self.srcmodel.appendRow([QStandardItem(x) for x in item]) self.setSourceModel(self.srcmodel) self.delete_func = delete_func def set_pattern(self, val): """Setter for pattern. Args: val: The value to set. """ self._pattern = val val = re.sub(r' +', r' ', val) # See #1919 val = re.escape(val) val = val.replace(r'\ ', '.*') rx = QRegExp(val, Qt.CaseInsensitive) self.setFilterRegExp(rx) self.invalidate() sortcol = 0 self.sort(sortcol) def lessThan(self, _lindex, rindex): """Custom sorting implementation. Prefers all items which start with self._pattern. Other than that, keep items in their original order. Args: _lindex: The QModelIndex of the left item (*left* < right) rindex: The QModelIndex of the right item (left < *right*) Return: True if left < right, else False """ qtutils.ensure_valid(rindex) right = self.srcmodel.data(rindex) return not right.startswith(self._pattern)
def __init__(self, parent=None): super(MDIHistory, self).__init__(parent) self.setMinimumSize(QSize(300, 200)) self.setWindowTitle("PyQt5 editor test example") lay = QVBoxLayout() lay.setContentsMargins(0,0,0,0) self.setLayout(lay) self.list = QListView() self.list.setEditTriggers(QListView.NoEditTriggers) self.list.activated.connect(self.activated) self.list.setAlternatingRowColors(True) self.list.selectionChanged = self.selectionChanged self.model = QStandardItemModel(self.list) self.MDILine = MDILine() self.MDILine.soft_keyboard = False self.MDILine.line_up = self.line_up self.MDILine.line_down = self.line_down # add widgets lay.addWidget(self.list) lay.addWidget(self.MDILine) self.reload()
def __init__(self, parentWidget): QWidget.__init__(self, parentWidget) self.editorWidget = parentWidget.editorWidget # TODO: Review class structure self.searching = False self.ui = Ui_SearchWidget() self.ui.setupUi(self) self.resultListModel = QStandardItemModel(self.ui.resultList) self.ui.resultWidget.setCurrentIndex(0) self.ui.resultList.setModel(self.resultListModel) self.ui.resultList.selectionModel().selectionChanged.connect(self.doResultSelected) self.startIcon = QIcon(':/icons/search-global-start.png') self.stopIcon = QIcon(':/icons/search-global-stop.png') self.ui.startStopButton.setIcon(self.startIcon) self.ui.searchInput.returnPressed.connect(self.doReturnKey) self.ui.startStopButton.clicked.connect(self.doStartStopButton) self.workerThread = QThread() self.worker = SearchWorker() self.worker.moveToThread(self.workerThread) self.startWork.connect(self.worker.startSearch) self.worker.searchDone.connect(self.searchDone) self.worker.addMatch.connect(self.addMatch) # self.stopWork.connect(self.worker.stopSearch) self.workerThread.start()
class ElfInfo(DwarfDialog): onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None, file_path=None): super().__init__(parent=parent) h_box = QHBoxLayout(self) self._ident_titles = ['EI_MAG0', 'EI_MAG1', 'EI_MAG2', 'EI_MAG3', 'EI_CLASS', 'EI_DATA', 'EI_VERSION', 'EI_OSABI', 'EI_ABIVERSION', 'EI_PAD'] self.elf_info = DwarfListView(self) self.elf_info.setRootIsDecorated(True) self.elf_info.setExpandsOnDoubleClick(True) self.elf_info.setContextMenuPolicy(Qt.CustomContextMenu) self.elf_info.customContextMenuRequested.connect(self._on_context_menu) h_box.addWidget(self.elf_info) self._elf_info_mdl = QStandardItemModel(0, 2) self._elf_info_mdl.setHeaderData(0, Qt.Horizontal, 'Name') self._elf_info_mdl.setHeaderData(1, Qt.Horizontal, 'Value') self.elf_info.setModel(self._elf_info_mdl) self.elf_info.doubleClicked.connect(self._on_dblclicked) self.title = "ELF Info" self._elf_file_path = None self.setLayout(h_box) if file_path: self.set_elf_file(file_path) def set_elf_file(self, file_path): self._elf_file_path = file_path self.title = 'ELF Info for ' + file_path self._elf_info_mdl.insertRow(0, [QStandardItem('File'), QStandardItem(file_path)]) def set_parsed_data(self, parsed_data): parent_item = self._elf_info_mdl.item(0) if 'endian' in parsed_data: parent_item.appendRow([QStandardItem('Endian'), QStandardItem(parsed_data['endian'])]) if 'is64bit' in parsed_data: txt = 'No' if parsed_data['is64bit']: txt = 'Yes' parent_item.appendRow([QStandardItem('64Bit'), QStandardItem(txt)]) if 'header' in parsed_data: elf_header = QStandardItem('ELF Header') parent_item.appendRow([elf_header]) for d in parsed_data['header']: if d == 'e_ident': ident_item = QStandardItem(d) elf_header.appendRow([ident_item, QStandardItem(str(parsed_data['header'][d]))]) a = 0 for i in parsed_data['header'][d]: if a >= len(self._ident_titles): a = len(self._ident_titles) - 1 ident_item.appendRow([QStandardItem(self._ident_titles[a]), QStandardItem(str(i))]) a += 1 else: elf_header.appendRow([QStandardItem(d), QStandardItem(hex(parsed_data['header'][d]))]) if 'programheaders' in parsed_data: prog_headers_item = QStandardItem('Program Headers') parent_item.appendRow([prog_headers_item]) i = 1 for header in parsed_data['programheaders']: header_item = QStandardItem("%d" % i) prog_headers_item.appendRow([header_item]) i += 1 for d in header: header_item.appendRow([QStandardItem(d), QStandardItem(hex(header[d]))]) if 'sectionheaders' in parsed_data: sect_headers = QStandardItem('Section Headers') parent_item.appendRow([sect_headers]) i = 1 for header in parsed_data['sectionheaders']: txt = header['name'] if not txt: txt = 'NULL' header_item = QStandardItem(txt) sect_headers.appendRow([header_item]) i += 1 for d in header: if d == 'name': continue elif d == 'data' and header[d]: data_item = QStandardItem('Data') header_item.appendRow(data_item) base = self.parent().dwarf.dwarf_api('findModule', self._elf_file_path)['base'] for ptr in header[d]: if int(ptr): va = hex(int(base, 16) + int(ptr)) fo = hex(int(ptr)) if self.elf_info.uppercase_hex: va = va.upper().replace('0X', '0x') fo = fo.upper().replace('0X', '0x') data_item.appendRow([QStandardItem(va), QStandardItem('FileOffset: ' + fo)]) else: header_item.appendRow([QStandardItem(d), QStandardItem(hex(header[d]))]) self.elf_info.expandAll() self.elf_info.resizeColumnToContents(0) self.elf_info.resizeColumnToContents(1) self.setMinimumWidth(self.elf_info.columnWidth(0) + self.elf_info.columnWidth(1) + 50) self.setMinimumHeight(400) self.elf_info.collapseAll() self.elf_info.expandToDepth(1) def _on_dblclicked(self, model_index): if model_index.column() == 0 and model_index.data(): if model_index.data().startswith('0x'): self.onShowMemoryRequest.emit(model_index.data()) def _on_context_menu(self, pos): model_index = self.elf_info.indexAt(pos) if model_index.column() == 0 and model_index.data(): if model_index.data().startswith('0x'): context_menu = QMenu() context_menu.addAction('Add to Bookmarks', lambda: self.parent().bookmarks_panel.insert_bookmark(model_index.data(), 'init_array')) context_menu.addAction('Copy Address', lambda: utils.copy_hex_to_clipboard(model_index.data())) # show contextmenu glbl_pt = self.elf_info.mapToGlobal(pos) context_menu.exec_(glbl_pt)
class App(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.srvList=["", "master_mercury230", "master_modbusRTU", "master_modbusTCP", "master_http", "master_dcon", "master_ping"] self.slvList=["","opcUA","modbusTCP"] if(os.name=='nt'): self.appPath=os.path.abspath(sys.argv[0]).replace(os.path.basename(__file__),'') self.imgPath=self.appPath+"img\\" self.dbPath=self.appPath+"db\\srvDb.db" else: self.appPath=os.path.abspath(sys.argv[0]).replace(os.path.basename(__file__),'') self.imgPath=self.appPath+"img/" self.dbPath=self.appPath+"db/srvDb.db" self.versionPr='ScadaPy Конфигуратор сервера v.3.11' self.setGeometry(400, 200, 1000, 520) self.setWindowTitle(self.versionPr) self.setWindowIcon(QIcon( self.imgPath+'gnome-monitor.png')) self.h=self.frameGeometry().height() font = QFont() font.setPointSize(12) self.label0=QLabel(self) self.label0.setFont(font) self.label0.move(400, 60) self.label0.resize(300,25) self.label0.setText("ID сервера") self.label00=QLabel(self) self.label00.setFont(font) self.label00.move(550, 60) self.label00.resize(300,25) self.label00.setText("") self.label1=QLabel(self) self.label1.setFont(font) self.label1.move(400, 90) self.label1.resize(140,25) self.label1.setText("Название сервера") self.srvName = QLineEdit(self) self.srvName.setToolTip('Пример: Сервер Маш.Зала №1') self.srvName.move(550, 90) self.srvName.setFont(font) self.srvName.resize(300,25) self.label2=QLabel(self) self.label2.setFont(font) self.label2.move(400, 120) self.label2.resize(140,25) self.label2.setText("Slave IP address") self.slaveIP = QLineEdit(self) self.slaveIP.setToolTip('Пример: 192.168.0.111') self.slaveIP.move(550, 120) self.slaveIP.setFont(font) self.slaveIP.resize(300,25) self.label2=QLabel(self) self.label2.setFont(font) self.label2.move(400, 150) self.label2.resize(140,25) self.label2.setText("Slave Port") self.slavePort = QLineEdit(self) self.slavePort.setToolTip('Пример modbus: 502\nПример opcua: 4840') self.slavePort.move(550, 150) self.slavePort.setFont(font) self.slavePort.resize(100,25) self.label7=QLabel(self) self.label7.setFont(font) self.label7.move(680, 150) self.label7.resize(140,25) self.label7.setText("Timeout") self.serverTimeout = QLineEdit(self) self.serverTimeout.setToolTip('Пример ms: 1 ') self.serverTimeout.move(750, 150) self.serverTimeout.setFont(font) self.serverTimeout.resize(100,25) self.label3=QLabel(self) self.label3.setFont(font) self.label3.move(400, 180) self.label3.resize(140,25) self.label3.setText("Тип Master") self.label3=QLabel(self) self.label3.setFont(font) self.label3.move(550, 180) self.label3.resize(340,25) self.label3.setText("---") self.combo1 = QComboBox(self) self.combo1.move(550, 210) self.combo1.setFont(font) self.combo1.resize(320,25) self.combo1.addItems(self.srvList) self.label4=QLabel(self) self.label4.setFont(font) self.label4.move(400, 240) self.label4.resize(140,25) self.label4.setText("Тип Slave") self.label4=QLabel(self) self.label4.setFont(font) self.label4.move(550, 240) self.label4.resize(340,25) self.label4.setText("---") self.combo2 = QComboBox(self) self.combo2.move(550, 270) self.combo2.setFont(font) self.combo2.resize(320,25) self.combo2.addItems(self.slvList) self.label5=QLabel(self) self.label5.setFont(font) self.label5.move(400, 300) self.label5.resize(140,25) self.label5.setText("Порт /dev/tty*") self.tty=QLineEdit(self) self.tty.setToolTip('Пример linux: /dev/ttyUSB0\nПример windows: com19') self.tty.setFont(font) self.tty.move(550, 300) self.tty.resize(150,25) self.label6=QLabel(self) self.label6.setFont(font) self.label6.move(720, 300) self.label6.resize(140,25) self.label6.setText("скорость") self.ttySpeed=QLineEdit(self) self.ttySpeed.setToolTip('Пример : 9600') self.ttySpeed.setFont(font) self.ttySpeed.move(800, 300) self.ttySpeed.resize(150,25) exitAction = QAction(QIcon( self.imgPath+'exit.png'), '&Выход', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Выход из программы') exitAction.triggered.connect(qApp.quit) addServerAction = QAction(QIcon(self.imgPath+'add.png'), '&Добавить', self) addServerAction.setStatusTip('Добавить сервер') addServerAction.triggered.connect(self.addNewServer) delServerAction = QAction(QIcon(self.imgPath+'button_cancel.png'), '&Удалить', self) delServerAction.setStatusTip('Удалить сервер') delServerAction.triggered.connect(self.delServer) saveServerAction = QAction(QIcon(self.imgPath+'filesave.png'), '&Сохранить', self) saveServerAction.setStatusTip('Сохранить сервер') saveServerAction.triggered.connect(self.saveServer) saveScr = QAction(QIcon(self.imgPath+'bottom.png'), '&Сохранить скрипт', self) saveScr.setStatusTip('Сохранить скрипт') saveScr.triggered.connect(self.saveScr) runScr = QAction(QIcon(self.imgPath+'run.png'), '&Запустить скрипт', self) runScr.setStatusTip('Запустить скрипт') runScr.triggered.connect(self.runScr) menubar = self.menuBar() fileMenu = menubar.addMenu('&Команды') fileMenu.addAction(addServerAction) fileMenu.addAction(delServerAction) fileMenu.addAction(saveServerAction) fileMenu.addAction(saveScr) fileMenu.addAction(runScr) fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Выход') self.toolbar.addAction(exitAction) self.toolbar.addAction(addServerAction) self.toolbar.addAction(delServerAction) self.toolbar.addAction(saveServerAction) self.toolbar.addAction(saveScr) self.toolbar.addAction(runScr) # self.statusBar().showMessage('Загрузка данных') self.treeView = QTreeView(self) self.treeView.setFont(font) self.treeView.setObjectName("treeView") self.model = QStandardItemModel() self.treeView.setModel(self.model) self.header = ['Название сервера'] self.model.setHorizontalHeaderLabels(self.header) self.sqlLoad() self.treeView.clicked.connect(self.onClickItem) self.frameTable = QFrame(self) self.frameTable.move(380, 350) self.frameTable.setFont(font) self.frameTable.resize(1350,950) self.frameTable.setVisible(True) self.addRow = QPushButton(self.frameTable) self.addRow.setIcon(QIcon(self.imgPath+'add.png')) self.addRow.move(10, 10) self.addRow.resize(30,30) self.addRow.clicked.connect(self.addRowTable) self.saveTable = QPushButton(self.frameTable) self.saveTable.setIcon(QIcon(self.imgPath+'filesave.png')) self.saveTable.resize(30,30) self.saveTable.move(50, 10) self.saveTable.clicked.connect(self.saveRowTable) self.treeTable = QTableWidget(self.frameTable) fontTable = QFont() fontTable.setPointSize(10) self.treeTable.setFont(fontTable) self.show() def addRowTable(self): self.treeTable.insertRow(self.treeTable.rowCount()) def getDataPing(self): self.treeTable.clear() self.treeTable.setColumnCount(2) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['IP адрес сервера','Имя переменной']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 380) self.treeTable.setColumnWidth(1, 400) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select ip,name from master_ping where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) i+=1 def getDataMercury(self): self.treeTable.clear() self.treeTable.setColumnCount(2) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['Сетевой адрес счетчика','Имя переменной']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 380) self.treeTable.setColumnWidth(1, 400) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select netAdr, serNum from master_mercury230 where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) i+=1 def getDataModbusTCP(self): self.treeTable.clear() self.treeTable.setColumnCount(8) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['IP адрес','Порт','Адрес\nRTU','Название регистра','Адрес\nячейки','Кол-во\nячеек','Адрес на\nсервере','Имя переменной']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 110) self.treeTable.setColumnWidth(1, 50) self.treeTable.setColumnWidth(2, 80) self.treeTable.setColumnWidth(3, 220) self.treeTable.setColumnWidth(4, 80) self.treeTable.setColumnWidth(5, 80) self.treeTable.setColumnWidth(6, 80) self.treeTable.setColumnWidth(7, 160) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select ip,port,adrRtu,reg,fromAdr,fromCount,toAdr,comment serNum from master_modbusTCP where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) self.treeTable.setItem(i, 2, QTableWidgetItem(dt[i][2])) self.treeTable.setItem(i, 3, QTableWidgetItem(dt[i][3])) self.treeTable.setItem(i, 4, QTableWidgetItem(dt[i][4])) self.treeTable.setItem(i, 5, QTableWidgetItem(dt[i][5])) self.treeTable.setItem(i, 6, QTableWidgetItem(dt[i][6])) self.treeTable.setItem(i, 7, QTableWidgetItem(dt[i][7])) i+=1 def getDataHttp(self): self.treeTable.clear() self.treeTable.setColumnCount(7) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['Адрес http','Название регистра','modbus-Адрес ячейки\nopc-тип переменной','Количество \nячеек','Объект','Login','Password']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 310) self.treeTable.setColumnWidth(1, 160) self.treeTable.setColumnWidth(2, 150) self.treeTable.setColumnWidth(3, 120) self.treeTable.setColumnWidth(4, 120) self.treeTable.setColumnWidth(5, 120) self.treeTable.setColumnWidth(6, 120) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select ip,reg,toAdr,fromCount,comment,login,password from master_http where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) self.treeTable.setItem(i, 2, QTableWidgetItem(dt[i][2])) self.treeTable.setItem(i, 3, QTableWidgetItem(dt[i][3])) self.treeTable.setItem(i, 4, QTableWidgetItem(dt[i][4])) self.treeTable.setItem(i, 5, QTableWidgetItem(dt[i][5])) self.treeTable.setItem(i, 6, QTableWidgetItem(dt[i][6])) i+=1 def getDataDcon(self): self.treeTable.clear() self.treeTable.setColumnCount(4) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['Модель','Адрес\nRTU','Адрес ячейки на\nсервере','Имя переменной']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 110) self.treeTable.setColumnWidth(1, 80) self.treeTable.setColumnWidth(2, 120) self.treeTable.setColumnWidth(3, 320) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select model,adrRtu,toAdr,comment from master_dcon where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) self.treeTable.setItem(i, 2, QTableWidgetItem(dt[i][2])) self.treeTable.setItem(i, 3, QTableWidgetItem(dt[i][3])) i+=1 def getDataModbusRTU(self): self.treeTable.clear() self.treeTable.setColumnCount(6) self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels(['Адрес\nRTU','Название регистра','Адрес\nячейки','Кол-во\nячеек','Адрес на\nсервере','Имя переменной']) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 50) self.treeTable.setColumnWidth(1, 220) self.treeTable.setColumnWidth(2, 80) self.treeTable.setColumnWidth(3, 80) self.treeTable.setColumnWidth(4, 80) self.treeTable.setColumnWidth(5, 220) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select adrRtu,reg,fromAdr,fromCount,toAdr,comment serNum from master_modbusRTU where serverId = "+self.label00.text()) dt=cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0,len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) self.treeTable.setItem(i, 2, QTableWidgetItem(dt[i][2])) self.treeTable.setItem(i, 3, QTableWidgetItem(dt[i][3])) self.treeTable.setItem(i, 4, QTableWidgetItem(dt[i][4])) self.treeTable.setItem(i, 5, QTableWidgetItem(dt[i][5])) i+=1 def saveRowTable(self): connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() if(self.label3.text()=="master_ping"): cursor.execute("delete from master_ping where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 ): cursor.execute("INSERT INTO master_ping(serverId,ip,name,valid)\ VALUES('"+self.label00.text()+"','"+self.treeTable.item(i,0).text()+"'\ ,'"+self.treeTable.item(i,1).text()+"',1)" ) connDb.commit() except Exception as e: #print(e) pass i+=1 self.getDataPing() if(self.label3.text()=="master_mercury230"): cursor.execute("delete from master_mercury230 where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 ): cursor.execute("INSERT INTO master_mercury230(serverId,netAdr,serNum,valid)\ VALUES('"+self.label00.text()+"','"+self.treeTable.item(i,0).text()+"'\ ,'"+self.treeTable.item(i,1).text()+"',1)" ) connDb.commit() except Exception as e: #print(e) pass i+=1 self.getDataMercury() if(self.label3.text()=="master_modbusTCP"): cursor.execute("delete from master_modbusTCP where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 and len(self.treeTable.item(i,2).text()) > 0 and len(self.treeTable.item(i,3).text()) > 0 and len(self.treeTable.item(i,4).text()) > 0 and len(self.treeTable.item(i,5).text()) > 0 and len(self.treeTable.item(i,6).text()) > 0 and len(self.treeTable.item(i,7).text()) > 0 ): cursor.execute("INSERT INTO master_modbusTCP(serverId,ip,port,adrRtu,reg,fromAdr,fromCount,toAdr,comment,valid)\ VALUES('"+self.label00.text()+"',\ '"+self.treeTable.item(i,0).text()+"',\ '"+self.treeTable.item(i,1).text()+"',\ '"+self.treeTable.item(i,2).text()+"',\ '"+self.treeTable.item(i,3).text()+"',\ '"+self.treeTable.item(i,4).text()+"',\ '"+self.treeTable.item(i,5).text()+"',\ '"+self.treeTable.item(i,6).text()+"',\ '"+self.treeTable.item(i,7).text()+"',\ 1)" ) connDb.commit() except Exception as e: #print(e) pass i+=1 self.getDataModbusTCP() if(self.label3.text()=="master_modbusRTU"): cursor.execute("delete from master_modbusRTU where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 and len(self.treeTable.item(i,2).text()) > 0 and len(self.treeTable.item(i,3).text()) > 0 and len(self.treeTable.item(i,4).text()) > 0 and len(self.treeTable.item(i,5).text()) > 0 ): cursor.execute("INSERT INTO master_modbusRTU(serverId,adrRtu,reg,fromAdr,fromCount,toAdr,comment,valid)\ VALUES('"+self.label00.text()+"',\ '"+self.treeTable.item(i,0).text()+"',\ '"+self.treeTable.item(i,1).text()+"',\ '"+self.treeTable.item(i,2).text()+"',\ '"+self.treeTable.item(i,3).text()+"',\ '"+self.treeTable.item(i,4).text()+"',\ '"+self.treeTable.item(i,5).text()+"',\ 1)" ) connDb.commit() except Exception as e: #print(e) pass i+=1 self.getDataModbusRTU() if(self.label3.text()=="master_dcon"): cursor.execute("delete from master_dcon where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 and len(self.treeTable.item(i,2).text()) > 0 and len(self.treeTable.item(i,3).text()) > 0 ): cursor.execute("INSERT INTO master_dcon (serverId,model,adrRtu,toAdr,comment,valid)\ VALUES('"+self.label00.text()+"',\ '"+self.treeTable.item(i,0).text()+"',\ '"+self.treeTable.item(i,1).text()+"',\ '"+self.treeTable.item(i,2).text()+"',\ '"+self.treeTable.item(i,3).text()+"',\ 1)" ) connDb.commit() except Exception as e: #print(e) pass i+=1 self.getDataDcon() if(self.label3.text()=="master_http"): cursor.execute("delete from master_http where serverId= '"+self.label00.text()+"'" ) connDb.commit() for i in range(0,self.treeTable.rowCount()): try: if( len(self.treeTable.item(i,0).text()) > 0 and len(self.treeTable.item(i,1).text()) > 0 and len(self.treeTable.item(i,2).text()) > 0 and len(self.treeTable.item(i,3).text()) > 0 ): cursor.execute("INSERT INTO master_http (serverId,ip,reg,toAdr,fromCount,comment,login,password,valid)\ VALUES('"+self.label00.text()+"',\ '"+self.treeTable.item(i,0).text()+"',\ '"+self.treeTable.item(i,1).text()+"',\ '"+self.treeTable.item(i,2).text()+"',\ '"+self.treeTable.item(i,3).text()+"',\ '"+self.treeTable.item(i,4).text()+"',\ '"+self.treeTable.item(i,5).text()+"',\ '"+self.treeTable.item(i,6).text()+"',\ 1)" ) connDb.commit() except Exception as e: print(e) pass i+=1 self.getDataHttp() def truePanel (self,index): if(index == 'master_ping'): self.getDataPing() if(index == 'master_mercury230'): self.getDataMercury() if(index == 'master_modbusTCP'): self.getDataModbusTCP() if(index == 'master_modbusRTU'): self.getDataModbusRTU() if(index == 'master_dcon'): self.getDataDcon() if(index == 'master_http'): self.getDataHttp() def onClickItem (self): self.treeTable.clear() self.treeTable.setRowCount(0) self.srvName.setText("") self.label00.setText("") self.slaveIP.setText("") self.slavePort.setText("") self.label3.setText("") self.tty.setText("") self.ttySpeed.setText("") self.label4.setText("") self.serverTimeout.setText("") try: self.slaveIP.setEnabled(True) self.slavePort.setEnabled(True) self.tty.setEnabled(True) self.ttySpeed.setEnabled(True) index_list =[i.data() for i in self.treeView.selectedIndexes()] s=index_list[0].split(':') self.srvName.setText(s[1]) self.label00.setText(s[0]) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("select ip, port,stype,mtype,tty,speed,timeout from servers where id = "+s[0]) dt=cursor.fetchone() self.slaveIP.setText(dt[0]) self.slavePort.setText(dt[1]) self.label4.setText(dt[2]) self.label3.setText(dt[3]) self.tty.setText(dt[4]) self.ttySpeed.setText(dt[5]) self.serverTimeout.setText(dt[6]) self.slvList[0]=dt[2] self.srvList[0]=dt[3] self.truePanel (self.label3.text()) except Exception as e: index_list =[i.data() for i in self.treeView.selectedIndexes()] self.srvName.setText(index_list[0]) self.slaveIP.setEnabled(False) self.slavePort.setEnabled(False) self.tty.setEnabled(False) self.ttySpeed.setEnabled(False) # print(e) self.combo1.clear() self.combo1.addItems(self.srvList) self.combo2.clear() self.combo2.addItems(self.slvList) def addNewServer(self): sender = self.sender() self.statusBar().showMessage('Добавление нового сервера') self.model.appendRow(QStandardItem("Новый Сервер ")) def closeEvent(self, event): reply = QMessageBox.question(self, 'Сообщение', "Вы уверены, что хотите выйти?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() def resizeEvent(self,event): self.h=self.frameGeometry().height() self.treeView.setGeometry(QtCore.QRect(0, 60, 350, self.h-120)) self.treeTable.setGeometry(QtCore.QRect(10, 50, 1140, self.h-460)) self.frameTable.setGeometry(QtCore.QRect(380, 350, 1150, self.h-400)) def sqlLoad(self): connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() for row in cursor.execute('SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1])+":"+row[0])) def saveServer(self): self.treeTable.clear() self.truePanel ("") connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() if(len(self.label00.text())>0 and int(self.label00.text()) >0): if(len(self.srvName.text()) > 1): connDb.execute("update servers set name ='"+self.srvName.text()+ "', ip = '"+self.slaveIP.text()+"', port = '"+self.slavePort.text()+"'\ ,mtype='"+self.combo1.currentText()+"',stype='"+self.combo2.currentText()+"',tty='"+self.tty.text()+"'\ ,speed='"+self.ttySpeed.text()+"',timeout='"+self.serverTimeout.text()+"' where id = "+self.label00.text()+" ") connDb.commit() cursor.execute("select ip, port, mtype,stype,tty,speed,timeout from servers where id = "+self.label00.text()) dt=cursor.fetchone() self.slaveIP.setText(dt[0]) self.slavePort.setText(dt[1]) self.label3.setText(dt[2]) self.label4.setText(dt[3]) self.tty.setText(dt[4]) self.ttySpeed.setText(dt[5]) self.slvList[0]=dt[3] self.srvList[0]=dt[2] self.serverTimeout.setText(dt[6]) else: try: if(len(self.srvName.text()) > 1): cursor.execute("INSERT INTO servers(name,valid) VALUES( '"+self.srvName.text()+"',1)" ) connDb.commit() except Exception as e: print(e) pass self.model.clear() self.model.setHorizontalHeaderLabels(self.header) cursor = connDb.cursor() for row in cursor.execute('SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1])+":"+row[0])) self.combo1.clear() self.combo1.addItems(self.srvList) self.combo2.clear() self.combo2.addItems(self.slvList) self.truePanel (self.label3.text()) def saveScr(self): pathFolder = self.appPath if(os.name=='nt'): slash='\\' bat='.bat' rem ='rem ' command = 'start ' else: slash='/' bat='.sh' rem='# ' command='' f=open(pathFolder +'scr'+slash+'start_'+self.label00.text() + bat,'w') f.write(rem+'Скрипт создан в программе \''+self.versionPr+'\'\n') f.write(rem+'Название сервера \''+self.srvName.text()+'\'\n') f.write(rem+'Slave адрес \''+self.slaveIP.text()+'\'\n') f.write(rem+'Slave порт \''+self.slavePort.text()+'\'\n') f.write(rem+'Тип master \''+self.label3.text()+'\'\n') f.write(rem+'Тип slave \''+self.label4.text()+'\'\n') f.write(rem+'Интерфейс tty \''+self.tty.text()+'\'\n') f.write(rem+'Скорость tty \''+self.ttySpeed.text()+'\'\n') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_modbusTCP'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_tcp.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_ping'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_ping.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_dcon'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_dcon.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_mercury230'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_mercury230.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_modbusRTU'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_rtu.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'opcUA' and self.label3.text() =='master_http'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'opcua_master_http.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_modbusTCP'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_tcp.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_ping'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_ping.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_dcon'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_dcon.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_mercury230'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_mercury230.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_modbusRTU'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_rtu.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') if(self.label4.text() == 'modbusTCP' and self.label3.text() =='master_http'): f.write(command+sys.executable+' '+pathFolder +'source'+slash+'modbustcp_master_http.py '+self.label00.text() +' '+pathFolder +'db'+slash+'srvDb.db') f.close() ret = pathFolder +''+slash+'scr'+slash+'start_'+self.label00.text() + bat return ret def runScr(self): if(os.name=='nt'): os.system(self.saveScr()) else: os.system('chmod 777 '+self.saveScr()) os.system('xfce4-terminal --command=\'sudo '+self.saveScr()+'\'') def delServer(self): self.treeTable.clear() self.treeTable.setRowCount(0) connDb = sqlite3.connect(self.dbPath) if(len(self.label00.text())>0 and int(self.label00.text()) >0): if(len(self.srvName.text()) > 1): connDb.execute("update servers set valid=0 where id = "+self.label00.text()+" ") connDb.commit() self.model.clear() self.model.setHorizontalHeaderLabels(self.header) cursor = connDb.cursor() for row in cursor.execute('SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1])+":"+row[0])) self.slaveIP.setText("") self.slavePort.setText("") self.label3.setText("") self.srvName.setText("")
def initUI(self): self.srvList=["", "master_mercury230", "master_modbusRTU", "master_modbusTCP", "master_http", "master_dcon", "master_ping"] self.slvList=["","opcUA","modbusTCP"] if(os.name=='nt'): self.appPath=os.path.abspath(sys.argv[0]).replace(os.path.basename(__file__),'') self.imgPath=self.appPath+"img\\" self.dbPath=self.appPath+"db\\srvDb.db" else: self.appPath=os.path.abspath(sys.argv[0]).replace(os.path.basename(__file__),'') self.imgPath=self.appPath+"img/" self.dbPath=self.appPath+"db/srvDb.db" self.versionPr='ScadaPy Конфигуратор сервера v.3.11' self.setGeometry(400, 200, 1000, 520) self.setWindowTitle(self.versionPr) self.setWindowIcon(QIcon( self.imgPath+'gnome-monitor.png')) self.h=self.frameGeometry().height() font = QFont() font.setPointSize(12) self.label0=QLabel(self) self.label0.setFont(font) self.label0.move(400, 60) self.label0.resize(300,25) self.label0.setText("ID сервера") self.label00=QLabel(self) self.label00.setFont(font) self.label00.move(550, 60) self.label00.resize(300,25) self.label00.setText("") self.label1=QLabel(self) self.label1.setFont(font) self.label1.move(400, 90) self.label1.resize(140,25) self.label1.setText("Название сервера") self.srvName = QLineEdit(self) self.srvName.setToolTip('Пример: Сервер Маш.Зала №1') self.srvName.move(550, 90) self.srvName.setFont(font) self.srvName.resize(300,25) self.label2=QLabel(self) self.label2.setFont(font) self.label2.move(400, 120) self.label2.resize(140,25) self.label2.setText("Slave IP address") self.slaveIP = QLineEdit(self) self.slaveIP.setToolTip('Пример: 192.168.0.111') self.slaveIP.move(550, 120) self.slaveIP.setFont(font) self.slaveIP.resize(300,25) self.label2=QLabel(self) self.label2.setFont(font) self.label2.move(400, 150) self.label2.resize(140,25) self.label2.setText("Slave Port") self.slavePort = QLineEdit(self) self.slavePort.setToolTip('Пример modbus: 502\nПример opcua: 4840') self.slavePort.move(550, 150) self.slavePort.setFont(font) self.slavePort.resize(100,25) self.label7=QLabel(self) self.label7.setFont(font) self.label7.move(680, 150) self.label7.resize(140,25) self.label7.setText("Timeout") self.serverTimeout = QLineEdit(self) self.serverTimeout.setToolTip('Пример ms: 1 ') self.serverTimeout.move(750, 150) self.serverTimeout.setFont(font) self.serverTimeout.resize(100,25) self.label3=QLabel(self) self.label3.setFont(font) self.label3.move(400, 180) self.label3.resize(140,25) self.label3.setText("Тип Master") self.label3=QLabel(self) self.label3.setFont(font) self.label3.move(550, 180) self.label3.resize(340,25) self.label3.setText("---") self.combo1 = QComboBox(self) self.combo1.move(550, 210) self.combo1.setFont(font) self.combo1.resize(320,25) self.combo1.addItems(self.srvList) self.label4=QLabel(self) self.label4.setFont(font) self.label4.move(400, 240) self.label4.resize(140,25) self.label4.setText("Тип Slave") self.label4=QLabel(self) self.label4.setFont(font) self.label4.move(550, 240) self.label4.resize(340,25) self.label4.setText("---") self.combo2 = QComboBox(self) self.combo2.move(550, 270) self.combo2.setFont(font) self.combo2.resize(320,25) self.combo2.addItems(self.slvList) self.label5=QLabel(self) self.label5.setFont(font) self.label5.move(400, 300) self.label5.resize(140,25) self.label5.setText("Порт /dev/tty*") self.tty=QLineEdit(self) self.tty.setToolTip('Пример linux: /dev/ttyUSB0\nПример windows: com19') self.tty.setFont(font) self.tty.move(550, 300) self.tty.resize(150,25) self.label6=QLabel(self) self.label6.setFont(font) self.label6.move(720, 300) self.label6.resize(140,25) self.label6.setText("скорость") self.ttySpeed=QLineEdit(self) self.ttySpeed.setToolTip('Пример : 9600') self.ttySpeed.setFont(font) self.ttySpeed.move(800, 300) self.ttySpeed.resize(150,25) exitAction = QAction(QIcon( self.imgPath+'exit.png'), '&Выход', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Выход из программы') exitAction.triggered.connect(qApp.quit) addServerAction = QAction(QIcon(self.imgPath+'add.png'), '&Добавить', self) addServerAction.setStatusTip('Добавить сервер') addServerAction.triggered.connect(self.addNewServer) delServerAction = QAction(QIcon(self.imgPath+'button_cancel.png'), '&Удалить', self) delServerAction.setStatusTip('Удалить сервер') delServerAction.triggered.connect(self.delServer) saveServerAction = QAction(QIcon(self.imgPath+'filesave.png'), '&Сохранить', self) saveServerAction.setStatusTip('Сохранить сервер') saveServerAction.triggered.connect(self.saveServer) saveScr = QAction(QIcon(self.imgPath+'bottom.png'), '&Сохранить скрипт', self) saveScr.setStatusTip('Сохранить скрипт') saveScr.triggered.connect(self.saveScr) runScr = QAction(QIcon(self.imgPath+'run.png'), '&Запустить скрипт', self) runScr.setStatusTip('Запустить скрипт') runScr.triggered.connect(self.runScr) menubar = self.menuBar() fileMenu = menubar.addMenu('&Команды') fileMenu.addAction(addServerAction) fileMenu.addAction(delServerAction) fileMenu.addAction(saveServerAction) fileMenu.addAction(saveScr) fileMenu.addAction(runScr) fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Выход') self.toolbar.addAction(exitAction) self.toolbar.addAction(addServerAction) self.toolbar.addAction(delServerAction) self.toolbar.addAction(saveServerAction) self.toolbar.addAction(saveScr) self.toolbar.addAction(runScr) # self.statusBar().showMessage('Загрузка данных') self.treeView = QTreeView(self) self.treeView.setFont(font) self.treeView.setObjectName("treeView") self.model = QStandardItemModel() self.treeView.setModel(self.model) self.header = ['Название сервера'] self.model.setHorizontalHeaderLabels(self.header) self.sqlLoad() self.treeView.clicked.connect(self.onClickItem) self.frameTable = QFrame(self) self.frameTable.move(380, 350) self.frameTable.setFont(font) self.frameTable.resize(1350,950) self.frameTable.setVisible(True) self.addRow = QPushButton(self.frameTable) self.addRow.setIcon(QIcon(self.imgPath+'add.png')) self.addRow.move(10, 10) self.addRow.resize(30,30) self.addRow.clicked.connect(self.addRowTable) self.saveTable = QPushButton(self.frameTable) self.saveTable.setIcon(QIcon(self.imgPath+'filesave.png')) self.saveTable.resize(30,30) self.saveTable.move(50, 10) self.saveTable.clicked.connect(self.saveRowTable) self.treeTable = QTableWidget(self.frameTable) fontTable = QFont() fontTable.setPointSize(10) self.treeTable.setFont(fontTable) self.show()
class StepListView: def __init__(self, main_window): self.main_window = main_window self.lst_steps: CustomStepsListView = self.main_window.lst_steps self.controller = StepListController(self, self.main_window.world) # menu delete_action = QAction("Delete", self.lst_steps) delete_action.triggered.connect(self.on_delete_selected_item) self.menu = QMenu() self.menu.addAction(delete_action) # setup model self.model = QStandardItemModel() self.lst_steps.setModel(self.model) self.lst_steps.setItemDelegate(StepItemDelegate()) # ui events self.lst_steps.selectionModel().currentChanged.connect( self.on_step_selected) self.lst_steps.setContextMenuPolicy(Qt.CustomContextMenu) self.lst_steps.customContextMenuRequested.connect( self.on_display_context_menu) self.lst_steps.dropEventSignal.connect(self.on_drop_event) def on_drop_event(self, model_index: QModelIndex): selected_model_indexes = self.lst_steps.selectedIndexes() self.delete_steps_by_indexes(selected_model_indexes, delete_from_db=False) def step_with_order(order): step_entity = self.model.item(order).data(STEP_LIST_OBJECT_ROLE) step_entity.order = order return step_entity steps = [step_with_order(n) for n in range(self.model.rowCount())] self.controller.update_multiple_steps(steps) def get_step_entity_at_index(self, model_index): return model_index.data(STEP_LIST_OBJECT_ROLE) def select_step_at_index(self, model_index): self.lst_steps.setCurrentIndex(model_index) def indexes_for_selected_rows(self): return self.lst_steps.selectedIndexes() def delete_steps_by_indexes(self, model_indexes, delete_from_db=True): for items in reversed(sorted(model_indexes)): if delete_from_db: step_entity: StepEntity = self.get_step_entity_at_index(items) self.controller.delete_step(step_entity) self.model.takeRow(items.row()) def on_delete_selected_item(self): selected_model_indexes = self.indexes_for_selected_rows() if not selected_model_indexes: return self.delete_steps_by_indexes(selected_model_indexes) before_first_row_to_delete = selected_model_indexes[0].row() - 1 if before_first_row_to_delete >= 0: previous_item: QStandardItem = self.model.item( before_first_row_to_delete) if previous_item: self.select_step_at_index(previous_item.index()) def on_display_context_menu(self, position): index: QModelIndex = self.lst_steps.indexAt(position) if not index.isValid(): return global_position = self.lst_steps.viewport().mapToGlobal(position) self.menu.exec_(global_position) def clear_steps(self): self.model.clear() def update_steps(self, steps): for step in steps: self.add_step_widget(step, select_item=False) def select_step_at(self, position): first_item: QStandardItem = self.model.item(position) self.lst_steps.setCurrentIndex(first_item.index()) def add_step_widget(self, step: StepEntity, select_item=True): logging.info("Adding a new widget for {}".format(step)) step_item = QStandardItem("({}) {}".format(step.step_type.value, step.title)) step_item.setData(step, STEP_LIST_OBJECT_ROLE) step_item.setData(QVariant(step.id), STEP_LIST_ID_ROLE) step_item.setDragEnabled(True) step_item.setDropEnabled(False) self.model.appendRow(step_item) if select_item: index = self.model.indexFromItem(step_item) self.lst_steps.setCurrentIndex(index) def on_step_selected(self, current: QModelIndex): if not current: return selected_step_id = current.data(STEP_LIST_ID_ROLE) self.controller.trigger_step_selected(selected_step_id)
class E5NetworkMonitor(QDialog, Ui_E5NetworkMonitor): """ Class implementing a network monitor dialog. """ _monitor = None @classmethod def instance(cls, networkAccessManager): """ Class method to get a reference to our singleton. @param networkAccessManager reference to the network access manager (QNetworkAccessManager) @return reference to the network monitor singleton (E5NetworkMonitor) """ if cls._monitor is None: cls._monitor = E5NetworkMonitor(networkAccessManager) return cls._monitor @classmethod def closeMonitor(cls): """ Class method to close the monitor dialog. """ if cls._monitor is not None: cls._monitor.close() def __init__(self, networkAccessManager, parent=None): """ Constructor @param networkAccessManager reference to the network access manager (QNetworkAccessManager) @param parent reference to the parent widget (QWidget) """ super(E5NetworkMonitor, self).__init__(parent) self.setupUi(self) self.setWindowFlags(Qt.Window) self.__requestHeaders = QStandardItemModel(self) self.__requestHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.requestHeadersList.setModel(self.__requestHeaders) self.requestHeadersList.horizontalHeader().setStretchLastSection(True) self.requestHeadersList.doubleClicked.connect(self.__showHeaderDetails) self.__replyHeaders = QStandardItemModel(self) self.__replyHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.responseHeadersList.setModel(self.__replyHeaders) self.responseHeadersList.horizontalHeader().setStretchLastSection(True) self.responseHeadersList.doubleClicked.connect( self.__showHeaderDetails) self.requestsList.horizontalHeader().setStretchLastSection(True) self.requestsList.verticalHeader().setMinimumSectionSize(-1) self.__proxyModel = QSortFilterProxyModel(self) self.__proxyModel.setFilterKeyColumn(-1) self.searchEdit.textChanged.connect( self.__proxyModel.setFilterFixedString) self.removeButton.clicked.connect(self.requestsList.removeSelected) self.removeAllButton.clicked.connect(self.requestsList.removeAll) self.__model = E5RequestModel(networkAccessManager, self) self.__proxyModel.setSourceModel(self.__model) self.requestsList.setModel(self.__proxyModel) self.__proxyModel.rowsInserted.connect( self.requestsList.scrollToBottom) self.requestsList.selectionModel()\ .currentChanged[QModelIndex, QModelIndex]\ .connect(self.__currentChanged) fm = self.fontMetrics() em = fm.width("m") self.requestsList.horizontalHeader().resizeSection(0, em * 5) self.requestsList.horizontalHeader().resizeSection(1, em * 20) self.requestsList.horizontalHeader().resizeSection(3, em * 5) self.requestsList.horizontalHeader().resizeSection(4, em * 15) self.__headersDlg = None def closeEvent(self, evt): """ Protected method called upon closing the dialog. @param evt reference to the close event object (QCloseEvent) """ self.__class__._monitor = None super(E5NetworkMonitor, self).closeEvent(evt) def reject(self): """ Public slot to close the dialog with a Reject status. """ self.__class__._monitor = None super(E5NetworkMonitor, self).reject() def __currentChanged(self, current, previous): """ Private slot to handle a change of the current index. @param current new current index (QModelIndex) @param previous old current index (QModelIndex) """ self.__requestHeaders.setRowCount(0) self.__replyHeaders.setRowCount(0) if not current.isValid(): return row = self.__proxyModel.mapToSource(current).row() req = self.__model.requests[row].request for header in req.rawHeaderList(): self.__requestHeaders.insertRows(0, 1, QModelIndex()) self.__requestHeaders.setData( self.__requestHeaders.index(0, 0), str(header, "utf-8")) self.__requestHeaders.setData( self.__requestHeaders.index(0, 1), str(req.rawHeader(header), "utf-8")) self.__requestHeaders.item(0, 0).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.__requestHeaders.item(0, 1).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) for header in self.__model.requests[row].replyHeaders: self.__replyHeaders.insertRows(0, 1, QModelIndex()) self.__replyHeaders.setData( self.__replyHeaders.index(0, 0), header[0]) self.__replyHeaders.setData( self.__replyHeaders.index(0, 1), header[1]) self.__replyHeaders.item(0, 0).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.__replyHeaders.item(0, 1).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) def __showHeaderDetails(self, index): """ Private slot to show a dialog with the header details. @param index index of the entry to show (QModelIndex) """ if not index.isValid(): return headerList = self.sender() if headerList is None: return row = index.row() name = headerList.model().data(headerList.model().index(row, 0)) value = headerList.model().data(headerList.model().index(row, 1)) if self.__headersDlg is None: from .E5NetworkHeaderDetailsDialog import \ E5NetworkHeaderDetailsDialog self.__headersDlg = E5NetworkHeaderDetailsDialog(self) self.__headersDlg.setData(name, value) self.__headersDlg.show()
class SkipOnlyDialog(QDialog): def __init__(self, columns=None, skip=None, only=None, parent=None): super(SkipOnlyDialog, self).__init__(parent) self.setWindowTitle("Select Columns") self.columns = columns self.selected_variables = ( [] ) # Names of selected variables. Only updated when accepting the dialog. # Select 'only' by default (unless a skip list is passed in) # starting_only and only are booleans to indicate whether 'only' is selected # starting_selected and selected are boolean arrays to indicate whether each variable is selected if skip is not None: self.starting_only = False self.starting_selected = [(c in skip) for c in self.columns] elif only is not None: self.starting_only = True self.starting_selected = [(c in only) for c in self.columns] elif skip is None and only is None: self.starting_only = True self.starting_selected = [False for _ in self.columns] else: raise ValueError("Can't pass both 'skip' and 'only'") # Available- Left Side self.left_model = QStandardItemModel(self) self.left_proxy = QSortFilterProxyModel(self) self.left_proxy.setSourceModel(self.left_model) self.left_proxy.setFilterKeyColumn(0) # Filters based on the only column self.left_proxy.setFilterCaseSensitivity( Qt.CaseInsensitive ) # Case insensitive search # Selected - Right side self.right_model = QStandardItemModel() self.right_proxy = QSortFilterProxyModel(self) self.right_proxy.setSourceModel(self.right_model) self.right_proxy.setFilterKeyColumn(0) # Filters based on the only column self.right_proxy.setFilterCaseSensitivity( Qt.CaseInsensitive ) # Case insensitive search # Setup Layout layout = QGridLayout(self) layout.setColumnStretch(0, 2) layout.setColumnStretch(1, 1) layout.setColumnStretch(2, 2) # Left Side Group Box ("Available") left_list_box = QGroupBox("Available Variables") left_list_box_layout = QVBoxLayout() # Multiselect listing available columns self.left_list = QListView(self) self.left_list.setModel(self.left_proxy) self.left_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.left_list.selectionModel().selectionChanged.connect( self.left_selected_change ) self.left_list.setEditTriggers(QAbstractItemView.NoEditTriggers) left_list_box_layout.addWidget(self.left_list) # Add a search box self.left_list_search = QLineEdit(parent=self) self.left_list_search.setPlaceholderText("Search...") self.left_list_search.textChanged.connect(self.left_proxy.setFilterFixedString) left_list_box_layout.addWidget(self.left_list_search) # Set layout and add to the main layout left_list_box.setLayout(left_list_box_layout) layout.addWidget(left_list_box, 0, 0) # Add/Remove Buttons btns = QWidget() btns_layout = QVBoxLayout() btns.setLayout(btns_layout) # Add self.btn_add = QPushButton(text="Add ->", parent=self) self.btn_add.clicked.connect(self.add) self.btn_add.setEnabled(False) btns_layout.addWidget(self.btn_add) # Remove self.btn_remove = QPushButton(text="<- Remove", parent=self) self.btn_remove.clicked.connect(self.remove) self.btn_remove.setEnabled(False) btns_layout.addWidget(self.btn_remove) # Undo Changes self.btn_undo = QPushButton(text="Undo Changes", parent=self) self.btn_undo.clicked.connect(self.undo) self.btn_undo.setEnabled(False) btns_layout.addWidget(self.btn_undo) # Reset self.btn_reset = QPushButton(text="Reset", parent=self) self.btn_reset.clicked.connect(self.reset) self.btn_reset.setEnabled(False) btns_layout.addWidget(self.btn_reset) # Add to layout layout.addWidget(btns, 0, 1) # Right Side Group Box ("Selected") right_list_box = QGroupBox("Selected Variables") right_list_box_layout = QVBoxLayout() # Multiselect listing current selected columns self.right_list = QListView(self) self.right_list.setModel(self.right_proxy) self.right_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.right_list.selectionModel().selectionChanged.connect( self.right_selected_change ) self.right_list.setEditTriggers(QAbstractItemView.NoEditTriggers) right_list_box_layout.addWidget(self.right_list) # Add a search box self.right_list_search = QLineEdit(parent=self) self.right_list_search.setPlaceholderText("Search...") self.right_list_search.textChanged.connect( self.right_proxy.setFilterFixedString ) right_list_box_layout.addWidget(self.right_list_search) # Set layout and add to the main layout right_list_box.setLayout(right_list_box_layout) layout.addWidget(right_list_box, 0, 2) # Radio Select for Skip/Only self.radio_btns = QGroupBox("Skip Selected or Only Selected") radio_btns_layout = QHBoxLayout() self.radio_btns.setLayout(radio_btns_layout) self.radio_skip = QRadioButton("skip") radio_btns_layout.addWidget(self.radio_skip) self.radio_only = QRadioButton("only") self.radio_only.setChecked(True) radio_btns_layout.addWidget(self.radio_only) # If either button changes, a toggle signal is called for each one. No need to pass the "checked" parameter. self.radio_skip.toggled.connect(lambda is_checked: self.update_result()) layout.addWidget(self.radio_btns, 1, 2) # Result label self.result_label = QLabel(parent=self) self.result_label.setText("0 Variables to be used") layout.addWidget(self.result_label, 2, 0) # Ok/Cancel QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel self.buttonBox = QDialogButtonBox(QBtn) self.buttonBox.accepted.connect(self.submit) self.buttonBox.rejected.connect(self.reject) layout.addWidget(self.buttonBox, 2, 2) # Run reset to initialize self.undo() def undo(self): """ Reset both list views and set the parameters ('only' and 'selected') to their starting values """ # Clear lists self.left_model.clear() self.right_model.clear() # Set to the starting state self.selected = ( self.starting_selected.copy() ) # Take a copy, don't refer to the same list self.only = self.starting_only for v, is_selected in zip(self.columns, self.selected): if not is_selected: self.left_model.appendRow(QStandardItem(v)) else: self.right_model.appendRow(QStandardItem(v)) self.update_result() self.btn_undo.setEnabled(False) # No reason to undo twice def reset(self): """ Remove the initialized state to do a complete reset """ self.starting_only = True self.starting_selected = [False for _ in self.columns] self.undo() self.btn_reset.setEnabled(False) # No reason to reset twice def left_selected_change(self): """ Track the currently selected rows on the left """ left_selected_num = len(self.left_list.selectedIndexes()) if left_selected_num == 0: self.btn_add.setEnabled(False) else: self.btn_add.setEnabled(True) def right_selected_change(self): """ track the currently selected rows on the right """ right_selected_num = len(self.right_list.selectedIndexes()) if right_selected_num == 0: self.btn_remove.setEnabled(False) else: self.btn_remove.setEnabled(True) def reset_list(self, side): """Clear the search field and show the full list""" if side == "available": self.left_list_search.setText("") self.left_model.clear() for v, is_selected in zip(self.columns, self.selected): if not is_selected: self.left_model.appendRow(QStandardItem(v)) elif side == "selected": self.right_list_search.setText("") self.right_model.clear() for v, is_selected in zip(self.columns, self.selected): if is_selected: self.right_model.appendRow(QStandardItem(v)) def add(self): """ Move currently selected columns on the left to the right side """ # Clear any right-side search self.reset_list("selected") # Get selection rows (indexed directly in the model) left_selected = sorted( [ self.left_proxy.mapToSource(idx).row() for idx in self.left_list.selectedIndexes() ] ) # Move items for idx in left_selected: item = self.left_model.takeItem(idx) self.right_model.appendRow(item) # Mark as selected col_idx = self.columns.index(item.text()) self.selected[col_idx] = True # Delete rows after moving them (don't do it during because it causes index changes) for idx in reversed( left_selected ): # Remove in reverse order, otherwise index changes self.left_model.removeRow(idx) # Update label self.update_result() # Disable Add since nothing is now selected self.btn_add.setEnabled(False) def remove(self): """ Move currently selected columns on the right to the left side """ # Clear any left-side search self.reset_list("available") # Get selection rows (indexed directly in the model) right_selected = sorted( [ self.right_proxy.mapToSource(idx).row() for idx in self.right_list.selectedIndexes() ] ) # Move items for idx in right_selected: item = self.right_model.takeItem(idx) self.left_model.appendRow(item) # Mark as not selected col_idx = self.columns.index(item.text()) self.selected[col_idx] = False # Delete rows after moving them (don't do it during because it causes index changes) for idx in reversed( right_selected ): # Remove in reverse order, otherwise index changes self.right_model.removeRow(idx) # Update label self.update_result() # Disable Remove since nothing is now selected self.btn_remove.setEnabled(False) def update_result(self): """ Update the tracking of what variables will be used """ self.only = self.radio_only.isChecked() num_selected = sum(self.selected) if num_selected == 0: self.result_label.setText(f"Using all {len(self.columns):,} variables") elif self.only: self.result_label.setText( f"Only using {num_selected:,} of {len(self.columns):,} variables" ) else: self.result_label.setText( f"Skipping {num_selected:,} of {len(self.columns):,} variables" ) # Set the undo button status if self.selected == self.starting_selected and self.only == self.starting_only: # In the starting state self.btn_undo.setEnabled(False) else: self.btn_undo.setEnabled(True) # Set the reset button status if num_selected == 0 and self.only: # In the default state self.btn_reset.setEnabled(False) else: self.btn_reset.setEnabled(True) def submit(self): # TODO: Add any warnings here self.selected_variables = [ c for (c, is_selected) in zip(self.columns, self.selected) if is_selected ] self.accept() @staticmethod def get_skip_only(columns=None, skip=None, only=None, parent=None): if columns is None: return "No columns", None, None # Launch dialog to select skip and only dlg = SkipOnlyDialog(columns, skip, only, parent) result = dlg.exec_() # Get info from the dialog label = dlg.result_label.text() if dlg.only: skip = None only = dlg.selected_variables else: skip = dlg.selected_variables only = None # Return return label, skip, only
def initUI(self): mainLayout = QVBoxLayout() grid1 = QGridLayout() grid1.setSpacing(10) # 消息框 self.msgbox = QTextBrowser() self.msgbox.setReadOnly(True) self.msgbox.append(info) grid1.addWidget(self.msgbox, 0, 0, 1, 4) # 发送消息框 self.input = QLineEdit() self.send_msg = QPushButton('发送') grid1.addWidget(self.input, 1, 0, 1, 3) grid1.addWidget(self.send_msg, 1, 3, 1, 1) self.send_msg.clicked.connect(self.sendMsg) # 消息发送板块 msgGroupBox = QGroupBox('消息发送') msgGroupBox.setLayout(grid1) # 文件传输板块 fileGroupBox = QGroupBox('文件传输') grid2 = QGridLayout() grid2.setSpacing(10) # 选择工作文件夹 lbw = QLabel('文件夹:') self.fpath = QLineEdit('./cfile') sel_f = QPushButton('选择文件夹') grid2.addWidget(lbw, 2, 0, 1, 1) grid2.addWidget(self.fpath, 2, 1, 1, 3) grid2.addWidget(sel_f, 2, 4, 1, 1) sel_f.clicked.connect(self.showDialog) # 展示本机文件列表 lbcf = QLabel('本机文件:') self.cflist = QListView() self.cmodel = QStandardItemModel(self.cflist) grid2.addWidget(lbcf, 4, 0, 1, 2) grid2.addWidget(self.cflist, 5, 0, 8, 2) # 展示服务器文件列表 lbsf = QLabel('服务器文件:') self.sflist = QListView() self.smodel = QStandardItemModel(self.sflist) grid2.addWidget(lbsf, 4, 3, 1, 2) grid2.addWidget(self.sflist, 5, 3, 8, 2) # 添加操作按钮 self.bsend = QToolButton() self.brec = QToolButton() self.bsend.setArrowType(Qt.RightArrow) self.brec.setArrowType(Qt.LeftArrow) self.brec.setEnabled(False) self.bsend.setEnabled(False) grid2.addWidget(self.bsend, 7, 2, 1, 1) grid2.addWidget(self.brec, 9, 2, 1, 1) self.bsend.clicked.connect( lambda: self.getList(self.cmodel, self.clist_num, 'sendf')) self.brec.clicked.connect( lambda: self.getList(self.smodel, self.slist_num, 'dwnf')) self.cmodel.itemChanged.connect( lambda: self.onChanged(self.clist_num, self.bsend)) self.smodel.itemChanged.connect( lambda: self.onChanged(self.slist_num, self.brec)) # 添加进度条 self.pro = QProgressBar() grid2.addWidget(self.pro, 13, 0, 1, 5) fileGroupBox.setLayout(grid2) mainLayout.addWidget(msgGroupBox) mainLayout.addWidget(fileGroupBox) self.setLayout(mainLayout) self.resize(640, 640)
class TableView(QTableView): def __init__(self, parent=None): super(TableView, self).__init__(parent) self.resize(800, 600) self.setContextMenuPolicy(Qt.ActionsContextMenu) # 右键菜单 self.setEditTriggers(self.NoEditTriggers) # 禁止编辑 self.doubleClicked.connect(self.onDoubleClick) self.addAction(QAction("复制", self, triggered=self.copyData)) self.myModel = QStandardItemModel() # model self.initHeader() # 初始化表头 self.setModel(self.myModel) self.initData() # 初始化模拟数据 def onDoubleClick(self, index): print(index.row(), index.column(), index.data()) def keyPressEvent(self, event): super(TableView, self).keyPressEvent(event) # Ctrl + C if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_C: self.copyData() def copyData(self): count = len(self.selectedIndexes()) if count == 0: return if count == 1: # 只复制了一个 QApplication.clipboard().setText( self.selectedIndexes()[0].data()) # 复制到剪贴板中 QMessageBox.information(self, "提示", "已复制一个数据") return rows = set() cols = set() for index in self.selectedIndexes(): # 得到所有选择的 rows.add(index.row()) cols.add(index.column()) # print(index.row(),index.column(),index.data()) if len(rows) == 1: # 一行 QApplication.clipboard().setText("\t".join( [index.data() for index in self.selectedIndexes()])) # 复制 QMessageBox.information(self, "提示", "已复制一行数据") return if len(cols) == 1: # 一列 QApplication.clipboard().setText("\r\n".join( [index.data() for index in self.selectedIndexes()])) # 复制 QMessageBox.information(self, "提示", "已复制一列数据") return mirow, marow = min(rows), max(rows) # 最(少/多)行 micol, macol = min(cols), max(cols) # 最(少/多)列 print(mirow, marow, micol, macol) arrays = [["" for _ in range(macol - micol + 1)] for _ in range(marow - mirow + 1)] # 创建二维数组(并排除前面的空行和空列) print(arrays) # 填充数据 for index in self.selectedIndexes(): # 遍历所有选择的 arrays[index.row() - mirow][index.column() - micol] = index.data() print(arrays) data = "" # 最后的结果 for row in arrays: data += "\t".join(row) + "\r\n" print(data) QApplication.clipboard().setText(data) # 复制到剪贴板中 QMessageBox.information(self, "提示", "已复制") def initHeader(self): for i in range(5): self.myModel.setHorizontalHeaderItem( i, QStandardItem("表头" + str(i + 1))) def initData(self): for row in range(100): for col in range(5): self.myModel.setItem( row, col, QStandardItem("row: {row},col: {col}".format(row=row + 1, col=col + 1)))
class ContextPanel(QTabWidget): # consts CONTEXT_TYPE_NATIVE = 0 CONTEXT_TYPE_JAVA = 1 CONTEXT_TYPE_EMULATOR = 2 onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None): super(ContextPanel, self).__init__(parent=parent) self._app_window = parent self.setAutoFillBackground(True) self._nativectx_model = QStandardItemModel(0, 4) self._nativectx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._nativectx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._nativectx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') #self._nativectx_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(3, Qt.Horizontal, 'Telescope') self._nativectx_list = DwarfListView() self._nativectx_list.setModel(self._nativectx_model) self._nativectx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._nativectx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._nativectx_list.customContextMenuRequested.connect( self._on_native_contextmenu) self._emulatorctx_model = QStandardItemModel(0, 3) self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') self._emulatorctx_list = DwarfListView() self._emulatorctx_list.setModel(self._emulatorctx_model) self._emulatorctx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._emulatorctx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._emulatorctx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._emulatorctx_list.customContextMenuRequested.connect( self._on_emulator_contextmenu) self._javactx_model = QStandardItemModel(0, 3) self._javactx_model.setHeaderData(0, Qt.Horizontal, 'Argument') self._javactx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(1, Qt.Horizontal, 'Class') #self._javactx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(2, Qt.Horizontal, 'Value') self._javactx_list = DwarfListView() self._javactx_list.setModel(self._javactx_model) self._javactx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._javactx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._javactx_list.customContextMenuRequested.connect( self._on_java_contextmenu) self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def clear(self): self._nativectx_list.clear() self._emulatorctx_list.clear() self._javactx_list.clear() def set_context(self, ptr, context_type, context): if isinstance(context, str): context = json.loads(context) if context_type == ContextPanel.CONTEXT_TYPE_NATIVE: self._nativectx_list.clear() self._set_native_context(ptr, context) elif context_type == ContextPanel.CONTEXT_TYPE_JAVA: self._javactx_list.clear() self._set_java_context(ptr, context) elif context_type == ContextPanel.CONTEXT_TYPE_EMULATOR: self._emulatorctx_list.clear() self._set_emulator_context(ptr, context) else: raise Exception('unknown context type') def have_context(self): return self.count() > 0 def show_context_tab(self, tab_name): index = 0 tab_name = tab_name.join(tab_name.split()).lower() if tab_name == 'native': index = self.indexOf(self._nativectx_list) elif tab_name == 'emulator': index = self.indexOf(self._emulatorctx_list) elif tab_name == 'java': index = self.indexOf(self._javactx_list) if self.count() > 0: self.setCurrentIndex(index) def _set_native_context(self, ptr, context): if self.indexOf(self._nativectx_list) == -1: self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') else: self.show_context_tab('Native') context_ptr = ptr reg_order = [] if self._app_window.dwarf.arch == 'arm': # arm reg_order = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc'] elif self._app_window.dwarf.arch == 'arm64': reg_order = ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'w0', 'w1', 'w2', 'w3', 'w4', 'w5', 'w6', 'w7', 'w8', 'w9', 'w10', 'w11', 'w12', 'w13', 'w14', 'w15', 'w16', 'w17', 'w18', 'w19', 'w20', 'w21', 'w22', 'w23', 'w24', 'w25', 'w26', 'w27', 'w28', 'w29', 'w30', 'sp', 'lr', 'fp', 'wsp', 'wzr', 'xzr', 'nzcv', 'ip0', 'ip1', 's0', 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11', 's12', 's13', 's14', 's15', 's16', 's17', 's18', 's19', 's20', 's21', 's22', 's23', 's24', 's25', 's26', 's27', 's28', 's29', 's30', 's31', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'd10', 'd11', 'd12', 'd13', 'd14', 'd15', 'd16', 'd17', 'd18', 'd19', 'd20', 'd21', 'd22', 'd23', 'd24', 'd25', 'd26', 'd27', 'd28', 'd29', 'd30', 'd31', 'q0', 'q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q7', 'q8', 'q9', 'q10', 'q11', 'q12', 'q13', 'q14', 'q15', 'q16', 'q17', 'q18', 'q19', 'q20', 'q21', 'q22', 'q23', 'q24', 'q25', 'q26', 'q27', 'q28', 'q29', 'q30', 'q31', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc'] elif self._app_window.dwarf.arch == 'ia32': reg_order = ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'esp', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', 'ebp', 'eip', 'sp', 'pc'] elif self._app_window.dwarf.arch == 'x64': # x64 reg_order = ['rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'esp', 'ebp', 'rip', 'eip', 'sp', 'pc'] sorted_regs = {b: i for i, b in enumerate(reg_order)} for register in sorted(context, key=lambda x: sorted_regs[x]): reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) if context[register]['isValidPointer']: reg_name.setForeground(Qt.red) reg_name.setData(context_ptr) value_x = QStandardItem() # value_x.setTextAlignment(Qt.AlignCenter) value_dec = QStandardItem() # value_dec.setTextAlignment(Qt.AlignCenter) telescope = QStandardItem() reg_name.setText(register) if context[register] is not None: str_fmt = '0x{0:x}' if self._nativectx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x.setText( str_fmt.format(int(context[register]['value'], 16))) value_dec.setText('{0:d}'.format( int(context[register]['value'], 16))) if context[register]['isValidPointer']: if 'telescope' in context[register] and context[register][ 'telescope'] is not None: telescope = QStandardItem() telescope.setText( str(context[register]['telescope'][1])) if context[register]['telescope'][0] == 2: telescope.setData( context[register]['telescope'][1], Qt.UserRole + 1) if context[register]['telescope'][0] == 0: telescope.setForeground(Qt.darkGreen) elif context[register]['telescope'][0] == 2: telescope.setForeground(Qt.white) elif context[register]['telescope'][0] != 1: telescope.setForeground(Qt.darkGray) self._nativectx_model.appendRow([reg_name, value_x, value_dec, telescope]) self._nativectx_list.resizeColumnToContents(0) def _set_emulator_context(self, ptr, context): if self.indexOf(self._emulatorctx_list) == -1: self.addTab(self._emulatorctx_list, 'Emulator') self.show_context_tab('Emulator') else: self.show_context_tab('Emulator') context_ptr = ptr context = context.__dict__ for register in sorted(context): # todo: ??? if register.startswith('_'): continue reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) reg_name.setForeground(QColor('#39c')) value_x = QStandardItem() # value_x.setTextAlignment(Qt.AlignCenter) value_dec = QStandardItem() # value_dec.setTextAlignment(Qt.AlignCenter) reg_name.setText(register) reg_name.setData(context_ptr) if context[register] is not None: if isinstance(context[register], int): str_fmt = '0x{0:x}' if self._emulatorctx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x.setText(str_fmt.format(context[register])) value_dec.setText('{0:d}'.format(context[register])) self._emulatorctx_model.appendRow([reg_name, value_x, value_dec]) self._emulatorctx_list.resizeColumnToContents(0) self._emulatorctx_list.resizeColumnToContents(1) def _set_java_context(self, ptr, context): if self.indexOf(self._javactx_list) == -1: self.addTab(self._javactx_list, 'Java') self.show_context_tab('Java') else: self.show_context_tab('Java') for arg in context: _arg = QStandardItem() _arg.setText(arg) _class = QStandardItem() _class.setText(context[arg]['className']) if isinstance(context[arg]['handle'], str): _class.setForeground(Qt.lightGray) _value = QStandardItem() if context[arg] is not None: _value.setText('null') _value.setForeground(Qt.gray) self._javactx_model.appendRow([_arg, _class, _value]) self._javactx_list.resizeColumnToContents(0) self._javactx_list.resizeColumnToContents(1) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_native_contextmenu(self, pos): index = self._nativectx_list.indexAt(pos).row() glbl_pt = self._nativectx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._nativectx_model.item(index, 1).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._nativectx_model.item(index, 1).text())) context_menu.exec_(glbl_pt) def _on_emulator_contextmenu(self, pos): index = self._emulatorctx_list.indexAt(pos).row() glbl_pt = self._emulatorctx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: pass context_menu.exec_(glbl_pt) def _on_java_contextmenu(self, pos): index = self._javactx_list.indexAt(pos).row() glbl_pt = self._javactx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: pass context_menu.exec_(glbl_pt)
class ContextWidget(QTabWidget): # consts CONTEXT_TYPE_NATIVE = 0 CONTEXT_TYPE_JAVA = 1 onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None): super(ContextWidget, self).__init__(parent=parent) self._app_window = parent self.setAutoFillBackground(True) self._app_window.dwarf.onContextChanged.connect( self._on_context_changed) self._nativectx_model = QStandardItemModel(0, 4) self._nativectx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._nativectx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._nativectx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') self._nativectx_model.setHeaderData(3, Qt.Horizontal, 'Telescope') self._nativectx_list = DwarfListView() self._nativectx_list.setModel(self._nativectx_model) self._nativectx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._nativectx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._nativectx_list.customContextMenuRequested.connect( self._on_native_contextmenu) self._javactx_model = QStandardItemModel(0, 3) self._javactx_model.setHeaderData(0, Qt.Horizontal, 'Argument') self._javactx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(1, Qt.Horizontal, 'Class') self._javactx_model.setHeaderData(2, Qt.Horizontal, 'Value') self._javactx_list = DwarfListView() self._javactx_list.setModel(self._javactx_model) self._javactx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._javactx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._javactx_list.customContextMenuRequested.connect( self._on_java_contextmenu) self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def clear(self): self._nativectx_list.clear() self._javactx_list.clear() def set_context(self, ptr, context_type, context): if isinstance(context, str): context = json.loads(context) if context_type == ContextWidget.CONTEXT_TYPE_NATIVE: self._nativectx_list.clear() self._set_native_context(ptr, context) elif context_type == ContextWidget.CONTEXT_TYPE_JAVA: self._javactx_list.clear() self._set_java_context(ptr, context) else: raise Exception('unknown context type') def have_context(self): return self.count() > 0 def show_context_tab(self, tab_name): index = 0 tab_name = tab_name.join(tab_name.split()).lower() if tab_name == 'native': index = self.indexOf(self._nativectx_list) elif tab_name == 'java': index = self.indexOf(self._javactx_list) if self.count() > 0: self.setCurrentIndex(index) def _set_native_context(self, ptr, context): if self.indexOf(self._nativectx_list) == -1: self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') else: self.show_context_tab('Native') context_ptr = ptr sorted_regs = self.get_sort_order() for register in sorted(context, key=lambda x: sorted_regs[x] if x in sorted_regs else len(sorted_regs)): reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) if context[register]['isValidPointer']: reg_name.setData(context_ptr, Qt.UserRole + 1) value_x = QStandardItem() if context[register]['isValidPointer']: value_x.setForeground(Qt.red) value_dec = QStandardItem() telescope = QStandardItem() reg_name.setText(register) if context[register] is not None: str_fmt = '0x{0:x}' if self._nativectx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x.setText( str_fmt.format(int(context[register]['value'], 16))) value_dec.setText('{0:d}'.format( int(context[register]['value'], 16))) if context[register]['isValidPointer']: if 'telescope' in context[register] and context[register][ 'telescope'] is not None: telescope = QStandardItem() telescope_value = str( context[register]['telescope'][1]).replace( '\n', ' ') if len(telescope_value) > 50: telescope_value = telescope_value[:50] + '...' telescope.setText(telescope_value) if context[register]['telescope'][0] == 2: telescope.setData( context[register]['telescope'][1], Qt.UserRole + 1) if context[register]['telescope'][0] == 0: telescope.setForeground(Qt.darkGreen) elif context[register]['telescope'][0] == 2: telescope.setForeground(Qt.white) elif context[register]['telescope'][0] != 1: telescope.setForeground(Qt.darkGray) self._nativectx_model.appendRow( [reg_name, value_x, value_dec, telescope]) self._nativectx_list.resizeColumnToContents(0) def _set_java_context(self, ptr, context): if self.indexOf(self._javactx_list) == -1: self.addTab(self._javactx_list, 'Java') self.show_context_tab('Java') else: self.show_context_tab('Java') for arg in context: _arg = QStandardItem() _arg.setText(arg) _class = QStandardItem() _class.setText(context[arg]['className']) if isinstance(context[arg]['handle'], str): _class.setForeground(Qt.lightGray) _value = QStandardItem() if 'arg' not in context[arg] or context[arg]['arg'] is None: _value.setText('null') _value.setForeground(Qt.gray) else: _value.setText(context[arg]['arg']) self._javactx_model.appendRow([_arg, _class, _value]) self._javactx_list.resizeColumnToContents(0) self._javactx_list.resizeColumnToContents(1) def get_sort_order(self): reg_order = [] if self._app_window.dwarf.arch == 'arm': # arm reg_order = [ 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc', 'cspr' ] elif self._app_window.dwarf.arch == 'arm64': reg_order = [ 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'w0', 'w1', 'w2', 'w3', 'w4', 'w5', 'w6', 'w7', 'w8', 'w9', 'w10', 'w11', 'w12', 'w13', 'w14', 'w15', 'w16', 'w17', 'w18', 'w19', 'w20', 'w21', 'w22', 'w23', 'w24', 'w25', 'w26', 'w27', 'w28', 'w29', 'w30', 'sp', 'lr', 'fp', 'wsp', 'wzr', 'xzr', 'nzcv', 'ip0', 'ip1', 's0', 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11', 's12', 's13', 's14', 's15', 's16', 's17', 's18', 's19', 's20', 's21', 's22', 's23', 's24', 's25', 's26', 's27', 's28', 's29', 's30', 's31', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'd10', 'd11', 'd12', 'd13', 'd14', 'd15', 'd16', 'd17', 'd18', 'd19', 'd20', 'd21', 'd22', 'd23', 'd24', 'd25', 'd26', 'd27', 'd28', 'd29', 'd30', 'd31', 'q0', 'q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q7', 'q8', 'q9', 'q10', 'q11', 'q12', 'q13', 'q14', 'q15', 'q16', 'q17', 'q18', 'q19', 'q20', 'q21', 'q22', 'q23', 'q24', 'q25', 'q26', 'q27', 'q28', 'q29', 'q30', 'q31', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc', 'cspr' ] elif self._app_window.dwarf.arch == 'ia32': reg_order = [ 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'esp', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', 'ebp', 'eip', 'sp', 'pc' ] elif self._app_window.dwarf.arch == 'x64': # x64 reg_order = [ 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'esp', 'ebp', 'rip', 'eip', 'sp', 'pc' ] sorted_regs = {b: i for i, b in enumerate(reg_order)} return sorted_regs # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_native_contextmenu(self, pos): index = self._nativectx_list.indexAt(pos).row() glbl_pt = self._nativectx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: item = self._nativectx_model.item(index, 1) dec = self._nativectx_model.item(index, 2) telescope = self._nativectx_model.item(index, 3) # show contextmenu if self._nativectx_model.item(index, 0).data(Qt.UserRole + 1): context_menu.addAction( 'Jump to {0}'.format(item.text()), lambda: self._app_window.jump_to_address(item.text())) context_menu.addSeparator() # copy menu context_sub_menu = QMenu('Copy', context_menu) context_sub_menu.addAction( 'Value', lambda: utils.copy_str_to_clipboard(item.text())) if dec.text(): context_sub_menu.addAction( 'Decimal', lambda: utils.copy_str_to_clipboard(dec.text())) if telescope.text(): context_sub_menu.addAction( 'Telescope', lambda: utils.copy_str_to_clipboard(telescope.text())) context_menu.addMenu(context_sub_menu) context_menu.exec_(glbl_pt) def _on_java_contextmenu(self, pos): index = self._javactx_list.indexAt(pos).row() glbl_pt = self._javactx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: # show contextmenu argument = self._javactx_model.item(index, 1) _class = self._javactx_model.item(index, 2) value = self._javactx_model.item(index, 3) context_sub_menu = QMenu('Copy', context_menu) context_sub_menu.addAction( 'Argument', lambda: utils.copy_str_to_clipboard(argument.text())) if _class.text(): context_sub_menu.addAction( 'Class', lambda: utils.copy_str_to_clipboard(_class.text())) if value: if value.text(): context_sub_menu.addAction( 'Value', lambda: utils.copy_str_to_clipboard(value.text())) context_menu.addMenu(context_sub_menu) context_menu.exec_(glbl_pt) def _on_context_changed(self, reg_name, reg_val): x_in = 0 for c in reg_val: if c.lower() not in '1234567890abcdef': if c.lower() == 'x' and x_in == 0: x_in += 1 continue self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return if isinstance(reg_val, str) and reg_val.startswith('0x'): try: reg_val = int(reg_val, 16) except ValueError: self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return try: reg_val = int(reg_val) except ValueError: self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return reg_val = hex(reg_val) was_found, find_result = self._nativectx_list.contains_text( reg_name, True, True, True) if was_found: if len(find_result) == 1: find_result = find_result[0] if self._nativectx_model.item(find_result[0], 0).text() == reg_name: str_fmt = '0x{0:x}' if self._nativectx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x = str_fmt.format(int(reg_val, 16)) value_dec = '{0:d}'.format(int(reg_val, 16)) self._nativectx_model.item(find_result[0], 1).setText(value_x) self._nativectx_model.item(find_result[0], 2).setText(value_dec) self._nativectx_model.item(find_result[0], 3).setText("")
class RefsWidget(QObject): error = pyqtSignal(Exception) reference_changed = pyqtSignal(Node) def __init__(self, view): super().__init__(view) self.view = view self.model = QStandardItemModel() self.view.setModel(self.model) self.settings = QSettings() self.model.setHorizontalHeaderLabels(['ReferenceType', 'NodeId', "BrowseName", "TypeDefinition"]) state = self.settings.value("WindowState/refs_widget_state", None) if state is not None: self.view.horizontalHeader().restoreState(state) self.node = None self.reloadAction = QAction("Reload", self.model) self.reloadAction.triggered.connect(self.reload) self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect(self.showContextMenu) self._contextMenu = QMenu() self._contextMenu.addAction(self.reloadAction) def showContextMenu(self, position): if not self.node: return self._contextMenu.exec_(self.view.viewport().mapToGlobal(position)) def clear(self): # remove all rows but not header self.model.removeRows(0, self.model.rowCount()) self.node = None @trycatchslot def reload(self): node = self.node self.clear() self.show_refs(node) def save_state(self): self.settings.setValue("WindowState/refs_widget_state", self.view.horizontalHeader().saveState()) def show_refs(self, node): self.clear() self.node = node self._show_refs(node) def _show_refs(self, node): try: refs = node.get_children_descriptions(refs=ua.ObjectIds.References) except Exception as ex: self.error.emit(ex) raise for ref in refs: self._add_ref_row(ref) def _add_ref_row(self, ref): if ref.ReferenceTypeId.Identifier in ua.ObjectIdNames: typename = ua.ObjectIdNames[ref.ReferenceTypeId.Identifier] else: typename = str(ref.ReferenceTypeId) if ref.NodeId.NamespaceIndex == 0 and ref.NodeId.Identifier in ua.ObjectIdNames: nodeid = ua.ObjectIdNames[ref.NodeId.Identifier] else: nodeid = ref.NodeId.to_string() if ref.TypeDefinition.Identifier in ua.ObjectIdNames: typedef = ua.ObjectIdNames[ref.TypeDefinition.Identifier] else: typedef = ref.TypeDefinition.to_string() titem = QStandardItem(typename) titem.setData(ref, Qt.UserRole) self.model.appendRow([ titem, QStandardItem(nodeid), QStandardItem(ref.BrowseName.to_string()), QStandardItem(typedef) ])
class KeysTab(GalacteekTab): def __init__(self, *args, **kw): super().__init__(*args, **kw) self.resolveTimeout = 60 * 5 self.keysW = QWidget() self.addToLayout(self.keysW) self.ui = ui_keys.Ui_KeysForm() self.ui.setupUi(self.keysW) self.ui.addKeyButton.clicked.connect(self.onAddKeyClicked) self.ui.deleteKeyButton.clicked.connect( lambda *args: ensure(self.onDelKeyClicked())) self.model = QStandardItemModel(parent=self) self.ui.treeKeys = KeysView() self.ui.treeKeys.doubleClicked.connect(self.onItemDoubleClicked) self.ui.treeKeys.setModel(self.model) self.ui.verticalLayout.addWidget(self.ui.treeKeys) self.setupModel() self.app.task(self.listKeys) def setupModel(self): self.model.clear() self.model.setColumnCount(3) self.model.setHorizontalHeaderLabels( [iKeyName(), iP2PKey(), iKeyResolve()]) self.ui.treeKeys.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.ui.treeKeys.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) async def onDelKeyClicked(self): idx = self.ui.treeKeys.currentIndex() if not idx.isValid(): return messageBox('Invalid key') idxName = self.model.index(idx.row(), 0, idx.parent()) keyName = self.model.data(idxName) if not keyName: return reply = await questionBoxAsync( 'Delete key', 'Delete IPNS key <b>{key}</b> ?'.format(key=keyName)) if reply is True: self.app.task(self.delKey, keyName) def onAddKeyClicked(self): runDialog(AddKeyDialog, self.app, parent=self) @ipfsOp async def delKey(self, ipfsop, name): if await ipfsop.keysRemove(name): modelDelete(self.model, name) self.updateKeysList() @ipfsOp async def listKeys(self, ipfsop): keys = await ipfsop.keys() for key in keys: found = modelSearch(self.model, search=key['Name']) if len(found) > 0: continue nameItem = UneditableItem(key['Name']) nameItem.setToolTip(key['Name']) resolveItem = KeyResolvedItem('') self.model.appendRow([nameItem, KeyItem(key['Id']), resolveItem]) self.app.task(self.keyResolve, key, resolveItem) @ipfsOp async def keyResolve(self, ipfsop, key, item): if not isinstance(item, KeyResolvedItem): return now = datetime.now() update = False if item.resolvedLast is None: update = True if isinstance(item.resolvedLast, datetime): delta = now - item.resolvedLast if delta.seconds > self.resolveTimeout: update = True if update is True: resolved = await ipfsop.nameResolve(key['Id']) if isinstance(resolved, dict): rPath = resolved.get('Path') if not rPath: item.setBackground(QBrush(QColor('red'))) elif item.resolvesTo and rPath != item.resolvesTo: color = QColor('#c1f0c1') item.setBackground(QBrush(color)) else: item.setBackground(QBrush(Qt.NoBrush)) if rPath and IPFSPath(rPath).valid: item.resolvesTo = rPath item.setText(rPath) item.setToolTip("{path}\n\nResolved date: {date}".format( path=rPath, date=now.isoformat(sep=' ', timespec='seconds'))) else: item.setText(iUnknown()) item.resolvedLast = now # Ensure another one self.app.loop.call_later(self.resolveTimeout, self.app.task, self.keyResolve, key, item) def updateKeysList(self): self.app.task(self.listKeys) def onItemDoubleClicked(self, index): # Browse IPNS key associated with current item on double-click keyHash = self.model.data(self.model.index(index.row(), 1)) self.gWindow.addBrowserTab().browseIpnsKey(keyHash)
class App(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.srvList = ["", "opcUA", "modbusTCP"] if (os.name == 'nt'): self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') self.imgPath = self.appPath + "img\\" self.dbPath = self.appPath + "db\\webDb.db" #import self.appPath+srvconf else: self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') self.imgPath = self.appPath + "img/" self.dbPath = self.appPath + "db/webDb.db" self.versionPr = 'ScadaPy Web JSON Сервер v.3.14' self.setGeometry(300, 100, 1500, 820) self.setWindowTitle(self.versionPr) self.setWindowIcon(QIcon(self.imgPath + 'Globe.png')) self.h = self.frameGeometry().height() self.w = self.frameGeometry().width() self.setStyleSheet("background-color: #FFF8E7;") font = QFont() font.setPointSize(12) self.label0 = QLabel(self) self.label0.setFont(font) self.label0.move(400, 60) self.label0.resize(300, 25) self.label0.setText("ID сервера") self.label00 = QLabel(self) self.label00.setFont(font) self.label00.move(550, 60) self.label00.resize(300, 25) self.label00.setText("") self.label1 = QLabel(self) self.label1.setFont(font) self.label1.move(400, 90) self.label1.resize(140, 25) self.label1.setText("Название сервера") self.srvName = QLineEdit(self) self.srvName.setToolTip('Пример: Сервер Маш.Зала №1') self.srvName.move(550, 90) self.srvName.setFont(font) self.srvName.resize(300, 25) self.label2 = QLabel(self) self.label2.setFont(font) self.label2.move(400, 120) self.label2.resize(140, 25) self.label2.setText("Http IP address") self.slaveIP = QLineEdit(self) self.slaveIP.setToolTip('Пример: 192.168.0.111') self.slaveIP.move(550, 120) self.slaveIP.setFont(font) self.slaveIP.resize(300, 25) self.label2 = QLabel(self) self.label2.setFont(font) self.label2.move(400, 150) self.label2.resize(140, 25) self.label2.setText("Http Port") self.slavePort = QLineEdit(self) self.slavePort.setToolTip('Пример : 8080') self.slavePort.move(550, 150) self.slavePort.setFont(font) self.slavePort.resize(100, 25) self.label7 = QLabel(self) self.label7.setFont(font) self.label7.move(680, 150) self.label7.resize(140, 25) self.label7.setText("Timeout") self.serverTimeout = QLineEdit(self) self.serverTimeout.setToolTip('Пример ms: 1 ') self.serverTimeout.move(750, 150) self.serverTimeout.setFont(font) self.serverTimeout.resize(100, 25) self.label8 = QLabel(self) self.label8.setFont(font) self.label8.move(400, 180) self.label8.resize(140, 25) self.label8.setText("Login") self.serverLogin = QLineEdit(self) self.serverLogin.setToolTip('Имя пользователя') self.serverLogin.move(550, 180) self.serverLogin.setFont(font) self.serverLogin.resize(100, 25) self.label9 = QLabel(self) self.label9.setFont(font) self.label9.move(680, 180) self.label9.resize(140, 25) self.label9.setText("Password") self.serverPassword = QLineEdit(self) self.serverPassword.setToolTip('Пароль') self.serverPassword.move(750, 180) self.serverPassword.setFont(font) self.serverPassword.resize(100, 25) exitAction = QAction(QIcon(self.imgPath + 'exit.png'), '&Выход', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Выход из программы') exitAction.triggered.connect(qApp.quit) addServerAction = QAction(QIcon(self.imgPath + 'add.png'), '&Добавить', self) addServerAction.setStatusTip('Добавить сервер') addServerAction.triggered.connect(self.addNewServer) delServerAction = QAction(QIcon(self.imgPath + 'button_cancel.png'), '&Удалить', self) delServerAction.setStatusTip('Удалить сервер') delServerAction.triggered.connect(self.delServer) saveServerAction = QAction(QIcon(self.imgPath + 'filesave.png'), '&Сохранить', self) saveServerAction.setStatusTip('Сохранить сервер') saveServerAction.triggered.connect(self.saveServer) saveScr = QAction(QIcon(self.imgPath + 'bottom.png'), '&Сохранить скрипт', self) saveScr.setStatusTip('Сохранить скрипт') saveScr.triggered.connect(self.saveScr) runScr = QAction(QIcon(self.imgPath + 'run.png'), '&Запустить скрипт', self) runScr.setStatusTip('Запустить скрипт') runScr.triggered.connect(self.runScr) runConf = QAction(QIcon(self.imgPath + 'app.png'), '&Запустить конфигуратор', self) runConf.setStatusTip('Запустить конфигуратор') runConf.triggered.connect(self.runConf) menubar = self.menuBar() fileMenu = menubar.addMenu('&Команды') fileMenu.addAction(addServerAction) fileMenu.addAction(delServerAction) fileMenu.addAction(saveServerAction) fileMenu.addAction(saveScr) fileMenu.addAction(runScr) fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Выход') self.toolbar.addAction(exitAction) self.toolbar.addAction(addServerAction) self.toolbar.addAction(delServerAction) self.toolbar.addAction(saveServerAction) self.toolbar.addAction(saveScr) self.toolbar.addAction(runScr) self.toolbar.addAction(runConf) # self.statusBar().showMessage('Загрузка данных') self.treeView = QTreeView(self) self.treeView.setFont(font) self.treeView.setObjectName("treeView") self.model = QStandardItemModel() self.treeView.setModel(self.model) self.treeView.setStyleSheet("background-color: white;") self.header = ['Название сервера'] self.model.setHorizontalHeaderLabels(self.header) self.sqlLoad() self.treeView.clicked.connect(self.onClickItem) self.frameTable = QFrame(self) self.frameTable.setVisible(True) self.addRow = QPushButton(self.frameTable) self.addRow.setIcon(QIcon(self.imgPath + 'add.png')) self.addRow.move(10, 10) self.addRow.resize(30, 30) self.addRow.clicked.connect(self.addItemTree) self.saveTable = QPushButton(self.frameTable) self.saveTable.setIcon(QIcon(self.imgPath + 'filesave.png')) self.saveTable.resize(30, 30) self.saveTable.move(50, 10) self.saveTable.clicked.connect(self.saveData) #################################################################### self.treeTable = QTableWidget(self.frameTable) self.treeTable.setStyleSheet("background-color: white;") fontTable = QFont() fontTable.setPointSize(10) self.treeTable.setFont(fontTable) # self.show() self.showMaximized() def addItemTree(self): items = ("modbus_tcp", "opc_ua") item, okPressed = QInputDialog.getItem(self, "Добавить тип сервера", "Тип:", items, 0, False) if okPressed and item: self.treeTable.insertRow(self.treeTable.rowCount()) self.treeTable.setItem(self.treeTable.rowCount() - 1, 0, QTableWidgetItem(item)) def getData(self): self.treeTable.clear() self.treeTable.setColumnCount(10) #self.treeTable.setRowCount(1) self.treeTable.setHorizontalHeaderLabels([ 'Тип сервера', 'Имя переменной', 'Имя параметра', 'IP адрес', 'Порт', 'Логин', 'Пароль', 'Timeout', 'Адрес ячейки', 'Количество' ]) self.treeTable.resizeColumnsToContents() self.treeTable.setColumnWidth(0, 120) self.treeTable.setColumnWidth(1, 170) self.treeTable.setColumnWidth(2, 170) self.treeTable.setColumnWidth(3, 140) self.treeTable.setColumnWidth(4, 80) self.treeTable.setColumnWidth(5, 120) self.treeTable.setColumnWidth(6, 120) self.treeTable.setColumnWidth(7, 80) self.treeTable.setColumnWidth(8, 120) self.treeTable.setColumnWidth(9, 80) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute( "select type,var,param,ip,port,login,password,t,regadr,regcount from master where serverId = " + self.label00.text()) dt = cursor.fetchall() self.treeTable.setRowCount(len(dt)) for i in range(0, len(dt)): self.treeTable.setItem(i, 0, QTableWidgetItem(dt[i][0])) self.treeTable.setItem(i, 1, QTableWidgetItem(dt[i][1])) self.treeTable.setItem(i, 2, QTableWidgetItem(dt[i][2])) self.treeTable.setItem(i, 3, QTableWidgetItem(dt[i][3])) self.treeTable.setItem(i, 4, QTableWidgetItem(dt[i][4])) self.treeTable.setItem(i, 5, QTableWidgetItem(dt[i][5])) self.treeTable.setItem(i, 6, QTableWidgetItem(dt[i][6])) self.treeTable.setItem(i, 7, QTableWidgetItem(dt[i][7])) self.treeTable.setItem(i, 8, QTableWidgetItem(dt[i][8])) self.treeTable.setItem(i, 9, QTableWidgetItem(dt[i][9])) i += 1 def saveData(self): connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute("delete from master where serverId= '" + self.label00.text() + "'") connDb.commit() for i in range(0, self.treeTable.rowCount()): try: if (len(self.treeTable.item(i, 0).text()) > 0 and len(self.treeTable.item(i, 1).text()) > 0 and len(self.treeTable.item(i, 2).text()) > 0 and len(self.treeTable.item(i, 3).text()) > 0 and len(self.treeTable.item(i, 4).text()) > 0 and len(self.treeTable.item(i, 5).text()) > 0 and len(self.treeTable.item(i, 6).text()) > 0 and len(self.treeTable.item(i, 7).text()) > 0 and len(self.treeTable.item(i, 8).text()) > 0): cursor.execute( "INSERT INTO master(serverId,type,var,param,ip,port,login,password,t,regadr,regcount,valid)\ VALUES('" + self.label00.text() + "',\ '" + self.treeTable.item(i, 0).text() + "',\ '" + self.treeTable.item(i, 1).text() + "',\ '" + self.treeTable.item(i, 2).text() + "',\ '" + self.treeTable.item(i, 3).text() + "',\ '" + self.treeTable.item(i, 4).text() + "',\ '" + self.treeTable.item(i, 5).text() + "',\ '" + self.treeTable.item(i, 6).text() + "',\ '" + self.treeTable.item(i, 7).text() + "',\ '" + self.treeTable.item(i, 8).text() + "',\ '" + self.treeTable.item(i, 9).text() + "',\ 1)") connDb.commit() except Exception as e: print(e) pass i += 1 self.getData() def truePanel(self): self.getData() def onClickItem(self): self.treeTable.clear() self.treeTable.setRowCount(0) self.srvName.setText("") self.label00.setText("") self.slaveIP.setText("") self.slavePort.setText("") self.serverTimeout.setText("") self.serverLogin.setText("") self.serverPassword.setText("") try: self.slaveIP.setEnabled(True) self.slavePort.setEnabled(True) index_list = [i.data() for i in self.treeView.selectedIndexes()] s = index_list[0].split(':') self.srvName.setText(s[1]) self.label00.setText(s[0]) connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() cursor.execute( "select ip, port,timeout,login,password from servers where id = " + s[0]) dt = cursor.fetchone() self.slaveIP.setText(dt[0]) self.slavePort.setText(dt[1]) self.serverTimeout.setText(dt[2]) self.serverLogin.setText(dt[3]) self.serverPassword.setText(dt[4]) self.truePanel() except Exception as e: index_list = [i.data() for i in self.treeView.selectedIndexes()] self.srvName.setText(index_list[0]) self.slaveIP.setEnabled(False) self.slavePort.setEnabled(False) print(e) def addNewServer(self): sender = self.sender() self.statusBar().showMessage('Добавление нового сервера') self.model.appendRow(QStandardItem("Новый Сервер ")) def closeEvent(self, event): reply = QMessageBox.question(self, 'Сообщение', "Вы уверены, что хотите выйти?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() def resizeEvent(self, event): self.h = self.frameGeometry().height() self.treeView.setGeometry(QtCore.QRect(0, 60, 350, self.h - 120)) self.treeTable.setGeometry( QtCore.QRect(10, 50, self.w - 270, self.h - 320)) self.frameTable.setGeometry( QtCore.QRect(350, 210, self.w - 250, self.h - 260)) def sqlLoad(self): connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() for row in cursor.execute( 'SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1]) + ":" + row[0])) def saveServer(self): self.treeTable.clear() connDb = sqlite3.connect(self.dbPath) cursor = connDb.cursor() if (len(self.label00.text()) > 0 and int(self.label00.text()) > 0): if (len(self.srvName.text()) > 1): connDb.execute("update servers set name ='" + self.srvName.text() + "', ip = '" + self.slaveIP.text() + "', port = '" + self.slavePort.text() + "'\ ,timeout='" + self.serverTimeout.text() + "', login='******',password='******' where id = " + self.label00.text() + " ") connDb.commit() cursor.execute( "select ip,port,timeout,login,password from servers where id = " + self.label00.text()) dt = cursor.fetchone() self.slaveIP.setText(dt[0]) self.slavePort.setText(dt[1]) self.serverTimeout.setText(dt[2]) self.serverLogin.setText(dt[3]) self.serverPassword.setText(dt[4]) self.truePanel() else: try: if (len(self.srvName.text()) > 1): cursor.execute( "INSERT INTO servers(name,valid) VALUES( '" + self.srvName.text() + "',1)") connDb.commit() except Exception as e: #print(e) pass self.model.clear() self.model.setHorizontalHeaderLabels(self.header) cursor = connDb.cursor() for row in cursor.execute( 'SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1]) + ":" + row[0])) # self.truePanel() def saveScr(self): try: pathFolder = self.appPath if (os.name == 'nt'): slash = '\\' bat = '.bat' rem = 'rem ' command = 'start ' else: slash = '/' bat = '.sh' rem = '# ' command = '' f = open( pathFolder + 'scr' + slash + 'web_' + self.label00.text() + bat, 'w') print(pathFolder + 'scr' + slash + 'web_' + self.label00.text() + bat) f.write(rem + 'Скрипт создан в программе \'' + self.versionPr + '\'\n') f.write(rem + 'Сервер Web \'' + self.srvName.text() + '\'\n') f.write(rem + 'Http адрес \'' + self.slaveIP.text() + '\'\n') f.write(rem + 'Http порт \'' + self.slavePort.text() + '\'\n') f.write(command + sys.executable + ' ' + pathFolder + 'source' + slash + 'websrv.py ' + self.label00.text() + ' ' + pathFolder + 'db' + slash + 'webDb.db') f.close() ret = pathFolder + '' + slash + 'scr' + slash + 'web_' + self.label00.text( ) + bat except Exception as e: print(e) return ret def runScr(self): if (os.name == 'nt'): os.system(self.saveScr()) else: os.system('chmod 777 ' + self.saveScr()) os.system('xfce4-terminal --command=\'sudo ' + self.saveScr() + '\'') def runConf(self): if (os.name == 'nt'): self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') os.system(sys.executable + " " + self.appPath + "srvconf.py") else: self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') os.system(sys.executable + " " + self.appPath + "srvconf.py") def delServer(self): self.treeTable.clear() self.treeTable.setRowCount(0) connDb = sqlite3.connect(self.dbPath) if (len(self.label00.text()) > 0 and int(self.label00.text()) > 0): if (len(self.srvName.text()) > 1): connDb.execute("update servers set valid=0 where id = " + self.label00.text() + " ") connDb.commit() self.model.clear() self.model.setHorizontalHeaderLabels(self.header) cursor = connDb.cursor() for row in cursor.execute( 'SELECT name, id FROM servers where valid=1 ORDER BY id'): self.model.appendRow(QStandardItem(str(row[1]) + ":" + row[0])) self.slaveIP.setText("") self.slavePort.setText("") # self.label3.setText("") self.srvName.setText("")
def __init__(self, columns=None, skip=None, only=None, parent=None): super(SkipOnlyDialog, self).__init__(parent) self.setWindowTitle("Select Columns") self.columns = columns self.selected_variables = ( [] ) # Names of selected variables. Only updated when accepting the dialog. # Select 'only' by default (unless a skip list is passed in) # starting_only and only are booleans to indicate whether 'only' is selected # starting_selected and selected are boolean arrays to indicate whether each variable is selected if skip is not None: self.starting_only = False self.starting_selected = [(c in skip) for c in self.columns] elif only is not None: self.starting_only = True self.starting_selected = [(c in only) for c in self.columns] elif skip is None and only is None: self.starting_only = True self.starting_selected = [False for _ in self.columns] else: raise ValueError("Can't pass both 'skip' and 'only'") # Available- Left Side self.left_model = QStandardItemModel(self) self.left_proxy = QSortFilterProxyModel(self) self.left_proxy.setSourceModel(self.left_model) self.left_proxy.setFilterKeyColumn(0) # Filters based on the only column self.left_proxy.setFilterCaseSensitivity( Qt.CaseInsensitive ) # Case insensitive search # Selected - Right side self.right_model = QStandardItemModel() self.right_proxy = QSortFilterProxyModel(self) self.right_proxy.setSourceModel(self.right_model) self.right_proxy.setFilterKeyColumn(0) # Filters based on the only column self.right_proxy.setFilterCaseSensitivity( Qt.CaseInsensitive ) # Case insensitive search # Setup Layout layout = QGridLayout(self) layout.setColumnStretch(0, 2) layout.setColumnStretch(1, 1) layout.setColumnStretch(2, 2) # Left Side Group Box ("Available") left_list_box = QGroupBox("Available Variables") left_list_box_layout = QVBoxLayout() # Multiselect listing available columns self.left_list = QListView(self) self.left_list.setModel(self.left_proxy) self.left_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.left_list.selectionModel().selectionChanged.connect( self.left_selected_change ) self.left_list.setEditTriggers(QAbstractItemView.NoEditTriggers) left_list_box_layout.addWidget(self.left_list) # Add a search box self.left_list_search = QLineEdit(parent=self) self.left_list_search.setPlaceholderText("Search...") self.left_list_search.textChanged.connect(self.left_proxy.setFilterFixedString) left_list_box_layout.addWidget(self.left_list_search) # Set layout and add to the main layout left_list_box.setLayout(left_list_box_layout) layout.addWidget(left_list_box, 0, 0) # Add/Remove Buttons btns = QWidget() btns_layout = QVBoxLayout() btns.setLayout(btns_layout) # Add self.btn_add = QPushButton(text="Add ->", parent=self) self.btn_add.clicked.connect(self.add) self.btn_add.setEnabled(False) btns_layout.addWidget(self.btn_add) # Remove self.btn_remove = QPushButton(text="<- Remove", parent=self) self.btn_remove.clicked.connect(self.remove) self.btn_remove.setEnabled(False) btns_layout.addWidget(self.btn_remove) # Undo Changes self.btn_undo = QPushButton(text="Undo Changes", parent=self) self.btn_undo.clicked.connect(self.undo) self.btn_undo.setEnabled(False) btns_layout.addWidget(self.btn_undo) # Reset self.btn_reset = QPushButton(text="Reset", parent=self) self.btn_reset.clicked.connect(self.reset) self.btn_reset.setEnabled(False) btns_layout.addWidget(self.btn_reset) # Add to layout layout.addWidget(btns, 0, 1) # Right Side Group Box ("Selected") right_list_box = QGroupBox("Selected Variables") right_list_box_layout = QVBoxLayout() # Multiselect listing current selected columns self.right_list = QListView(self) self.right_list.setModel(self.right_proxy) self.right_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.right_list.selectionModel().selectionChanged.connect( self.right_selected_change ) self.right_list.setEditTriggers(QAbstractItemView.NoEditTriggers) right_list_box_layout.addWidget(self.right_list) # Add a search box self.right_list_search = QLineEdit(parent=self) self.right_list_search.setPlaceholderText("Search...") self.right_list_search.textChanged.connect( self.right_proxy.setFilterFixedString ) right_list_box_layout.addWidget(self.right_list_search) # Set layout and add to the main layout right_list_box.setLayout(right_list_box_layout) layout.addWidget(right_list_box, 0, 2) # Radio Select for Skip/Only self.radio_btns = QGroupBox("Skip Selected or Only Selected") radio_btns_layout = QHBoxLayout() self.radio_btns.setLayout(radio_btns_layout) self.radio_skip = QRadioButton("skip") radio_btns_layout.addWidget(self.radio_skip) self.radio_only = QRadioButton("only") self.radio_only.setChecked(True) radio_btns_layout.addWidget(self.radio_only) # If either button changes, a toggle signal is called for each one. No need to pass the "checked" parameter. self.radio_skip.toggled.connect(lambda is_checked: self.update_result()) layout.addWidget(self.radio_btns, 1, 2) # Result label self.result_label = QLabel(parent=self) self.result_label.setText("0 Variables to be used") layout.addWidget(self.result_label, 2, 0) # Ok/Cancel QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel self.buttonBox = QDialogButtonBox(QBtn) self.buttonBox.accepted.connect(self.submit) self.buttonBox.rejected.connect(self.reject) layout.addWidget(self.buttonBox, 2, 2) # Run reset to initialize self.undo()
def __init__(self, parent=None): # pylint: disable=too-many-statements super(BookmarksWidget, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('BookmarksPanel created before Dwarf exists') return self.bookmarks = {} self._bookmarks_list = DwarfListView() self._bookmarks_list.doubleClicked.connect(self._on_double_clicked) self._bookmarks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._bookmarks_list.customContextMenuRequested.connect( self._on_contextmenu) self._bookmarks_model = QStandardItemModel(0, 2) self._bookmarks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._bookmarks_model.setHeaderData(1, Qt.Horizontal, 'Notes') self._bookmarks_list.setModel(self._bookmarks_model) self._bookmarks_list.header().setStretchLastSection(False) self._bookmarks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._bookmarks_list.header().setSectionResizeMode( 1, QHeaderView.Stretch | QHeaderView.Interactive) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._bookmarks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(lambda: self._create_bookmark(-1)) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._bookmarks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_B), self._app_window, self._create_bookmark) shortcut_addnative.setAutoRepeat(False)
class AddressList(MyTreeView): class Columns(IntEnum): TYPE = 0 ADDRESS = 1 LABEL = 2 COIN_BALANCE = 3 FIAT_BALANCE = 4 NUM_TXS = 5 filter_columns = [Columns.TYPE, Columns.ADDRESS, Columns.LABEL, Columns.COIN_BALANCE] ROLE_SORT_ORDER = Qt.UserRole + 1000 def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.LABEL) self.wallet = self.parent.wallet self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) for addr_type in AddressTypeFilter.__members__.values(): # type: AddressTypeFilter self.change_button.addItem(addr_type.ui_text()) self.used_button = QComboBox(self) self.used_button.currentIndexChanged.connect(self.toggle_used) for addr_usage_state in AddressUsageStateFilter.__members__.values(): # type: AddressUsageStateFilter self.used_button.addItem(addr_usage_state.ui_text()) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.update() self.sortByColumn(self.Columns.TYPE, Qt.AscendingOrder) def get_toolbar_buttons(self): return QLabel(_("Filter:")), self.change_button, self.used_button def on_hide_toolbar(self): self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.update() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_addresses', state) def refresh_headers(self): fx = self.parent.fx if fx and fx.get_fiat_address_config(): ccy = fx.get_currency() else: ccy = _('Fiat') headers = { self.Columns.TYPE: _('Type'), self.Columns.ADDRESS: _('Address'), self.Columns.LABEL: _('Label'), self.Columns.COIN_BALANCE: _('Balance'), self.Columns.FIAT_BALANCE: ccy + ' ' + _('Balance'), self.Columns.NUM_TXS: _('Tx'), } self.update_headers(headers) def toggle_change(self, state: int): if state == self.show_change: return self.show_change = AddressTypeFilter(state) self.update() def toggle_used(self, state: int): if state == self.show_used: return self.show_used = AddressUsageStateFilter(state) self.update() @profiler def update(self): if self.maybe_defer_update(): return current_address = self.current_item_user_role(col=self.Columns.LABEL) if self.show_change == AddressTypeFilter.RECEIVING: addr_list = self.wallet.get_receiving_addresses() elif self.show_change == AddressTypeFilter.CHANGE: addr_list = self.wallet.get_change_addresses() else: addr_list = self.wallet.get_addresses() self.proxy.setDynamicSortFilter(False) # temp. disable re-sorting after every change self.std_model.clear() self.refresh_headers() fx = self.parent.fx set_address = None addresses_beyond_gap_limit = self.wallet.get_all_known_addresses_beyond_gap_limit() for address in addr_list: num = self.wallet.get_address_history_len(address) label = self.wallet.labels.get(address, '') c, u, x = self.wallet.get_addr_balance(address) balance = c + u + x is_used_and_empty = self.wallet.is_used(address) and balance == 0 if self.show_used == AddressUsageStateFilter.UNUSED and (balance or is_used_and_empty): continue if self.show_used == AddressUsageStateFilter.FUNDED and balance == 0: continue if self.show_used == AddressUsageStateFilter.USED_AND_EMPTY and not is_used_and_empty: continue balance_text = self.parent.format_amount(balance, whitespaces=True) # create item if fx and fx.get_fiat_address_config(): rate = fx.exchange_rate() fiat_balance = fx.value_str(balance, rate) else: fiat_balance = '' labels = ['', address, label, balance_text, fiat_balance, "%d"%num] address_item = [QStandardItem(e) for e in labels] # align text and set fonts for i, item in enumerate(address_item): item.setTextAlignment(Qt.AlignVCenter) if i not in (self.Columns.TYPE, self.Columns.LABEL): item.setFont(QFont(MONOSPACE_FONT)) self.set_editability(address_item) address_item[self.Columns.FIAT_BALANCE].setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) # setup column 0 if self.wallet.is_change(address): address_item[self.Columns.TYPE].setText(_('change')) address_item[self.Columns.TYPE].setBackground(ColorScheme.YELLOW.as_color(True)) else: address_item[self.Columns.TYPE].setText(_('receiving')) address_item[self.Columns.TYPE].setBackground(ColorScheme.GREEN.as_color(True)) address_item[self.Columns.LABEL].setData(address, Qt.UserRole) address_path = self.wallet.get_address_index(address) address_item[self.Columns.TYPE].setData(address_path, self.ROLE_SORT_ORDER) address_path_str = self.wallet.get_address_path_str(address) if address_path_str is not None: address_item[self.Columns.TYPE].setToolTip(address_path_str) address_item[self.Columns.FIAT_BALANCE].setData(balance, self.ROLE_SORT_ORDER) # setup column 1 if self.wallet.is_frozen_address(address): address_item[self.Columns.ADDRESS].setBackground(ColorScheme.BLUE.as_color(True)) if address in addresses_beyond_gap_limit: address_item[self.Columns.ADDRESS].setBackground(ColorScheme.RED.as_color(True)) # add item count = self.std_model.rowCount() self.std_model.insertRow(count, address_item) address_idx = self.std_model.index(count, self.Columns.LABEL) if address == current_address: set_address = QPersistentModelIndex(address_idx) self.set_current_idx(set_address) # show/hide columns if fx and fx.get_fiat_address_config(): self.showColumn(self.Columns.FIAT_BALANCE) else: self.hideColumn(self.Columns.FIAT_BALANCE) self.filter() self.proxy.setDynamicSortFilter(True) def create_menu(self, position): from electrum.wallet import Multisig_Wallet is_multisig = isinstance(self.wallet, Multisig_Wallet) can_delete = self.wallet.can_delete_address() selected = self.selected_in_column(self.Columns.ADDRESS) if not selected: return multi_select = len(selected) > 1 addrs = [self.item_from_index(item).text() for item in selected] menu = QMenu() if not multi_select: idx = self.indexAt(position) if not idx.isValid(): return item = self.item_from_index(idx) if not item: return addr = addrs[0] addr_column_title = self.std_model.horizontalHeaderItem(self.Columns.LABEL).text() addr_idx = idx.sibling(idx.row(), self.Columns.LABEL) self.add_copy_menu(menu, idx) menu.addAction(_('Details'), lambda: self.parent.show_address(addr)) persistent = QPersistentModelIndex(addr_idx) menu.addAction(_("Edit {}").format(addr_column_title), lambda p=persistent: self.edit(QModelIndex(p))) #menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr)) if self.wallet.can_export(): menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr)) if not is_multisig and not self.wallet.is_watching_only(): menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr)) menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr)) if can_delete: menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr)) addr_URL = block_explorer_URL(self.config, 'addr', addr) if addr_URL: menu.addAction(_("View on block explorer"), lambda: webopen(addr_URL)) if not self.wallet.is_frozen_address(addr): menu.addAction(_("Freeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], True)) else: menu.addAction(_("Unfreeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], False)) coins = self.wallet.get_spendable_coins(addrs) if coins: menu.addAction(_("Spend from"), lambda: self.parent.utxo_list.set_spend_list(coins)) run_hook('receive_menu', menu, addrs, self.wallet) menu.exec_(self.viewport().mapToGlobal(position)) def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: if is_address(text): try: self.wallet.check_address_for_corruption(text) except InternalAddressCorruption as e: self.parent.show_error(str(e)) raise super().place_text_on_clipboard(text, title=title)
class BookmarksWidget(QWidget): def __init__(self, parent=None): # pylint: disable=too-many-statements super(BookmarksWidget, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('BookmarksPanel created before Dwarf exists') return self.bookmarks = {} self._bookmarks_list = DwarfListView() self._bookmarks_list.doubleClicked.connect(self._on_double_clicked) self._bookmarks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._bookmarks_list.customContextMenuRequested.connect( self._on_contextmenu) self._bookmarks_model = QStandardItemModel(0, 2) self._bookmarks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._bookmarks_model.setHeaderData(1, Qt.Horizontal, 'Notes') self._bookmarks_list.setModel(self._bookmarks_model) self._bookmarks_list.header().setStretchLastSection(False) self._bookmarks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._bookmarks_list.header().setSectionResizeMode( 1, QHeaderView.Stretch | QHeaderView.Interactive) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._bookmarks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(lambda: self._create_bookmark(-1)) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._bookmarks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_B), self._app_window, self._create_bookmark) shortcut_addnative.setAutoRepeat(False) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def delete_items(self): """ Delete selected Items """ index = self._bookmarks_list.selectionModel().currentIndex().row() if index != -1: self._on_delete_bookmark(index) self._bookmarks_model.removeRow(index) def clear_list(self): """ Clear the List """ # go through all items and tell it gets removed for item in range(self._bookmarks_model.rowCount()): self._on_delete_bookmark(item) if self._bookmarks_model.rowCount() > 0: # something was wrong it should be empty self._bookmarks_model.removeRows(0, self._bookmarks_model.rowCount()) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_double_clicked(self, index): index = self._bookmarks_list.selectionModel().currentIndex().row() if index != -1: addr = self._bookmarks_model.item(index, 0).text() if addr: self._app_window.jump_to_address(addr, view=1) def _on_contextmenu(self, pos): context_menu = QMenu(self) index = self._bookmarks_list.indexAt(pos).row() if index != -1: context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._bookmarks_model.item(index, 0).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._bookmarks_model.item(index, 0).text())) # todo: add breakpoint address menu context_menu.addSeparator() context_menu.addAction('Edit', lambda: self._create_bookmark(index=index)) context_menu.addAction('Delete', lambda: self._on_delete_bookmark(index)) context_menu.addSeparator() if self._bookmarks_list.search_enabled: context_menu.addSeparator() context_menu.addAction('Search', self._bookmarks_list._on_cm_search) context_menu.addSeparator() context_menu.addAction('New', self._create_bookmark) global_pt = self._bookmarks_list.mapToGlobal(pos) context_menu.exec(global_pt) # + button def _create_bookmark(self, index=-1, ptr='', note=''): if ptr == '': if isinstance(index, int) and index >= 0: ptr = self._bookmarks_model.item(index, 0).text() note = self._bookmarks_model.item(index, 1).text() ptr, _ = InputDialog.input_pointer(parent=self._app_window, input_content=ptr) else: ptr = utils.parse_ptr(ptr) if ptr > 0: ptr = hex(ptr) if self._bookmarks_list.uppercase_hex: ptr = ptr.upper().replace('0X', '0x') index = self._bookmarks_model.findItems(ptr, Qt.MatchExactly) if len(index) > 0: index = index[0].row() note = self._bookmarks_model.item(index, 1).text() else: index = -1 accept = note != '' if note == '': accept, note = InputDialog.input(hint='Insert notes for %s' % ptr, input_content=note) if accept: if index < 0: self.insert_bookmark(ptr, note) else: item = self._bookmarks_model.item(index, 0) item.setText(ptr) item = self._bookmarks_model.item(index, 1) item.setText(note) self.bookmarks[ptr] = note def insert_bookmark(self, ptr_as_hex, note): if self._bookmarks_list.uppercase_hex: ptr_as_hex = ptr_as_hex.upper().replace('0X', '0x') self._bookmarks_model.appendRow( [QStandardItem(ptr_as_hex), QStandardItem(note)]) self._bookmarks_list.resizeColumnToContents(0) def is_address_bookmarked(self, ptr): return utils.parse_ptr(ptr) in self.bookmarks # shortcuts/menu def _on_delete_bookmark(self, index): ptr = self._bookmarks_model.item(index, 0).text() del self.bookmarks[ptr] self._bookmarks_model.removeRow(index)
def __init__(self, *args): super(TableViewSelectTypes, self).__init__(args[1]) self.tableView = args[1] self._text = '' gMainWindow = GlobalObjs.GetValue('MainWindow') self.setModal(True) #self.setModel(True) self.setWindowTitle('Select Type') self.vboxLayout = QtWidgets.QVBoxLayout(self) self.tree = QTreeView(self) self.model = QStandardItemModel(self) self.tree.setHeaderHidden(True) self.tree.setModel(self.model) self.bacisItem = QStandardItem() self.bacisItem.setText('BasicTypes') self.bacisItem.setFlags(QtCore.Qt.ItemIsEnabled) self.model.appendRow(self.bacisItem) self.tree.expand(self.bacisItem.index()) for v in GridTableView.BasicTypes: item = QStandardItem() item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) item.setText(v) item.setData(True) self.bacisItem.appendRow(item) if self.tableView.Model.activeColumn != args[2]: self.otherItem = QStandardItem() self.otherItem.setText('Other') self.otherItem.setFlags(QtCore.Qt.ItemIsEnabled) self.model.appendRow(self.otherItem) self.tree.expand(self.otherItem.index()) def LoadOtherTypes(item, parent): for i in range(0, item.rowCount()): childItem = item.child(i, 0) if childItem.data(Qt.UserRole + 2) == self.tableView.Model: continue itemAdd = QStandardItem() itemAdd.setText(childItem.text()) if childItem.data() == 3: itemAdd.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) else: itemAdd.setFlags(QtCore.Qt.ItemIsEnabled) LoadOtherTypes(childItem, itemAdd) parent.appendRow(itemAdd) LoadOtherTypes(gMainWindow.TreeRootItem, self.otherItem) self.vboxLayout.addWidget(self.tree) self.tree.doubleClicked.connect(self.OnDoubleClicked) self.tree.setFocus() self.show()
class InvoiceList(MyTreeView): class Columns(IntEnum): DATE = 0 DESCRIPTION = 1 AMOUNT = 2 STATUS = 3 headers = { Columns.DATE: _('Date'), Columns.DESCRIPTION: _('Description'), Columns.AMOUNT: _('Amount'), Columns.STATUS: _('Status'), } filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT] def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DESCRIPTION, editable_columns=[]) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.update() def update_item(self, key, invoice: Invoice): model = self.std_model for row in range(0, model.rowCount()): item = model.item(row, 0) if item.data(ROLE_REQUEST_ID) == key: break else: return status_item = model.item(row, self.Columns.STATUS) status = self.parent.wallet.get_invoice_status(invoice) status_str = invoice.get_status_str(status) if self.parent.wallet.lnworker: log = self.parent.wallet.lnworker.logs.get(key) if log and status == PR_INFLIGHT: status_str += '... (%d)' % len(log) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update(self): # not calling maybe_defer_update() as it interferes with conditional-visibility self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.update_headers(self.__class__.headers) for idx, item in enumerate(self.parent.wallet.get_invoices()): if item.is_lightning(): key = item.rhash icon_name = 'lightning.png' else: key = item.id icon_name = 'bitcoin.png' if item.bip70: icon_name = 'seal.png' status = self.parent.wallet.get_invoice_status(item) status_str = item.get_status_str(status) message = item.message amount = item.amount timestamp = item.time or 0 date_str = format_time(timestamp) if timestamp else _('Unknown') amount_str = self.parent.format_amount(amount, whitespaces=True) labels = [date_str, message, amount_str, status_str] items = [QStandardItem(e) for e in labels] self.set_editability(items) items[self.Columns.DATE].setIcon(read_QIcon(icon_name)) items[self.Columns.STATUS].setIcon(read_QIcon( pr_icons.get(status))) items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID) items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER) self.std_model.insertRow(idx, items) self.filter() self.proxy.setDynamicSortFilter(True) # sort requests by date self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder) # hide list if empty if self.parent.isVisible(): b = self.std_model.rowCount() > 0 self.setVisible(b) self.parent.invoices_label.setVisible(b) def create_menu(self, position): wallet = self.parent.wallet items = self.selected_in_column(0) if len(items) > 1: keys = [item.data(ROLE_REQUEST_ID) for item in items] invoices = [wallet.invoices.get(key) for key in keys] can_batch_pay = all([ i.type == PR_TYPE_ONCHAIN and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices ]) menu = QMenu(self) if can_batch_pay: menu.addAction( _("Batch pay invoices"), lambda: self.parent.pay_multiple_invoices(invoices)) menu.addAction(_("Delete invoices"), lambda: self.parent.delete_invoices(keys)) menu.exec_(self.viewport().mapToGlobal(position)) return idx = self.indexAt(position) item = self.item_from_index(idx) item_col0 = self.item_from_index( idx.sibling(idx.row(), self.Columns.DATE)) if not item or not item_col0: return key = item_col0.data(ROLE_REQUEST_ID) invoice = self.parent.wallet.get_invoice(key) menu = QMenu(self) self.add_copy_menu(menu, idx) if invoice.is_lightning(): menu.addAction(_("Details"), lambda: self.parent.show_lightning_invoice(invoice)) else: if len(invoice.outputs) == 1: menu.addAction( _("Copy Address"), lambda: self.parent.do_copy(invoice.get_address(), title='Bitcoin Address')) menu.addAction(_("Details"), lambda: self.parent.show_onchain_invoice(invoice)) status = wallet.get_invoice_status(invoice) if status == PR_UNPAID: menu.addAction(_("Pay"), lambda: self.parent.do_pay_invoice(invoice)) if status == PR_FAILED: menu.addAction(_("Retry"), lambda: self.parent.do_pay_invoice(invoice)) if self.parent.wallet.lnworker: log = self.parent.wallet.lnworker.logs.get(key) if log: menu.addAction(_("View log"), lambda: self.show_log(key, log)) menu.addAction(_("Delete"), lambda: self.parent.delete_invoices([key])) menu.exec_(self.viewport().mapToGlobal(position)) def show_log(self, key, log: Sequence[PaymentAttemptLog]): d = WindowModalDialog(self, _("Payment log")) d.setMinimumWidth(600) vbox = QVBoxLayout(d) log_w = QTreeWidget() log_w.setHeaderLabels([_('Hops'), _('Channel ID'), _('Message')]) log_w.header().setSectionResizeMode(2, QHeaderView.Stretch) log_w.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) for payment_attempt_log in log: route_str, chan_str, message = payment_attempt_log.formatted_tuple( ) x = QTreeWidgetItem([route_str, chan_str, message]) log_w.addTopLevelItem(x) vbox.addWidget(log_w) vbox.addLayout(Buttons(CloseButton(d))) d.exec_()
class TableViewSelectTypes(QtWidgets.QDialog): def setText(self, text): self._text = text if text in GridTableView.BasicTypes: self.tree.expand(self.bacisItem.index()) for i in range(self.bacisItem.rowCount()): childItem = self.bacisItem.child(i, 0) if childItem.text() == text: self.tree.setCurrentIndex(childItem.index()) else: self.tree.expand(self.otherItem.index()) names = text.split('.') parentItem = self.otherItem for v in names: isBreak = False for i in range(parentItem.rowCount()): if isBreak == True: continue if parentItem.child(i, 0).text() == v: parentItem = parentItem.child(i, 0) self.tree.expand(parentItem.index()) isBreak = True continue self.tree.setCurrentIndex(parentItem.index()) def text(self): return self._text def __init__(self, *args): super(TableViewSelectTypes, self).__init__(args[1]) self.tableView = args[1] self._text = '' gMainWindow = GlobalObjs.GetValue('MainWindow') self.setModal(True) #self.setModel(True) self.setWindowTitle('Select Type') self.vboxLayout = QtWidgets.QVBoxLayout(self) self.tree = QTreeView(self) self.model = QStandardItemModel(self) self.tree.setHeaderHidden(True) self.tree.setModel(self.model) self.bacisItem = QStandardItem() self.bacisItem.setText('BasicTypes') self.bacisItem.setFlags(QtCore.Qt.ItemIsEnabled) self.model.appendRow(self.bacisItem) self.tree.expand(self.bacisItem.index()) for v in GridTableView.BasicTypes: item = QStandardItem() item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) item.setText(v) item.setData(True) self.bacisItem.appendRow(item) if self.tableView.Model.activeColumn != args[2]: self.otherItem = QStandardItem() self.otherItem.setText('Other') self.otherItem.setFlags(QtCore.Qt.ItemIsEnabled) self.model.appendRow(self.otherItem) self.tree.expand(self.otherItem.index()) def LoadOtherTypes(item, parent): for i in range(0, item.rowCount()): childItem = item.child(i, 0) if childItem.data(Qt.UserRole + 2) == self.tableView.Model: continue itemAdd = QStandardItem() itemAdd.setText(childItem.text()) if childItem.data() == 3: itemAdd.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) else: itemAdd.setFlags(QtCore.Qt.ItemIsEnabled) LoadOtherTypes(childItem, itemAdd) parent.appendRow(itemAdd) LoadOtherTypes(gMainWindow.TreeRootItem, self.otherItem) self.vboxLayout.addWidget(self.tree) self.tree.doubleClicked.connect(self.OnDoubleClicked) self.tree.setFocus() self.show() def OnDoubleClicked(self, index): item = self.model.itemFromIndex(index) if item.flags( ) == QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable: if item.data() == True: self.setText(index.data()) else: names = [] parent = index while True: names.append(parent.data()) parent = parent.parent() if parent.isValid() == False or self.otherItem.index( ) == parent: break self.setText('.'.join(reversed(names))) self.done(QtWidgets.QDialog.Accepted)
def __init__(self, parent=None): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences super(MainWindow, self).__init__(parent=parent) self.setupUi(self) # Set up song list (left hand side of screen) self.SongListModel = QStandardItemModel() self.SongList.setModel(self.SongListModel) # Work out the directory where the python/executable lives - preferences are within this dir. self.HomeDirectory = os.getcwd() self.SongPreferencesFileName = self.HomeDirectory + '\\OpenSongViewerPrefs.json' IntroText = "Hello there<br><br>" IntroText = IntroText + "<i>OpenSongViewer version " + VersionNumber + " " IntroText = IntroText + VersionInformation + "</i><br><br>" IntroText = IntroText + "Remember to set the location of your OpenSong songs in the preferences<br><br>" IntroText = IntroText + "Click on <br>" IntroText = IntroText + " * Add - to add a song to the song list<br>" IntroText = IntroText + " * Rem - to remove the current selected song to the song list<br>" IntroText = IntroText + " * Edit - to edit the current selected song to the song list<br><br>" IntroText = IntroText + "Remember to save your song list using 'Song List' -> 'Save As...' - it'll retain order and keys<br>" IntroText = IntroText + "Remember to check your current preferences under the file menu<br>" IntroText = IntroText + "<br>" IntroText = IntroText + "Changelog:<br>" IntroText = IntroText + "0.5 - bugfix - when transposing and base key was 'B' the value key didn't update<br>" IntroText = IntroText + " * Improvement - when you select a song in the songlist, you can now use right and left cursor or arrows under the songlist to move up and down the list<br>" IntroText = IntroText + " * Improvement - new preference setting - when editing, you can choose to always edit in the original base key, or edit in the current transposed value<br>" IntroText = IntroText + " - NOTE - if you edit in the current transposed value, this will overwrite the original base key<br>" IntroText = IntroText + " - this means that chord characters can move slightly when the base key switches from a single to a double character - e.g. 'C' to 'Db'<br>" self.SongText.setText(IntroText) # try to pull in the preferences try: with open(self.SongPreferencesFileName) as f: SongPreferences = json.load(f) except: # none found - set default prefs. SongPreferences['PREFSVER'] = '0.5' SongPreferences['SONGDIR'] = self.HomeDirectory SongPreferences['DEFAULTFONTSIZE'] = '25' SongPreferences['DEFAULTPAGESIZE'] = '38' SongPreferences['SHARPFLAT_C'] = 'C#' SongPreferences['SHARPFLAT_D'] = 'D#' SongPreferences['SHARPFLAT_F'] = 'F#' SongPreferences['SHARPFLAT_G'] = 'G#' SongPreferences['SHARPFLAT_A'] = 'A#' SongPreferences['EDIT_USE_ORIGINALKEY'] = 'ORIGINALKEY' if type(SongPreferences) is list: # V0.1 preferences used lists instead of dict - convert and re-save print('Old V0.1 preferences file format - upgraded to v0.2') OLDPrefs = SongPreferences SongPreferences = {} SongPreferences['PREFSVER'] = '0.2' SongPreferences['SONGDIR'] = OLDPrefs[0][1] # Overwrite old file with open(self.SongPreferencesFileName, 'w') as f: json.dump(SongPreferences, f) if SongPreferences['PREFSVER'] == '0.2': # Upgrade preferences values - put in default values. SongPreferences['PREFSVER'] = '0.3' SongPreferences['DEFAULTFONTSIZE'] = '25' SongPreferences['SHARPFLAT_C'] = 'C#' SongPreferences['SHARPFLAT_D'] = 'D#' SongPreferences['SHARPFLAT_F'] = 'F#' SongPreferences['SHARPFLAT_G'] = 'G#' SongPreferences['SHARPFLAT_A'] = 'A#' if SongPreferences['PREFSVER'] == '0.3': SongPreferences['PREFSVER'] = '0.4' SongPreferences['DEFAULTPAGESIZE'] = '38' if SongPreferences['PREFSVER'] == '0.4': # 0.5 brings in edit use original key, or use transposed value # normal is to keep the base key SongPreferences['PREFSVER'] = '0.5' SongPreferences['EDIT_USE_ORIGINALKEY'] = 'ORIGINALKEY' self.InterpretPreferences() # Wire up the buttons self.AddSong.clicked.connect(self.AddNewSong) self.DeleteSong.clicked.connect(self.DelSelectedSong) self.EditSong.clicked.connect(self.EditCurrentSong) self.SongList.clicked.connect(self.SongListSelected) self.TransposeMinus.clicked.connect(self.TransposeMinusSelected) self.TransposePlus.clicked.connect(self.TransposePlusSelected) self.actionClear_List.triggered.connect(self.ClearAll) self.actionEdit.triggered.connect(self.EditCurrentSong) self.actionNew.triggered.connect(self.NewSong) self.actionSave_Song_List.triggered.connect(self.SaveSongList) self.actionLoad_Song_List.triggered.connect(self.LoadSongList) self.actionSave_Song_List_As.triggered.connect(self.SaveSongListAs) self.actionPreferences.triggered.connect(self.UpdatePrefs) self.actionAbout.triggered.connect(self.AboutWindow) self.NextSong.clicked.connect(self.MoveNextSong) self.PrevSong.clicked.connect(self.MovePrevSong)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): CurrentSong = '' CurrentSongKey = '' CurrentOffset = 0 # Directory that holds the song files - picked up from preferences SongLocation = '' # Directory holding this program HomeDirectory = '' # Location and name of preferences file - this is held in the same directory as the program SongPreferencesFileName = '' # Default songlist file name - we save after change (transpose etc) SaveFileName = 'SongData.json' def __init__(self, parent=None): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences super(MainWindow, self).__init__(parent=parent) self.setupUi(self) # Set up song list (left hand side of screen) self.SongListModel = QStandardItemModel() self.SongList.setModel(self.SongListModel) # Work out the directory where the python/executable lives - preferences are within this dir. self.HomeDirectory = os.getcwd() self.SongPreferencesFileName = self.HomeDirectory + '\\OpenSongViewerPrefs.json' IntroText = "Hello there<br><br>" IntroText = IntroText + "<i>OpenSongViewer version " + VersionNumber + " " IntroText = IntroText + VersionInformation + "</i><br><br>" IntroText = IntroText + "Remember to set the location of your OpenSong songs in the preferences<br><br>" IntroText = IntroText + "Click on <br>" IntroText = IntroText + " * Add - to add a song to the song list<br>" IntroText = IntroText + " * Rem - to remove the current selected song to the song list<br>" IntroText = IntroText + " * Edit - to edit the current selected song to the song list<br><br>" IntroText = IntroText + "Remember to save your song list using 'Song List' -> 'Save As...' - it'll retain order and keys<br>" IntroText = IntroText + "Remember to check your current preferences under the file menu<br>" IntroText = IntroText + "<br>" IntroText = IntroText + "Changelog:<br>" IntroText = IntroText + "0.5 - bugfix - when transposing and base key was 'B' the value key didn't update<br>" IntroText = IntroText + " * Improvement - when you select a song in the songlist, you can now use right and left cursor or arrows under the songlist to move up and down the list<br>" IntroText = IntroText + " * Improvement - new preference setting - when editing, you can choose to always edit in the original base key, or edit in the current transposed value<br>" IntroText = IntroText + " - NOTE - if you edit in the current transposed value, this will overwrite the original base key<br>" IntroText = IntroText + " - this means that chord characters can move slightly when the base key switches from a single to a double character - e.g. 'C' to 'Db'<br>" self.SongText.setText(IntroText) # try to pull in the preferences try: with open(self.SongPreferencesFileName) as f: SongPreferences = json.load(f) except: # none found - set default prefs. SongPreferences['PREFSVER'] = '0.5' SongPreferences['SONGDIR'] = self.HomeDirectory SongPreferences['DEFAULTFONTSIZE'] = '25' SongPreferences['DEFAULTPAGESIZE'] = '38' SongPreferences['SHARPFLAT_C'] = 'C#' SongPreferences['SHARPFLAT_D'] = 'D#' SongPreferences['SHARPFLAT_F'] = 'F#' SongPreferences['SHARPFLAT_G'] = 'G#' SongPreferences['SHARPFLAT_A'] = 'A#' SongPreferences['EDIT_USE_ORIGINALKEY'] = 'ORIGINALKEY' if type(SongPreferences) is list: # V0.1 preferences used lists instead of dict - convert and re-save print('Old V0.1 preferences file format - upgraded to v0.2') OLDPrefs = SongPreferences SongPreferences = {} SongPreferences['PREFSVER'] = '0.2' SongPreferences['SONGDIR'] = OLDPrefs[0][1] # Overwrite old file with open(self.SongPreferencesFileName, 'w') as f: json.dump(SongPreferences, f) if SongPreferences['PREFSVER'] == '0.2': # Upgrade preferences values - put in default values. SongPreferences['PREFSVER'] = '0.3' SongPreferences['DEFAULTFONTSIZE'] = '25' SongPreferences['SHARPFLAT_C'] = 'C#' SongPreferences['SHARPFLAT_D'] = 'D#' SongPreferences['SHARPFLAT_F'] = 'F#' SongPreferences['SHARPFLAT_G'] = 'G#' SongPreferences['SHARPFLAT_A'] = 'A#' if SongPreferences['PREFSVER'] == '0.3': SongPreferences['PREFSVER'] = '0.4' SongPreferences['DEFAULTPAGESIZE'] = '38' if SongPreferences['PREFSVER'] == '0.4': # 0.5 brings in edit use original key, or use transposed value # normal is to keep the base key SongPreferences['PREFSVER'] = '0.5' SongPreferences['EDIT_USE_ORIGINALKEY'] = 'ORIGINALKEY' self.InterpretPreferences() # Wire up the buttons self.AddSong.clicked.connect(self.AddNewSong) self.DeleteSong.clicked.connect(self.DelSelectedSong) self.EditSong.clicked.connect(self.EditCurrentSong) self.SongList.clicked.connect(self.SongListSelected) self.TransposeMinus.clicked.connect(self.TransposeMinusSelected) self.TransposePlus.clicked.connect(self.TransposePlusSelected) self.actionClear_List.triggered.connect(self.ClearAll) self.actionEdit.triggered.connect(self.EditCurrentSong) self.actionNew.triggered.connect(self.NewSong) self.actionSave_Song_List.triggered.connect(self.SaveSongList) self.actionLoad_Song_List.triggered.connect(self.LoadSongList) self.actionSave_Song_List_As.triggered.connect(self.SaveSongListAs) self.actionPreferences.triggered.connect(self.UpdatePrefs) self.actionAbout.triggered.connect(self.AboutWindow) self.NextSong.clicked.connect(self.MoveNextSong) self.PrevSong.clicked.connect(self.MovePrevSong) # Do anything based on preferences settings - copy values to variables etc. def InterpretPreferences(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Go through the preferences and set variables. self.SongLocation = SongPreferences['SONGDIR'] # General routine to ask a query on screen def AskQuery(self, QueryTitle, QueryText): resp = QMessageBox.question(self, QueryTitle, QueryText, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if resp == 16384: return "YES" else: return "NO" # General routine to ask a query on screen def OkMessage(self, QueryTitle, QueryText): resp = QMessageBox.question(self, QueryTitle, QueryText, QMessageBox.Ok, QMessageBox.Ok) # Save the current song list, but specify a location. def SaveSongListAs(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Set the new default file name for songs. options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog SaveFile = QFileDialog.getSaveFileName(self, 'Save Song List As', self.SongLocation) # Get the file name Fname = SaveFile[0] # Linux / windows if os.sep == '\\': Fname = Fname.replace('/', '\\') # set the new default file name for songs self.SaveFileName = Fname # and save the songlist self.SaveSongList() def NavigateSong(self, Direction): # Improvement 20210401 # Click in the Main SongList - you can then use right and left keys to # move through the songs instead of having to click on specific songs # its slightly more efficient when playing live... global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Get the total rows in the list, so we can wrap around TotalRows = self.SongListModel.rowCount() # And the current song CurrentSelected = self.SongList.currentIndex().row() if Direction == "DOWN": NewSelected = CurrentSelected + 1 print("Next song") else: NewSelected = CurrentSelected - 1 print("Previous song") # We only want to do stuff if there's a list there... if TotalRows > 0: # Do we need to wrap around? if NewSelected < 0: NewSelected = TotalRows - 1 if NewSelected >= TotalRows: NewSelected = 0 # print("Total:"+str(TotalRows)+" Current:"+str(CurrentSelected)+" New:"+str(NewSelected)) # Set the updated selection value index = self.SongListModel.index(NewSelected, 0, QModelIndex()) self.SongList.setCurrentIndex(index) # To display the song, we need the song title, so get it from the list... SongTitle = self.SongListModel.index(NewSelected, 0).data() # and display the updated song. self.DisplaySong(SongTitle) def MoveNextSong(self): self.NavigateSong("DOWN") def MovePrevSong(self): self.NavigateSong("UP") def keyPressEvent(self, event): # Improvement 20210401 # Click in the Main SongList - you can then use right and left keys to # move through the songs instead of having to click on specific songs # its slightly more efficient when playing live... global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Get the total rows in the list, so we can wrap around TotalRows = self.SongListModel.rowCount() # And the current song CurrentSelected = self.SongList.currentIndex().row() # Use -1 as 'no movement' NewSelected = -1 # If we press right or left, capture it and set NewSelected if event.key() == Qt.Key_Right: print("Right pressed") self.NavigateSong("DOWN") if event.key() == Qt.Key_Left: print("Left pressed") self.NavigateSong("UP") # Save the song list to the current default file name def SaveSongList(self): # Take the current songdata and save this to a file e.g. 'SongData.json' global SongDataList global SongKeys global SongKeys_Alt global SongPreferences SaveFileName = self.SaveFileName with open(SaveFileName, 'w') as f: json.dump(SongDataList, f) print("Saved updated song list " + SaveFileName) # Load a song list def LoadSongList(self): # Identify and load songdata, then update the screen. global SongDataList global SongKeys global SongKeys_Alt global SongPreferences options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName = QFileDialog.getOpenFileName(self, 'Open file', self.SongLocation, 'OpenFile(*)') if fileName and len(fileName[0]) > 0: # If Windows, change the separator FName = fileName[0] if os.sep == '\\': FName = FName.replace('/', '\\') # Set the default from now on... self.SaveFileName = FName # Now, open then file and read the JSON data. with open(FName) as f: SongDataList = json.load(f) # Clear out and populate the song list panel. self.SongListModel.clear() # Add the files to the on-screen list Ptr = 0 try: while Ptr < len(SongDataList): FName = SongDataList[Ptr][4] item = QStandardItem(FName) self.SongListModel.appendRow(item) Ptr = Ptr + 1 except: self.OkMessage( 'Load error', 'Song list file is not compatible with this version - sorry' ) # Given a song name, find the location within the main song array and return the number def LocateSong(self, SongName): # Locate the song... global SongDataList global SongKeys global SongKeys_Alt global SongPreferences Ptr = 0 RetValue = -1 while Ptr < len(SongDataList) and RetValue == -1: if SongDataList[Ptr][4] == SongName: # Located the song information... RetValue = Ptr Ptr = Ptr + 1 return RetValue # Transpose - go down a key def TransposeMinusSelected(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Locate the song... SongPtr = self.LocateSong(self.CurrentSong) if SongPtr > -1: # got a valid song.. print("Located song") # Take it down a key SongDataList[SongPtr][3] -= 1 # 0 1 2 3 4 5 6 7 8 9 10 11 # c c# d d# e f f# g g# a a# b # Wraparound if necessary if SongDataList[SongPtr][3] < 0: SongDataList[SongPtr][3] = 11 # now re-display self.DisplaySong(self.CurrentSong) # we've made a change to the song set - save the list self.SaveSongList() # Transpost - go up a key def TransposePlusSelected(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Locate the song... SongPtr = self.LocateSong(self.CurrentSong) if SongPtr > -1: # got a valid song.. print("Located song") # take it up a key SongDataList[SongPtr][3] += 1 # 0 1 2 3 4 5 6 7 8 9 10 11 # c c# d d# e f f# g g# a a# b # too high - wraparound if SongDataList[SongPtr][3] > 11: SongDataList[SongPtr][3] = 0 # now re-display self.DisplaySong(self.CurrentSong) # we've made a change - save the song set. self.SaveSongList() # Given a song name, put the song text onto screen # Note - if the song offset is not zero, it transposes to the correct chord # we don't ever overwrite the original chords - we re-work out each time # doing it this way means that the positioning won't change if you keep transposing. def DisplaySong(self, SongName): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Locate the song... Ptr = self.LocateSong(SongName) if Ptr > -1: # Located the song information... SongText = SongDataList[Ptr][1] SongKey = SongDataList[Ptr][2] SongOffset = SongDataList[Ptr][3] ActualSongKey = Derive_Actual_Song_Key(SongKey, SongOffset) self.CurrentSong = SongName self.CurrentSongKey = SongKey self.CurrentOffset = SongOffset # In order to have the display in columns and have different colours for particular items etc # we use a HTML viewer to display the song text. # This means we can apply style sheets - however, it appears the HTML viewer doesn't # fully implement HTML? SongTextHeader = "<html><head>" SongTextHeader = SongTextHeader + "<style>" SongTextHeader = SongTextHeader + "body { background-color: #555555;} " SongTextHeader = SongTextHeader + "p { font-size: " + SongPreferences[ 'DEFAULTFONTSIZE'] + "px; margin: 0px;} " SongTextHeader = SongTextHeader + "table { width: 100%; border: 2px solid black; padding 20px;} " SongTextHeader = SongTextHeader + "tr { width: 100%; border: 2px solid black; padding 20px;} " SongTextHeader = SongTextHeader + "td { border: 2px solid black; padding 5px; background-color: #eeeeee;} " SongTextHeader = SongTextHeader + "</style>" SongTextHeader = SongTextHeader + "</head>" SongTextHeader = SongTextHeader + "<body>" OutputSongText = "<table><tr><td>" OutputSongText = OutputSongText + Derive_Song_Text( "YES", SongText, SongKey, SongOffset) # SongText is in 'SongText' variable - chords are defined with lines beginning with '.' # First, split the string on newlines. #SongTextLines = SongText.split('\n') # Now, go through the lines... #Ptr2 = 0 #SongTextLineNumber = 0 # Work through all the lines of text #while Ptr2 < (len(SongTextLines)-1): # Put the line we're working with into a working variable # TextLine = SongTextLines[Ptr2] # If its not a blank line # if len(TextLine) > 0: # is it a command line? # if TextLine[0] == '.': # Line begins with '.' - it contains chords - need to work through letter by letter # Ptr3 = 0 # pointer into the text line # OutputLine = '' # converted line # Create a temp line with extra spaces at the end - so we don't read past the end of line. # TempLine = TextLine + " " # while Ptr3 < len( TextLine ): # NewValue = ord(TextLine[Ptr3]) # if 65 <= NewValue <= 71: # This is a key value # Get the chord # NewString = TextLine[Ptr3] # Check: is this a minor or sharp? # if (TempLine[Ptr3+1] == 'M') or (TempLine[Ptr3+1] == '#') or (TempLine[Ptr3+1] == 'b'): # NewString = NewString+TextLine[Ptr3+1] # Ptr3 = Ptr3+1 # Check: is this a minor or sharp? # if (TempLine[Ptr3+1] == 'M') or (TempLine[Ptr3+1] == '#') or (TempLine[Ptr3+1] == 'b'): # NewString = NewString+TextLine[Ptr3+1] # Ptr3 = Ptr3+1 # NewString now contains the chord - convert it... # UpdatedChord = self.ConvertChord(NewString,SongOffset) # OutputLine = OutputLine+UpdatedChord # else: # OutputLine = OutputLine+TextLine[Ptr3] # Ptr3 = Ptr3+1 # Now put bold around it.. # OutputLine = "<b>"+OutputLine+"</b>" # else: # OutputLine = TextLine # else: # its a blank line # OutputLine = '\n ' # If we're too far down, go to another display column # if SongTextLineNumber > int(self.SongPreferences['DEFAULTPAGESIZE']) or "===" in TextLine: # SongTextLineNumber = 1 # OutputLine = OutputLine+'</td><td>' # print("NewLine") # TextLine = "<p>"+OutputLine+" </p>" # SongText = SongText+'\n'+TextLine # Ptr2 = Ptr2+1 # SongTextLineNumber = SongTextLineNumber+1 SongLyricsDisplay = OutputSongText.replace('\n.', '<b> ').replace( '\n ', '</b> ').replace(' ', ' ') SongLyricsDisplay = SongLyricsDisplay.replace('SUS', 'sus') SongLyricsDisplay = SongLyricsDisplay.replace( '[', '<b><font color=' 'red' '>[').replace(']', ']</font></b>') SongLyricsDisplay = SongTextHeader + SongLyricsDisplay + '</td></tr></table></body></html>' # print(SongLyricsDisplay) self.SongText.setText(SongLyricsDisplay) self.CurrentKey.setText(SongKeys_Alt[ActualSongKey]) # User has clicked on a song on the on-screen list - display the song. def SongListSelected(self, index): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # This is the selected song... SelectedString = index.data() self.DisplaySong(SelectedString) # Remove a song from the song list on screen def DelSelectedSong(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # del the currently selected song - i.e. 'self.CurrentSong' Result = self.AskQuery("Remove Song from list?", "Delete " + self.CurrentSong) if Result == "YES": # Yes - delete the item in the on-screen list listItems = self.SongList.selectedIndexes() if not listItems: return for item in listItems: self.SongListModel.removeRow(item.row()) Ptr = self.LocateSong(self.CurrentSong) if Ptr >= 0: ToRemove = SongDataList[Ptr] SongDataList.remove(ToRemove) print("Removed: " + self.CurrentSong) # Clear the song list on-screen and data structure def ClearAll(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences Result = self.AskQuery("Clear Songlist?", "Clear Songlist?") if Result == "YES": self.SongListModel.clear() SongDataList = [] print("Cleared") # Save a specific song name from the data structure to a song file # Save the file in 'OpenSong' format (xml) def SaveSong(self, SongName): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Locate the given song Ptr = self.LocateSong(self.CurrentSong) if Ptr >= 0: # Get the data about the song SingleSongData = SongDataList[Ptr] # Get the default song location and add the song name Fname = self.SongLocation + '/' + SongName # Linux / windows if os.sep == '\\': Fname = Fname.replace('/', '\\') # 0.4: Open the original song we're going to overwrite # and grab the data from it - so that we preserve # the information when we overwrite # if the song is 'brand new' then we'll not be able # to open, and should go through the exception handler # and we can set default values. # If the file already exists, read the file in and overwrite # individual elements # otherwise create a file from scratch. if os.path.isfile(Fname): try: with open(Fname, 'r') as Originalfile: SongData = Originalfile.read() # tree contains the tree structure tree = ET.ElementTree(ET.fromstring(SongData)) # Overwrite the items within the XML... tree.find('title').text = SingleSongData[4] tree.find('lyrics').text = SingleSongData[1] tree.find('key').text = SingleSongData[2] # overwrite the original file with the updated values tree.write(Fname) except: self.OkMessage("Problem overwriting file...", sys.exc_info()[0]) else: # the file doesn't exist - so we need to create a new file from scratch # Work out the text to save. New_FileName = Fname New_SongText = '<?xml version="1.0" encoding="UTF-8"?>\n' New_SongText = New_SongText + '<song>\n' New_SongText = New_SongText + '<title>' + SingleSongData[ 4] + '</title>\n' New_SongText = New_SongText + ' <lyrics>' New_SongText = New_SongText + SingleSongData[1] + '\n' New_SongText = New_SongText + ' </lyrics>\n' New_SongText = New_SongText + '<author></author>\n' New_SongText = New_SongText + '<copyright></copyright>\n' New_SongText = New_SongText + '<hymn_number></hymn_number>\n' New_SongText = New_SongText + '<presentation></presentation>\n' New_SongText = New_SongText + '<ccli></ccli>\n' New_SongText = New_SongText + '<capo print = "false"></capo>\n' New_SongText = New_SongText + '<key>' + SingleSongData[ 2] + '</key>\n' New_SongText = New_SongText + '<aka></aka>\n' New_SongText = New_SongText + '<key_line></key_line>\n' New_SongText = New_SongText + '<user1></user1>\n' New_SongText = New_SongText + '<user2></user2>\n' New_SongText = New_SongText + '<user3></user3>\n' New_SongText = New_SongText + '<theme></theme>\n' New_SongText = New_SongText + '<linked_songs></linked_songs>\n' New_SongText = New_SongText + '<tempo></tempo>\n' New_SongText = New_SongText + '<time_sig></time_sig>\n' New_SongText = New_SongText + '<backgrounds resize="body" keep_aspect="false" link="false" background_as_text="false"/>\n' New_SongText = New_SongText + '</song>\n' # and write out the file with open(New_FileName, 'w') as myfile: myfile.write(New_SongText) # User has clicked on 'Edit' def EditCurrentSong(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Locate the song Ptr = self.LocateSong(self.CurrentSong) if Ptr > -1: SingleSongData = SongDataList[Ptr] # Initialise and show the song dlg = EditWindow(SingleSongData) # Activate the window on screen if dlg.exec_(): print("Success!") # Copy the song data to the main data structure SongDataList[Ptr][ 0] = self.SongLocation + '/' + dlg.ui.FName.text() SongDataList[Ptr][1] = dlg.ui.SongText.toPlainText() SongDataList[Ptr][2] = dlg.ui.SongKey.currentText() SongDataList[Ptr][3] = 0 SongDataList[Ptr][4] = dlg.ui.FName.text() self.DisplaySong(self.CurrentSong) self.SaveSong(self.CurrentSong) print('Edited song saved') else: print("Cancel!") # User has selected to add a new song def NewSong(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Create a blank song SingleSongData = ['a', 'a', 'a', 0, 'a'] SingleSongData[0] = self.SongLocation + '/New Song' SingleSongData[1] = '.C\n Words' SingleSongData[2] = 'C' SingleSongData[3] = 0 SingleSongData[4] = 'New Song' # Initialise the edit window dlg = EditWindow(SingleSongData) # Activate the edit window if dlg.exec_(): print("Success!") SingleSongData[0] = self.SongLocation + '/' + dlg.ui.FName.text() SingleSongData[1] = dlg.ui.SongText.toPlainText() SingleSongData[2] = dlg.ui.SongKey.currentText() SingleSongData[3] = 0 SingleSongData[4] = dlg.ui.FName.text() # Up to this point its the same as edit - however, now we need to add the # new song to the on-screen list, and display. SongDataList.append(SingleSongData) self.CurrentSong = SingleSongData[4] item = QStandardItem(self.CurrentSong) self.SongListModel.appendRow(item) self.DisplaySong(self.CurrentSong) self.SaveSong(self.CurrentSong) else: print("Cancel!") # User has selected to add a song to the list def AddNewSong(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # get the user to select a song. options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName = QFileDialog.getOpenFileName(self, 'Open file', self.SongLocation, 'OpenFile(*)') if fileName and len(fileName[0]) > 0: # If Windows, change the separator FName = fileName[0] # windows/linux if os.sep == '\\': FName = FName.replace('/', '\\') FName = FName.replace(self.SongLocation + '\\', '') item = QStandardItem(os.path.basename(FName)) self.SongListModel.appendRow(item) # Read in the song data, to add to the list... print("reading file...") with open(FName, 'r') as myfile: SongData = myfile.read() print("getting data") tree = ET.ElementTree(ET.fromstring(SongData)) # Interpret the XML into the main data structure print("getting lyrics") SongLyrics = list(tree.iter('lyrics')) print("getting key") KeyData = tree.find('key') if KeyData is None: SongKeyValue = 'C' else: SongKey = list(tree.iter('key')) if SongKey[0].text is None: SongKeyValue = 'C' else: SongKeyValue = SongKey[0].text print("create list element") # Create list element, SongName, LyricsText, Key, OffsetToKey print("Filename:" + FName) print("Lyrics:" + SongLyrics[0].text) print("Key:" + SongKeyValue) # Data structure # 0 - full file and path name # 1 - lyrics text # 2 - Base key # 3 - Offset # 4 - Basename (just the file name) NewSongData = [ FName, SongLyrics[0].text, SongKeyValue, 0, os.path.basename(FName) ] print("append into songdata") SongDataList.append(NewSongData) print("added") self.SaveSongList() def CleanString(self, InputString): OutputString = "" for Ptr in range(0, len(InputString)): if InputString[ Ptr] in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ()[]=:-": OutputString += InputString[Ptr] return OutputString # User has selected to edit prefs def UpdatePrefs(self): global SongDataList global SongKeys global SongKeys_Alt global SongPreferences # Initialise window dlg = Prefs() # Activate preferences screen if dlg.exec_(): print("Success!") # Pick up the values from screen SongPreferences['PREFSVER'] = '0.5' SongPreferences['SONGDIR'] = dlg.ui.SongDirectory.text() SongPreferences[ 'DEFAULTFONTSIZE'] = dlg.ui.DefaultFontSize.currentText() SongPreferences['DEFAULTPAGESIZE'] = dlg.ui.PageSize.currentText() if dlg.ui.radioButton_Cs.isChecked(): SongPreferences['SHARPFLAT_C'] = 'C#' else: SongPreferences['SHARPFLAT_C'] = 'Db' if dlg.ui.radioButton_Ds.isChecked(): SongPreferences['SHARPFLAT_D'] = 'D#' else: SongPreferences['SHARPFLAT_D'] = 'Eb' if dlg.ui.radioButton_Fs.isChecked(): SongPreferences['SHARPFLAT_F'] = 'F#' else: SongPreferences['SHARPFLAT_F'] = 'Gb' if dlg.ui.radioButton_Gs.isChecked(): SongPreferences['SHARPFLAT_G'] = 'G#' else: SongPreferences['SHARPFLAT_G'] = 'Ab' if dlg.ui.radioButton_As.isChecked(): SongPreferences['SHARPFLAT_A'] = 'A#' else: SongPreferences['SHARPFLAT_A'] = 'Bb' # 0.5 20210402 - edit using original key or transposed key if dlg.ui.EditOriginalKey.isChecked(): SongPreferences['EDIT_USE_ORIGINALKEY'] = 'ORIGINALKEY' else: SongPreferences['EDIT_USE_ORIGINALKEY'] = 'TRANSPOSEDKEY' with open(self.SongPreferencesFileName, 'w') as f: json.dump(SongPreferences, f) # Set up preference variables. self.InterpretPreferences() else: print("Cancel!") def AboutWindow(self): # Initialise window dlg = AboutWindow() # Activate preferences screen - user just has to click on OK dlg.exec_()
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) #fix stuff imposible to do in qtdesigner #remove dock titlebar for addressbar w = QWidget() self.ui.addrDockWidget.setTitleBarWidget(w) #tabify some docks self.tabifyDockWidget(self.ui.evDockWidget, self.ui.subDockWidget) self.tabifyDockWidget(self.ui.subDockWidget, self.ui.refDockWidget) # init widgets self.ui.statusBar.hide() self.ui.addrComboBox.insertItem(-1, "opc.tcp://localhost:4841/") self.ui.addrComboBox.insertItem( 1, "opc.tcp://localhost:53530/OPCUA/SimulationServer/") self.ui.addrComboBox.insertItem(1, "opc.tcp://10.0.5.15:49320/") self.attr_model = QStandardItemModel() self.refs_model = QStandardItemModel() self.sub_model = QStandardItemModel() self.ui.attrView.setModel(self.attr_model) self.ui.refView.setModel(self.refs_model) self.ui.subView.setModel(self.sub_model) self.model = MyModel(self) self.model.clear() self.model.error.connect(self.show_error) self.ui.treeView.setModel(self.model) self.ui.treeView.setUniformRowHeights(True) self.ui.treeView.setSelectionBehavior(QAbstractItemView.SelectRows) self.uaclient = UaClient() self.ui.connectButton.clicked.connect(self._connect) self.ui.disconnectButton.clicked.connect(self._disconnect) self.ui.treeView.activated.connect(self._show_attrs_and_refs) self.ui.treeView.clicked.connect(self._show_attrs_and_refs) self.ui.treeView.expanded.connect(self._fit) self.ui.actionSubscribeDataChange.triggered.connect(self._subscribe) self.ui.actionSubscribeEvent.triggered.connect(self._subscribeEvent) self.ui.actionConnect.triggered.connect(self._connect) self.ui.actionDisconnect.triggered.connect(self._disconnect) self.ui.attrRefreshButton.clicked.connect(self.show_attrs) # context menu self.ui.treeView.addAction(self.ui.actionSubscribeDataChange) self.ui.treeView.addAction(self.ui.actionSubscribeEvent) self.ui.treeView.addAction(self.ui.actionUnsubscribe) # handle subscriptions self._subhandler = SubHandler(self.sub_model) def show_error(self, msg, level=1): print("showing error: ", msg, level) self.ui.statusBar.show() self.ui.statusBar.setStyleSheet( "QStatusBar { background-color : red; color : black; }") #self.ui.statusBar.clear() self.ui.statusBar.showMessage(str(msg)) QTimer.singleShot(1500, self.ui.statusBar.hide) def _fit(self, idx): self.ui.treeView.resizeColumnToContents(0) def _subscribeEvent(self): self.showError("Not Implemented") def _subscribe(self): idx = self.ui.treeView.currentIndex() it = self.model.itemFromIndex(idx) if not id: self.show_error("No item currently selected") node = it.data() attrs = self.uaclient.get_node_attrs(node) self.sub_model.setHorizontalHeaderLabels( ["DisplayName", "Browse Name", 'NodeId', "Value"]) item = QStandardItem(attrs[1]) self.sub_model.appendRow( [item, QStandardItem(attrs[2]), QStandardItem(attrs[3])]) try: # FIXME use handle to unsubscribe!!! handle = self.uaclient.subscribe(node, self._subhandler) except Exception as ex: self.show_error(ex) idx = self.sub_model.indexFromItem(item) self.sub_model.takeRow(idx.row()) def unsubscribe(self): idx = self.ui.treeView.currentIndex() it = self.model.itemFromIndex(idx) if not id: print("No item currently selected") node = it.data() self.uaclient.unsubscribe(node) def _show_attrs_and_refs(self, idx): node = self.get_current_node(idx) if node: self._show_attrs(node) self._show_refs(node) def get_current_node(self, idx=None): if idx is None: idx = self.ui.treeView.currentIndex() it = self.model.itemFromIndex(idx) if not it: return None node = it.data() if not node: print("No node for item:", it, it.text()) return None return node def show_attrs(self): node = self.get_current_node() if node: self._show_attrs(node) else: self.attr_model.clear() def _show_refs(self, node): self.refs_model.clear() self.refs_model.setHorizontalHeaderLabels( ['ReferenceType', 'NodeId', "BrowseName", "TypeDefinition"]) try: refs = self.uaclient.get_all_refs(node) except Exception as ex: self.show_error(ex) raise for ref in refs: self.refs_model.appendRow([ QStandardItem(str(ref.ReferenceTypeId)), QStandardItem(str(ref.NodeId)), QStandardItem(str(ref.BrowseName)), QStandardItem(str(ref.TypeDefinition)) ]) self.ui.refView.resizeColumnToContents(0) self.ui.refView.resizeColumnToContents(1) self.ui.refView.resizeColumnToContents(2) self.ui.refView.resizeColumnToContents(3) def _show_attrs(self, node): try: attrs = self.uaclient.get_all_attrs(node) except Exception as ex: self.show_error(ex) raise self.attr_model.clear() self.attr_model.setHorizontalHeaderLabels(['Attribute', 'Value']) for k, v in attrs.items(): self.attr_model.appendRow( [QStandardItem(k), QStandardItem(str(v))]) self.ui.attrView.resizeColumnToContents(0) self.ui.attrView.resizeColumnToContents(1) def _connect(self): uri = self.ui.addrComboBox.currentText() try: self.uaclient.connect(uri) except Exception as ex: self.show_error(ex) raise self.model.client = self.uaclient self.model.clear() self.model.add_item(self.uaclient.get_root_attrs()) self.ui.treeView.resizeColumnToContents(0) self.ui.treeView.resizeColumnToContents(1) self.ui.treeView.resizeColumnToContents(2) def _disconnect(self): try: self.uaclient.disconnect() except Exception as ex: self.show_error(ex) raise finally: self.model.clear() self.sub_model.clear() self.model.client = None def closeEvent(self, event): self._disconnect() event.accept()
class QWTree(QTreeView): """Widget for tree """ dic_smodes = { 'single': QAbstractItemView.SingleSelection, 'contiguous': QAbstractItemView.ContiguousSelection, 'extended': QAbstractItemView.ExtendedSelection, 'multi': QAbstractItemView.MultiSelection, 'no selection': QAbstractItemView.NoSelection } def __init__(self, parent=None): QTreeView.__init__(self, parent) #self._name = self.__class__.__name__ icon.set_icons() self.model = QStandardItemModel() self.set_selection_mode() self.fill_tree_model() # defines self.model self.setModel(self.model) self.setAnimated(True) self.set_style() self.show_tool_tips() self.expanded.connect(self.on_item_expanded) self.collapsed.connect(self.on_item_collapsed) #self.model.itemChanged.connect(self.on_item_changed) self.connect_item_selected_to(self.on_item_selected) self.clicked[QModelIndex].connect(self.on_click) #self.doubleClicked[QModelIndex].connect(self.on_double_click) def set_selection_mode(self, smode='extended'): logger.debug('Set selection mode: %s' % smode) mode = self.dic_smodes[smode] self.setSelectionMode(mode) def connect_item_selected_to(self, recipient): self.selectionModel().currentChanged[QModelIndex, QModelIndex].connect(recipient) def disconnect_item_selected_from(self, recipient): self.selectionModel().currentChanged[QModelIndex, QModelIndex].disconnect(recipient) def selected_indexes(self): return self.selectedIndexes() def selected_items(self): indexes = self.selectedIndexes() return [self.model.itemFromIndex(i) for i in self.selectedIndexes()] def clear_model(self): rows = self.model.rowCount() self.model.removeRows(0, rows) def fill_tree_model(self): self.clear_model() for k in range(0, 4): parentItem = self.model.invisibleRootItem() parentItem.setIcon(icon.icon_folder_open) for i in range(0, k): item = QStandardItem('itemA %s %s' % (k, i)) item.setIcon(icon.icon_table) item.setCheckable(True) parentItem.appendRow(item) item = QStandardItem('itemB %s %s' % (k, i)) item.setIcon(icon.icon_folder_closed) parentItem.appendRow(item) parentItem = item logger.debug('append item %s' % (item.text())) def on_item_expanded(self, ind): item = self.model.itemFromIndex(ind) # get QStandardItem if item.hasChildren(): item.setIcon(icon.icon_folder_open) #msg = 'on_item_expanded: %s' % item.text() #logger.debug(msg) def on_item_collapsed(self, ind): item = self.model.itemFromIndex(ind) if item.hasChildren(): item.setIcon(icon.icon_folder_closed) #msg = 'on_item_collapsed: %s' % item.text() #logger.debug(msg) def on_item_selected(self, selected, deselected): itemsel = self.model.itemFromIndex(selected) if itemsel is not None: parent = itemsel.parent() parname = parent.text() if parent is not None else None msg = 'selected item: %s row: %d parent: %s' % ( itemsel.text(), selected.row(), parname) logger.debug(msg) #itemdes = self.model.itemFromIndex(deselected) #if itemdes is not None : # msg = 'on_item_selected row: %d deselected %s' % (deselected.row(), itemdes.text()) # logger.debug(msg) def on_item_changed(self, item): state = ['UNCHECKED', 'TRISTATE', 'CHECKED'][item.checkState()] msg = 'on_item_changed: item "%s", is at state %s' % (item.text(), state) logger.debug(msg) def on_click(self, index): item = self.model.itemFromIndex(index) parent = item.parent() spar = parent.text() if parent is not None else None msg = 'clicked item: %s parent: %s' % (item.text(), spar ) # index.row() logger.debug(msg) def on_double_click(self, index): item = self.model.itemFromIndex(index) msg = 'on_double_click item in row:%02d text: %s' % (index.row(), item.text()) logger.debug(msg) #-------------------------- #-------------------------- def process_expand(self): logger.debug('process_expand') #self.model.set_all_group_icons(self.icon_expand) self.expandAll() #self.tree_view_is_expanded = True def process_collapse(self): logger.debug('process_collapse') #self.model.set_all_group_icons(self.icon_collapse) self.collapseAll() #self.tree_view_is_expanded = False #def expand_collapse(self): # if self.isExpanded() : self.collapseAll() # else : self.expandAll() #-------------------------- #-------------------------- #-------------------------- def show_tool_tips(self): self.setToolTip('Tree model') def set_style(self): self.header().hide() #from psana.graphqt.Styles import style self.setWindowIcon(icon.icon_monitor) self.setContentsMargins(0, 0, 0, 0) self.setStyleSheet("QTreeView::item:hover{background-color:#00FFAA;}") #def resizeEvent(self, e): #pass #self.frame.setGeometry(self.rect()) #logger.debug('resizeEvent') #def moveEvent(self, e): #logger.debug('moveEvent') #self.position = self.mapToGlobal(self.pos()) #self.position = self.pos() #logger.debug('moveEvent - pos:' + str(self.position), __name__) #pass def closeEvent(self, e): logger.debug('closeEvent') QTreeView.closeEvent(self, e) #try : self.gui_win.close() #except : pass #try : del self.gui_win #except : pass def on_exit(self): logger.debug('on_exit') self.close() if __name__ == "__main__": def key_usage(self): return 'Keys:'\ '\n ESC - exit'\ '\n E - expand'\ '\n C - collapse'\ '\n' def keyPressEvent(self, e): #logger.debug('keyPressEvent, key = %s'%e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_E: self.process_expand() elif e.key() == Qt.Key_C: self.process_collapse() else: logger.debug(self.key_usage())
def clear(self): QStandardItemModel.clear(self) self._fetched = [] self.setHorizontalHeaderLabels(['Name', "Browse Name", 'NodeId'])
def initUI(self): self.srvList = ["", "opcUA", "modbusTCP"] if (os.name == 'nt'): self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') self.imgPath = self.appPath + "img\\" self.dbPath = self.appPath + "db\\webDb.db" #import self.appPath+srvconf else: self.appPath = os.path.abspath(sys.argv[0]).replace( os.path.basename(__file__), '') self.imgPath = self.appPath + "img/" self.dbPath = self.appPath + "db/webDb.db" self.versionPr = 'ScadaPy Web JSON Сервер v.3.14' self.setGeometry(300, 100, 1500, 820) self.setWindowTitle(self.versionPr) self.setWindowIcon(QIcon(self.imgPath + 'Globe.png')) self.h = self.frameGeometry().height() self.w = self.frameGeometry().width() self.setStyleSheet("background-color: #FFF8E7;") font = QFont() font.setPointSize(12) self.label0 = QLabel(self) self.label0.setFont(font) self.label0.move(400, 60) self.label0.resize(300, 25) self.label0.setText("ID сервера") self.label00 = QLabel(self) self.label00.setFont(font) self.label00.move(550, 60) self.label00.resize(300, 25) self.label00.setText("") self.label1 = QLabel(self) self.label1.setFont(font) self.label1.move(400, 90) self.label1.resize(140, 25) self.label1.setText("Название сервера") self.srvName = QLineEdit(self) self.srvName.setToolTip('Пример: Сервер Маш.Зала №1') self.srvName.move(550, 90) self.srvName.setFont(font) self.srvName.resize(300, 25) self.label2 = QLabel(self) self.label2.setFont(font) self.label2.move(400, 120) self.label2.resize(140, 25) self.label2.setText("Http IP address") self.slaveIP = QLineEdit(self) self.slaveIP.setToolTip('Пример: 192.168.0.111') self.slaveIP.move(550, 120) self.slaveIP.setFont(font) self.slaveIP.resize(300, 25) self.label2 = QLabel(self) self.label2.setFont(font) self.label2.move(400, 150) self.label2.resize(140, 25) self.label2.setText("Http Port") self.slavePort = QLineEdit(self) self.slavePort.setToolTip('Пример : 8080') self.slavePort.move(550, 150) self.slavePort.setFont(font) self.slavePort.resize(100, 25) self.label7 = QLabel(self) self.label7.setFont(font) self.label7.move(680, 150) self.label7.resize(140, 25) self.label7.setText("Timeout") self.serverTimeout = QLineEdit(self) self.serverTimeout.setToolTip('Пример ms: 1 ') self.serverTimeout.move(750, 150) self.serverTimeout.setFont(font) self.serverTimeout.resize(100, 25) self.label8 = QLabel(self) self.label8.setFont(font) self.label8.move(400, 180) self.label8.resize(140, 25) self.label8.setText("Login") self.serverLogin = QLineEdit(self) self.serverLogin.setToolTip('Имя пользователя') self.serverLogin.move(550, 180) self.serverLogin.setFont(font) self.serverLogin.resize(100, 25) self.label9 = QLabel(self) self.label9.setFont(font) self.label9.move(680, 180) self.label9.resize(140, 25) self.label9.setText("Password") self.serverPassword = QLineEdit(self) self.serverPassword.setToolTip('Пароль') self.serverPassword.move(750, 180) self.serverPassword.setFont(font) self.serverPassword.resize(100, 25) exitAction = QAction(QIcon(self.imgPath + 'exit.png'), '&Выход', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Выход из программы') exitAction.triggered.connect(qApp.quit) addServerAction = QAction(QIcon(self.imgPath + 'add.png'), '&Добавить', self) addServerAction.setStatusTip('Добавить сервер') addServerAction.triggered.connect(self.addNewServer) delServerAction = QAction(QIcon(self.imgPath + 'button_cancel.png'), '&Удалить', self) delServerAction.setStatusTip('Удалить сервер') delServerAction.triggered.connect(self.delServer) saveServerAction = QAction(QIcon(self.imgPath + 'filesave.png'), '&Сохранить', self) saveServerAction.setStatusTip('Сохранить сервер') saveServerAction.triggered.connect(self.saveServer) saveScr = QAction(QIcon(self.imgPath + 'bottom.png'), '&Сохранить скрипт', self) saveScr.setStatusTip('Сохранить скрипт') saveScr.triggered.connect(self.saveScr) runScr = QAction(QIcon(self.imgPath + 'run.png'), '&Запустить скрипт', self) runScr.setStatusTip('Запустить скрипт') runScr.triggered.connect(self.runScr) runConf = QAction(QIcon(self.imgPath + 'app.png'), '&Запустить конфигуратор', self) runConf.setStatusTip('Запустить конфигуратор') runConf.triggered.connect(self.runConf) menubar = self.menuBar() fileMenu = menubar.addMenu('&Команды') fileMenu.addAction(addServerAction) fileMenu.addAction(delServerAction) fileMenu.addAction(saveServerAction) fileMenu.addAction(saveScr) fileMenu.addAction(runScr) fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Выход') self.toolbar.addAction(exitAction) self.toolbar.addAction(addServerAction) self.toolbar.addAction(delServerAction) self.toolbar.addAction(saveServerAction) self.toolbar.addAction(saveScr) self.toolbar.addAction(runScr) self.toolbar.addAction(runConf) # self.statusBar().showMessage('Загрузка данных') self.treeView = QTreeView(self) self.treeView.setFont(font) self.treeView.setObjectName("treeView") self.model = QStandardItemModel() self.treeView.setModel(self.model) self.treeView.setStyleSheet("background-color: white;") self.header = ['Название сервера'] self.model.setHorizontalHeaderLabels(self.header) self.sqlLoad() self.treeView.clicked.connect(self.onClickItem) self.frameTable = QFrame(self) self.frameTable.setVisible(True) self.addRow = QPushButton(self.frameTable) self.addRow.setIcon(QIcon(self.imgPath + 'add.png')) self.addRow.move(10, 10) self.addRow.resize(30, 30) self.addRow.clicked.connect(self.addItemTree) self.saveTable = QPushButton(self.frameTable) self.saveTable.setIcon(QIcon(self.imgPath + 'filesave.png')) self.saveTable.resize(30, 30) self.saveTable.move(50, 10) self.saveTable.clicked.connect(self.saveData) #################################################################### self.treeTable = QTableWidget(self.frameTable) self.treeTable.setStyleSheet("background-color: white;") fontTable = QFont() fontTable.setPointSize(10) self.treeTable.setFont(fontTable) # self.show() self.showMaximized()
def setupTab1(self, tab1): """Basic widgets for preview panel""" scrollContainer = QVBoxLayout() scrollArea = QScrollArea() scrollArea.setWidgetResizable(True) mainWidget = QWidget() layout = QVBoxLayout() mainWidget.setLayout(layout) mainWidget.setMinimumSize(QSize(420, 800)) scrollArea.setWidget(mainWidget) scrollContainer.addWidget(scrollArea) tab1.setLayout(scrollContainer) # Label TextBox group1 = QGroupBox("Text") group1.setCheckable(True) group1layout = QHBoxLayout() group1.setLayout(group1layout) layout.addWidget(group1) layoutCol1 = QFormLayout() layoutCol2 = QFormLayout() group1layout.addLayout(layoutCol1) group1layout.addLayout(layoutCol2) label1 = QLabel(self.tr("User Name(&Id):")) text1 = QLineEdit("default") label1.setBuddy(text1) label2 = QLabel(self.tr("data 1:")) text2 = QLineEdit() text2.setPlaceholderText(self.tr("input")) lebel3 = QLabel(self.tr("<b>Pasword</b>:")) text3 = QLineEdit("******") text3.setEchoMode(QLineEdit.Password) label4 = QLabel(self.tr("link label:")) label5 = QLabel( self. tr("<a href='https://github.com/hustlei/'>github.com/hustlei</a>")) label5.setOpenExternalLinks(True) label6 = QLabel(self.tr("icon label:")) label7 = QLabel("icon") label7.setPixmap(QPixmap(":appres.img/book_address.png")) layoutCol1.addRow(label1, text1) layoutCol1.addRow(label2, text2) layoutCol1.addRow(lebel3, text3) layoutCol1.addRow(label4, label5) layoutCol1.addRow(label6, label7) text4 = QLineEdit() text4.setInputMask("0000-00-00") text5 = QLineEdit() text5.setInputMask("HH:HH:HH:HH:HH:HH;_") text6 = QLineEdit() text6.setInputMask("XXXXXX") text7 = QLineEdit() validator1 = QDoubleValidator() validator1.setRange(0, 100) validator1.setDecimals(2) text7.setValidator(validator1) text8 = QLineEdit() validator2 = QRegExpValidator() reg = QRegExp("[a-zA-Z0-9]+$") validator2.setRegExp(reg) text8.setValidator(validator2) layoutCol2.addRow(self.tr("Date Mask:"), text4) layoutCol2.addRow(self.tr("Mac Mask"), text5) layoutCol2.addRow(self.tr("String Mask"), text6) layoutCol2.addRow(self.tr("Double Validate:"), text7) layoutCol2.addRow(self.tr("Regexp Validate:"), text8) text9 = QLineEdit() text9.setPlaceholderText("input email") text9.setToolTip("please input a email address.") model = QStandardItemModel(0, 1, self) completer = QCompleter(model, self) text9.setCompleter(completer) def textch(texts): if "@" in texts: return strList = [ "@163.com", "@qq.com", "@gmail.com", "@hotmail.com", "@126.com" ] model.removeRows(0, model.rowCount()) for i in strList: model.insertRow(0) model.setData(model.index(0, 0), texts + i) text9.textChanged.connect(textch) text10 = QLineEdit("ReadOnly") text10.setReadOnly(True) layoutCol1.addRow(self.tr("auto complete:"), text9) layoutCol2.addRow("Readonly:", text10) # Button group2 = QGroupBox("Button") group2.setCheckable(True) group2layout = QVBoxLayout() group2.setLayout(group2layout) layout.addWidget(group2) layoutRow1 = QHBoxLayout() layoutRow2 = QHBoxLayout() group2layout.addLayout(layoutRow1) group2layout.addLayout(layoutRow2) btn1 = QPushButton("Button") btn2 = QPushButton("IconBtn") btn2.setIcon(QIcon(":appres.img/yes.png")) btn3 = QPushButton("Disabled") btn3.setEnabled(False) btn4 = QPushButton("Default") btn4.setDefault(True) btn5 = QPushButton("Switch") btn5.setCheckable(True) btn6 = QToolButton() # btn6.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) btn6.setText("ToolButton") btn6.setPopupMode(QToolButton.MenuButtonPopup) m = QMenu() m.addAction("action1") m.addAction("action2") m.addAction("action3") btn6.setMenu(m) btn7 = QCommandLinkButton("LinkBtn") layoutRow1.addWidget(btn1) layoutRow1.addWidget(btn2) layoutRow1.addWidget(btn3) layoutRow1.addWidget(btn4) layoutRow2.addWidget(btn5) layoutRow2.addWidget(btn6) layoutRow2.addWidget(btn7) # Checkable Item group3 = QGroupBox("Checkable") group3Layout = QVBoxLayout() layoutRow1 = QHBoxLayout() layoutRow2 = QHBoxLayout() group3Layout.addLayout(layoutRow1) group3Layout.addLayout(layoutRow2) group3.setLayout(group3Layout) layout.addWidget(group3) group3.setCheckable(True) ch1 = QRadioButton("Radio") ch2 = QRadioButton("Iconradio") ch2.setIcon(QIcon(":appres.img/Flag_blueHS.png")) ch3 = QRadioButton("Iconradio") ch3.setIcon(QIcon(":appres.img/Flag_greenHS.png")) ch4 = QRadioButton("Disable") ch4.setEnabled(False) ch5 = QCheckBox("CheckBox") ch6 = QCheckBox("CheckBox") ch6.setIcon(QIcon(":appres.img/Flag_blueHS.png")) ch7 = QCheckBox("TriState") ch7.setTristate(True) ch7.setCheckState(Qt.PartiallyChecked) ch8 = QCheckBox("Disable") ch8.setEnabled(False) layoutRow1.addWidget(ch1) layoutRow1.addWidget(ch2) layoutRow1.addWidget(ch3) layoutRow1.addWidget(ch4) layoutRow2.addWidget(ch5) layoutRow2.addWidget(ch6) layoutRow2.addWidget(ch7) layoutRow2.addWidget(ch8) # Selecting Input group4 = QGroupBox("Selectable") group4.setCheckable(True) group4Layout = QVBoxLayout() layoutRow1 = QHBoxLayout() group4Layout.addLayout(layoutRow1) group4.setLayout(group4Layout) layout.addWidget(group4) s1 = QSpinBox() s1.setValue(50) s2 = QDoubleSpinBox() s2.setRange(0, 1) s2.setValue(0.5) s3 = QComboBox() s3.addItems(["aaa", "bbb", "ccc"]) s3.setEditable(True) s3.setCurrentIndex(2) s4 = QComboBox() s4.addItems(["aaa", "bbb", "ccc"]) layoutRow1.addWidget(s1) layoutRow1.addWidget(s2) layoutRow1.addWidget(s3) layoutRow1.addWidget(s4) # TextEdit group5 = QGroupBox("TextEdit") group5.setCheckable(True) group5Layout = QVBoxLayout() group5.setLayout(group5Layout) layout.addWidget(group5) group5Layout.addWidget( QTextEdit( self. tr("If you do not leave me, I will be by your side until the end." ))) layout.addStretch(1)
def __init__(self, parent=None): super(ContextPanel, self).__init__(parent=parent) self._app_window = parent self.setAutoFillBackground(True) self._nativectx_model = QStandardItemModel(0, 4) self._nativectx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._nativectx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._nativectx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') #self._nativectx_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(3, Qt.Horizontal, 'Telescope') self._nativectx_list = DwarfListView() self._nativectx_list.setModel(self._nativectx_model) self._nativectx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._nativectx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._nativectx_list.customContextMenuRequested.connect( self._on_native_contextmenu) self._emulatorctx_model = QStandardItemModel(0, 3) self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') self._emulatorctx_list = DwarfListView() self._emulatorctx_list.setModel(self._emulatorctx_model) self._emulatorctx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._emulatorctx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._emulatorctx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._emulatorctx_list.customContextMenuRequested.connect( self._on_emulator_contextmenu) self._javactx_model = QStandardItemModel(0, 3) self._javactx_model.setHeaderData(0, Qt.Horizontal, 'Argument') self._javactx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(1, Qt.Horizontal, 'Class') #self._javactx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(2, Qt.Horizontal, 'Value') self._javactx_list = DwarfListView() self._javactx_list.setModel(self._javactx_model) self._javactx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._javactx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._javactx_list.customContextMenuRequested.connect( self._on_java_contextmenu) self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native')
class RequestList(MyTreeView): class Columns(IntEnum): DATE = 0 DESCRIPTION = 1 AMOUNT = 2 STATUS = 3 headers = { Columns.DATE: _('Date'), Columns.DESCRIPTION: _('Description'), Columns.AMOUNT: _('Amount'), Columns.STATUS: _('Status'), } filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT] def __init__(self, parent: 'ElectrumWindow'): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DESCRIPTION, editable_columns=[]) self.wallet = self.parent.wallet self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.setSortingEnabled(True) self.selectionModel().currentRowChanged.connect(self.item_changed) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.update() def select_key(self, key): for i in range(self.model().rowCount()): item = self.model().index(i, self.Columns.DATE) row_key = item.data(ROLE_KEY) if key == row_key: self.selectionModel().setCurrentIndex( item, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) break def item_changed(self, idx: Optional[QModelIndex]): if idx is None: self.parent.receive_payreq_e.setText('') self.parent.receive_address_e.setText('') return if not idx.isValid(): return # TODO use siblingAtColumn when min Qt version is >=5.11 item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE)) key = item.data(ROLE_KEY) req = self.wallet.get_request(key) if req is None: self.update() return self.parent.receive_payreq_e.setText( self.parent.wallet.get_request_URI(req)) self.parent.receive_address_e.setText(req.get_address()) self.parent.receive_payreq_e.repaint() # macOS hack (similar to #4777) self.parent.receive_address_e.repaint( ) # macOS hack (similar to #4777) def clearSelection(self): super().clearSelection() self.selectionModel().clearCurrentIndex() def refresh_status(self): m = self.std_model for r in range(m.rowCount()): idx = m.index(r, self.Columns.STATUS) date_idx = idx.sibling(idx.row(), self.Columns.DATE) date_item = m.itemFromIndex(date_idx) status_item = m.itemFromIndex(idx) key = date_item.data(ROLE_KEY) req = self.wallet.get_request(key) if req: status = self.parent.wallet.get_request_status(key) status_str = req.get_status_str(status) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update_item(self, key, invoice: Invoice): model = self.std_model for row in range(0, model.rowCount()): item = model.item(row, 0) if item.data(ROLE_KEY) == key: break else: return status_item = model.item(row, self.Columns.STATUS) status = self.parent.wallet.get_request_status(key) status_str = invoice.get_status_str(status) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update(self): # not calling maybe_defer_update() as it interferes with conditional-visibility self.parent.update_receive_address_styling() self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.update_headers(self.__class__.headers) for req in self.wallet.get_unpaid_requests(): key = self.wallet.get_key_for_receive_request(req) status = self.parent.wallet.get_request_status(key) status_str = req.get_status_str(status) request_type = req.type timestamp = req.time amount = req.get_amount_sat() message = req.message date = format_time(timestamp) amount_str = self.parent.format_amount(amount) if amount else "" labels = [date, message, amount_str, status_str] icon = read_QIcon("zcashcoin.png") tooltip = 'onchain request' items = [QStandardItem(e) for e in labels] self.set_editability(items) items[self.Columns.DATE].setData(request_type, ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(key, ROLE_KEY) items[self.Columns.DATE].setData(timestamp, ROLE_SORT_ORDER) items[self.Columns.DATE].setIcon(icon) items[self.Columns.STATUS].setIcon(read_QIcon( pr_icons.get(status))) items[self.Columns.DATE].setToolTip(tooltip) self.std_model.insertRow(self.std_model.rowCount(), items) self.filter() self.proxy.setDynamicSortFilter(True) # sort requests by date self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder) # hide list if empty if self.parent.isVisible(): b = self.std_model.rowCount() > 0 self.setVisible(b) self.parent.receive_requests_label.setVisible(b) if not b: # list got hidden, so selected item should also be cleared: self.item_changed(None) def create_menu(self, position): items = self.selected_in_column(0) if len(items) > 1: keys = [item.data(ROLE_KEY) for item in items] menu = QMenu(self) menu.addAction(_("Delete requests"), lambda: self.parent.delete_requests(keys)) menu.exec_(self.viewport().mapToGlobal(position)) return idx = self.indexAt(position) # TODO use siblingAtColumn when min Qt version is >=5.11 item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE)) if not item: return key = item.data(ROLE_KEY) req = self.wallet.get_request(key) if req is None: self.update() return menu = QMenu(self) self.add_copy_menu(menu, idx) URI = self.wallet.get_request_URI(req) menu.addAction(_("Copy Request"), lambda: self.parent.do_copy(URI, title='Zcash URI')) menu.addAction( _("Copy Address"), lambda: self.parent.do_copy(req.get_address(), title='Zcash Address')) #if 'view_url' in req: # menu.addAction(_("View in web browser"), lambda: webopen(req['view_url'])) menu.addAction(_("Delete"), lambda: self.parent.delete_requests([key])) run_hook('receive_list_menu', self.parent, menu, key) menu.exec_(self.viewport().mapToGlobal(position))
class CForm(QWidget): statSignal = pyqtSignal() # 更新窗口状态的信号 sendSignal = pyqtSignal(dict) # 发送数据的信号 def __init__(self, ur): super().__init__() self.ur = ur self.clist_num = 0 # 本机文件数量 self.slist_num = 0 # 服务器文件数量 self.initUI() # 绘制主界面 def initUI(self): mainLayout = QVBoxLayout() grid1 = QGridLayout() grid1.setSpacing(10) # 消息框 self.msgbox = QTextBrowser() self.msgbox.setReadOnly(True) self.msgbox.append(info) grid1.addWidget(self.msgbox, 0, 0, 1, 4) # 发送消息框 self.input = QLineEdit() self.send_msg = QPushButton('发送') grid1.addWidget(self.input, 1, 0, 1, 3) grid1.addWidget(self.send_msg, 1, 3, 1, 1) self.send_msg.clicked.connect(self.sendMsg) # 消息发送板块 msgGroupBox = QGroupBox('消息发送') msgGroupBox.setLayout(grid1) # 文件传输板块 fileGroupBox = QGroupBox('文件传输') grid2 = QGridLayout() grid2.setSpacing(10) # 选择工作文件夹 lbw = QLabel('文件夹:') self.fpath = QLineEdit('./cfile') sel_f = QPushButton('选择文件夹') grid2.addWidget(lbw, 2, 0, 1, 1) grid2.addWidget(self.fpath, 2, 1, 1, 3) grid2.addWidget(sel_f, 2, 4, 1, 1) sel_f.clicked.connect(self.showDialog) # 展示本机文件列表 lbcf = QLabel('本机文件:') self.cflist = QListView() self.cmodel = QStandardItemModel(self.cflist) grid2.addWidget(lbcf, 4, 0, 1, 2) grid2.addWidget(self.cflist, 5, 0, 8, 2) # 展示服务器文件列表 lbsf = QLabel('服务器文件:') self.sflist = QListView() self.smodel = QStandardItemModel(self.sflist) grid2.addWidget(lbsf, 4, 3, 1, 2) grid2.addWidget(self.sflist, 5, 3, 8, 2) # 添加操作按钮 self.bsend = QToolButton() self.brec = QToolButton() self.bsend.setArrowType(Qt.RightArrow) self.brec.setArrowType(Qt.LeftArrow) self.brec.setEnabled(False) self.bsend.setEnabled(False) grid2.addWidget(self.bsend, 7, 2, 1, 1) grid2.addWidget(self.brec, 9, 2, 1, 1) self.bsend.clicked.connect( lambda: self.getList(self.cmodel, self.clist_num, 'sendf')) self.brec.clicked.connect( lambda: self.getList(self.smodel, self.slist_num, 'dwnf')) self.cmodel.itemChanged.connect( lambda: self.onChanged(self.clist_num, self.bsend)) self.smodel.itemChanged.connect( lambda: self.onChanged(self.slist_num, self.brec)) # 添加进度条 self.pro = QProgressBar() grid2.addWidget(self.pro, 13, 0, 1, 5) fileGroupBox.setLayout(grid2) mainLayout.addWidget(msgGroupBox) mainLayout.addWidget(fileGroupBox) self.setLayout(mainLayout) self.resize(640, 640) # 跳出文件夹选择对话框 def showDialog(self): upath = QFileDialog.getExistingDirectory(self, '选择文件夹', '.') if not upath: upath = './cfile' self.fpath.setText(upath) self.upCList(upath) # 更新客户端文件列表 def upCList(self, upath): self.cmodel.clear() f_list = [f for f in listdir(upath) if isfile(join(upath, f))] self.clist_num = len(f_list) for fname in f_list: item = QStandardItem() item.setText(fname) item.setCheckable(True) self.cmodel.appendRow(item) # 将新文件添加进视图中 self.cflist.setModel(self.cmodel) # 更新服务器文件列表 def upSList(self, slist): self.smodel.clear() self.slist_num = len(slist) for fname in slist: item = QStandardItem() item.setText(fname) item.setCheckable(True) self.smodel.appendRow(item) # 将新文件添加进视图中 self.sflist.setModel(self.smodel) # 获取用户选择的文件列表 def getList(self, model, num, tp): path = self.fpath.text() # 遍历整个视图 for i in range(num): data = {'type': tp, 'cnt': {'ur': self.ur}} data['cnt']['path'] = path item = model.item(i) # 如果该选项被选中 if item and item.checkState() == 2: fname = item.text() data['cnt']['fname'] = fname if tp == 'sendf': fsize = getsize(path + '/' + fname) # 判断是否为空文件 if fsize > 0: data['cnt']['fsize'] = fsize else: # 空文件报错 self.statSignal.emit(fname + '为空文件,无法发送!') continue self.sendSignal.emit(data) # 设置发送下载按钮的可以状态 def onChanged(self, num, btn): sender = self.sender() flag = False for i in range(num): item = sender.item(i) if item and item.checkState() == 2: flag = True btn.setEnabled(flag) # 设置进度条最大值 def setProMax(self, num): self.pro.setMaximum(num) # 更新进度条 def upPro(self, num): self.pro.setValue(num) # 发送信息 def sendMsg(self): now = time.strftime('%H:%M:%S') msg = self.input.text() self.msgbox.append('%-15s: %-40s' % ('本机(' + now + ')', msg)) # 将信息在对话框中显示 data = {'type': 'msg', 'cnt': {'ur': self.ur, 'msg': msg}} # 封装发送的数据 self.sendSignal.emit(data) self.input.clear() # 显示服务器的信息 def showMsg(self, msg): now = time.strftime('%H:%M:%S') self.msgbox.append('%-15s: %-40s' % ('服务器(' + now + ')', msg))