def to_model(self) -> QStandardItemModel: root = QStandardItemModel() root.invisibleRootItem() for package in self.packages: item = package.to_model() root.appendRow(item) return root
class NestedDictView(QTreeView): def __init__(self): super().__init__() self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(['Key', 'Value']) self.header().setSectionResizeMode(3) # QHeaderView::ResizeMode = ResizeToContents self.setModel(self.model) self.table = NestedDict() def on_edit(self, callback): self.model.itemChanged.connect(callback) def clear(self, parent=None): parent = parent or self.model.invisibleRootItem() parent.removeRows(0, parent.rowCount()) def set(self, data, parent=None, parent_node=None): self.clear(parent) parent = parent or self.model.invisibleRootItem() parent_node = parent_node or self.table for k, v in sorted(data.items()): if type(v) is NestedDict: parent.appendRow([QStandardItem(k), QStandardItem('')]) entry = parent.child(parent.rowCount() - 1) parent_node[k] = NestedDict() self.set(v, parent=entry, parent_node=parent_node[k]) else: parent.appendRow([QStandardItem(k), QStandardItem(str(v))]) parent_node[k] = parent self.expand(parent.index())
def model_from_file(self, file_name): # file = QFile(file_name) # if not file.open(QFile.ReadOnly): # return QStringListModel(self._completer) QApplication.instance().setOverrideCursor(QCursor(Qt.WaitCursor)) model = QStandardItemModel(self._completer) parents = [model.invisibleRootItem()] with open(file_name) as file: pat = re.compile("^\\s+") for line in file: if not line: continue trimmed_line = line.strip() if not trimmed_line: continue match = pat.match(line) if not match: level = 0 else: length = match.end() - match.start() if line.startswith("\t"): level = length else: level = length // 4 while len(parents) < level + 2: parents.append(None) item = QStandardItem() item.setText(trimmed_line) parents[level].appendRow(item) parents[level + 1] = item QApplication.instance().restoreOverrideCursor() return model
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 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 add1(self): text, ok = QInputDialog.getText(self, "菜单添加", "请输入:父目录节点-添加菜单名称") if ok: print(text) else: return global list_1, list1tp ss = text.split('-') try: list_1[ss[0]].append(ss[1]) list_1[ss[1]] = [] except: reply = QMessageBox.warning(self, '警告', '父节点不存在', QMessageBox.Yes) print(id2string) for key, value in id2string.items(): if value == ss[0]: fakey = key break mxid = 1 for key in id2string.keys(): if key != fakey and key.startswith(fakey): mxid = max(mxid, int(key[len(fakey) + 1])) print(fakey + '.' + str(mxid + 1) + '-' + ss[1]) list1tp.append(fakey + '.' + str(mxid + 1) + '-' + ss[1]) self.treeView.setHeaderHidden(True) treeModel = QStandardItemModel() rootNode = treeModel.invisibleRootItem() self.get_menu(rootNode, 'root') self.treeView.setModel(treeModel) self.treeView.expandAll() self.write_menu()
def _from_xml(self, keywords): model = QStandardItemModel() model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword']) rootNode = model.invisibleRootItem() if keywords.xpath('place'): self.ui.rbtn_yes.setChecked(True) else: self.ui.rbtn_yes.setChecked(False) for place in keywords.xpath('place'): thesaurus_name = place.xpath('placekt')[0].text branch = QStandardItem(thesaurus_name) branch.setFont(QFont('Arial', 9)) for kw in place.xpath('placekey'): childnode = QStandardItem(kw.text) childnode.setFont(QFont('Arial', 10)) branch.appendRow([None, childnode]) rootNode.appendRow([branch, None]) self.ui.place.setModel(model) # self.ui.place.setColumnWidth(250, 150) self.ui.place.expandAll()
def load_iso(self): self.ui.label_search_term.hide() self.ui.search_term.hide() self.ui.button_search.hide() self.ui.label_search_results.text = "ISO 19115 Topic Categories" self.populate_thesauri_lookup() iso_url = "https://www2.usgs.gov/science/term.php?thcode=15&text=ISO 19115 Topic Category" results = utils.requests_pem_get(iso_url).json() thesaurus_name = "ISO 19115 Topic Category" branch = QStandardItem(thesaurus_name) branch.setFont(QFont('Arial', 11)) for item in results['nt']: childnode = QStandardItem(item['name']) childnode.setFont(QFont('Arial', 9)) branch.appendRow([childnode]) model = QStandardItemModel(0, 0) rootNode = model.invisibleRootItem() rootNode.appendRow(branch) self.ui.treeview_results.setModel(model) self.ui.treeview_results.expandAll()
def __update_tree_modules(self, current): modules = current['modules'] if 'modules' in current else {} model = QStandardItemModel() parent_item = model.invisibleRootItem() # type: QStandardItem for m in sorted(modules): text_item = QStandardItem(m) text_item.setEditable(False) text_item.setCheckState( Qt.Checked if json.loads(modules[m].lower()) else Qt.Unchecked) # NOTE: some modules name their parameters differently than themselves if json.loads(modules[m].lower()) and m in current: for i in sorted(current[m]): item = QStandardItem(i + " = " + current[m][i]) item.setEditable(False) font = QFont() font.setItalic(True) item.setFont(font) text_item.appendRow(item) parent_item.appendRow(text_item) model.setHeaderData(0, Qt.Horizontal, "Modules") self.ui.modules.setModel(model)
class CatalogueManager: """ 单例化,管理目录结构 """ def __init__(self): self._root_abs_path = GlobalVarManager.root_abs_path self._lattice_edt = GlobalVarManager.lattice_edt self._file_mgr = FileManager() # 用于充当ListView数据源 self._cat_list_model = QStandardItemModel() # 初始化目录 self.init_catalogue() def init_catalogue(self): """从图数据库中读取路径用于填充""" self._cat_list_model.clear() self._cat_list_model.setHorizontalHeaderLabels(['节点名', '路径', '备注']) root_item: QStandardItem = self._cat_list_model.invisibleRootItem() parent_item = QStandardItem(QIcon(self._root_abs_path + "\\resources\\go-home.png"), "root") root_item.appendRow(parent_item) for path in self._lattice_edt.tree_model.get_root2leaf_path(): print(path) depth = 1 self._add_path(path, depth, parent_item, "root", len(path)) def _add_path(self, path: List[str], depth: int, parent_item: QStandardItem, path_str: str, path_len: int): is_file = False if depth == path_len: return if depth == path_len - 1: # 为文件 is_file = True node_name_list = path[depth] for node_name in node_name_list: # 检查节点名在是否重复 index = 0 child_item = parent_item.child(index) while child_item: child_name = child_item.index().data() if child_name == node_name: node_item = child_item break index += 1 child_item = parent_item.child(index) else: note_str = "文件" if is_file else "文件夹" icon = QIcon(self._root_abs_path + "\\resources\\folder.png") if not is_file else IconExtractor( self._file_mgr.get_abs_path(node_name)).get_icon() node_item = QStandardItem(icon, node_name) path_str += "\\" + node_name path_item = QStandardItem(path_str) note_item = QStandardItem(note_str) parent_item.appendRow([node_item, path_item, note_item]) self._add_path(path, depth + 1, node_item, path_str, path_len) @property def cat_list_model(self): return self._cat_list_model
def _setupModel(self): """ definimos el modelo. """ newModel = QStandardItemModel() newModel.setColumnCount(5) self.hiddenRoot = newModel.invisibleRootItem() self.baseModel = newModel #proxyModel
def search_thesaurus(self): if not self.populate_thesauri_lookup(): return False term = self.ui.search_term.text() search_url = "https://www2.usgs.gov/science/term-search.php?thcode=any&term={}".format( term ) results = self.get_result(search_url) if results is None: return False if not results: msg = "The Metadata Wizard was unable to locate the provided search term in the controlled vocabulary search" msg += "\n\n'{}' Not Found".format(self.ui.search_term.text()) QMessageBox.information(self, "Search Term Not Found", msg, QMessageBox.Ok) return False self.branch_lookup = {} unique_children = [] for item in results: thesaurus_name = self.thesauri_lookup[item["thcode"]] if ( item["thcode"] != "1" and not self.place or item["thcode"] == "1" and self.place ): branch = self.branch_lookup.get( thesaurus_name, QStandardItem(thesaurus_name) ) branch.setFont(QFont("Arial", 11)) if item["label"] != item["value"]: childnode = QStandardItem( "{} (use: {})".format(item["label"], item["value"]) ) else: childnode = QStandardItem(item["label"]) childnode.setFont(QFont("Arial", 9)) if (thesaurus_name, item["value"]) not in unique_children: branch.appendRow([childnode, None]) unique_children.append((thesaurus_name, item["value"])) self.branch_lookup[thesaurus_name] = branch model = QStandardItemModel(0, 0) rootNode = model.invisibleRootItem() for thesaurus_node in self.branch_lookup.items(): rootNode.appendRow(thesaurus_node[1]) self.ui.treeview_results.setModel(model) self.ui.treeview_results.expandAll()
def search_thesaurus(self): self.populate_thesauri_lookup() search_url = "https://www2.usgs.gov/science/term-search.php?thcode=any&term={}".format( self.ui.search_term.text()) results = requests.get(search_url).json() if not results: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("'{}' Not Found".format(self.ui.search_term.text())) msg.setInformativeText( "The Metadata Wizard was unable to locate the provided search term in the controlled vocabulary search" ) msg.setWindowTitle("Keyword Not Found") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() branch_lookup = {} unique_children = [] for item in results: thesaurus_name = self.thesauri_lookup[item['thcode']] if item['thcode'] != '1' and not self.place or \ item['thcode'] == '1' and self.place: branch = branch_lookup.get(thesaurus_name, QStandardItem(thesaurus_name)) branch.setFont(QFont('Arial', 11)) childnode = QStandardItem(item['value']) childnode.setFont(QFont('Arial', 9)) if (thesaurus_name, item['value']) not in unique_children: branch.appendRow([childnode]) unique_children.append((thesaurus_name, item['value'])) branch_lookup[thesaurus_name] = branch model = QStandardItemModel(0, 0) # model.setHorizontalHeaderLabels(['Theme Keywords (thesaurus/keywords)']) rootNode = model.invisibleRootItem() # branch1 = QStandardItem("Branch 1") # branch1.appendRow([QStandardItem("Child A")]) # childnode = QStandardItem("Child B") # branch1.appendRow([childnode]) # # branch2 = QStandardItem("Branch 2") # branch2.appendRow([QStandardItem("Child C")]) # branch2.appendRow([QStandardItem("Child D")]) for thesaurus_node in branch_lookup.items(): rootNode.appendRow(thesaurus_node[1]) # rootNode.appendRow([ branch1]) # rootNode.appendRow([ branch2]) self.ui.treeview_results.setModel(model) # self.ui.treeview_results.setColumnWidth(0, 150) self.ui.treeview_results.expandAll()
def generate_model(self) -> Tuple[QStandardItemModel, QModelIndex]: """Generate a Qt Model based on the project structure.""" model = QStandardItemModel() root = model.invisibleRootItem() # TODO: Add these icon resources to library or something so they are not loaded every time dgs_ico = QIcon('ui/assets/DGSIcon.xpm') flt_ico = QIcon('ui/assets/flight_icon.png') prj_header = QStandardItem( dgs_ico, "{name}: {path}".format(name=self.name, path=self.projectdir)) prj_header.setEditable(False) fli_header = QStandardItem(flt_ico, "Flights") fli_header.setEditable(False) # TODO: Add a human readable identifier to flights first_flight = None for uid, flight in self.flights.items(): fli_item = QStandardItem(flt_ico, "Flight: {}".format(flight.name)) if first_flight is None: first_flight = fli_item fli_item.setToolTip("UUID: {}".format(uid)) fli_item.setEditable(False) fli_item.setData(flight, QtCore.Qt.UserRole) gps_path, gps_uid = flight.gps_file gps = QStandardItem("GPS: {}".format(gps_uid)) gps.setToolTip("File Path: {}".format(gps_path)) gps.setEditable(False) gps.setData(gps_uid) # For future use grav_path, grav_uid = flight.gravity_file if grav_path is not None: _, grav_fname = os.path.split(grav_path) else: grav_fname = '<None>' grav = QStandardItem("Gravity: {}".format(grav_fname)) grav.setToolTip("File Path: {}".format(grav_path)) grav.setEditable(False) grav.setData(grav_uid) # For future use fli_item.appendRow(gps) fli_item.appendRow(grav) for line in flight: line_item = QStandardItem("Line {}:{}".format( line.start, line.end)) line_item.setEditable(False) fli_item.appendRow(line_item) fli_header.appendRow(fli_item) prj_header.appendRow(fli_header) root.appendRow(prj_header) self.log.debug("Tree Model generated") first_index = model.indexFromItem(first_flight) return model, first_index
def delete1(self): text = self.treeView.selectedIndexes()[0].data() print(text) self.delet_menu('root', text) self.treeView.setHeaderHidden(True) treeModel = QStandardItemModel() rootNode = treeModel.invisibleRootItem() self.get_menu(rootNode, 'root') self.treeView.setModel(treeModel) self.treeView.expandAll() self.write_menu()
def update_commands(self,meas_prog_list_byname): global Regexprogramfile Regexprogramfile="("+"|".join(meas_prog_list_byname)+")" self.valid_list_of_commands = self.get_list_of_commands() #initiate syntax highlighting for the macro editor self.highlighter = MacroHighlighter(self.ui.macro_textbox.document(),self.valid_list_of_commands) #update the list of available macro commands in the user interface model=QStandardItemModel() parentItem = model.invisibleRootItem() for command in self.valid_list_of_commands: parentItem.appendRow(QStandardItem(command.label)) self.ui.macrocommandtree.setModel(model)
def build_ui(self): self.ui = self.ui_class() self.ui.setupUi(self) # self.setup_dragdrop(self) model = QStandardItemModel() model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword']) rootNode = model.invisibleRootItem() self.ui.theme.setModel(model) self.ui.theme.setColumnWidth(0, 250) self.ui.theme.expandAll()
def setup(self, iface): self.iface = iface LAYER_GROUP_ITEMS = ((q3dconst.TYPE_DEM, "DEM"), (q3dconst.TYPE_POINT, "Point"), (q3dconst.TYPE_LINESTRING, "Line"), (q3dconst.TYPE_POLYGON, "Polygon")) model = QStandardItemModel(0, 1) self.layerParentItem = {} for geomType, name in LAYER_GROUP_ITEMS: item = QStandardItem(name) item.setIcon(self.icons[geomType]) item.setEditable(False) self.layerParentItem[geomType] = item model.invisibleRootItem().appendRow([item]) self.setModel(model) self.expandAll() self.model().itemChanged.connect(self.treeItemChanged)
class CommentTree(QTreeView): def __init__(self, parent=None): super().__init__(parent) self.setUniformRowHeights(False) self.setAnimated(True) self.model = QStandardItemModel() self.filter = CommentModel() self.filter.setSourceModel(self.model) self.setModel(self.filter) self.filter.setDynamicSortFilter(False) self.rootItem = self.model.invisibleRootItem() self.setWordWrap(True) self.setItemDelegate(ItemWordWrap())
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)
def setup(self, iface): self.iface = iface TREE_TOP_ITEMS = ("Scene", "Lights & Shadow", "Layers") # tr LAYER_GROUP_ITEMS = ((q3dconst.TYPE_DEM, "DEM"), (q3dconst.TYPE_POINT, "Point"), (q3dconst.TYPE_LINESTRING, "Line"), (q3dconst.TYPE_POLYGON, "Polygon")) model = QStandardItemModel(0, 2) self.treeItems = [] for name in TREE_TOP_ITEMS: item = QStandardItem(name) item.setIcon(QgsApplication.getThemeIcon("/propertyicons/CRS.svg")) #item.setData(itemId) item.setEditable(False) self.treeItems.append(item) model.invisibleRootItem().appendRow([item]) itemLayers = self.treeItems[2] # Layers self.layerParentItem = {} for geomType, name in LAYER_GROUP_ITEMS: item = QStandardItem(name) item.setIcon(self.icons[geomType]) #item.setData(itemId) item.setEditable(False) itemLayers.appendRow([item]) self.layerParentItem[geomType] = item self.setModel(model) self.header().setStretchLastSection(False) self.header().setSectionResizeMode(0, QHeaderView.Stretch) self.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) self.expandAll() self.model().itemChanged.connect(self.treeItemChanged) self.doubleClicked.connect(self.treeItemDoubleClicked)
def build_ui(self): self.ui = self.ui_class() self.ui.setupUi(self) # self.setup_dragdrop(self) model = QStandardItemModel() model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword']) rootNode = model.invisibleRootItem() self.ui.place.setModel(model) self.ui.place.setColumnWidth(0, 250) self.ui.place.expandAll() self.contact_include_place_change(self.ui.rbtn_yes.isChecked())
class QDictTreeView(QTreeView): def __init__(self, data=None): super().__init__() self.header().hide() self.root_model = QStandardItemModel() self.setModel(self.root_model) if data: self.populate_tree(data) def populate_tree(self, children, parent=None): if not parent: parent = self.root_model.invisibleRootItem() for child in sorted(children): child_item = QStandardItem(child) parent.appendRow(child_item) if isinstance(children, dict) and bool(list(children)): self.populate_tree(children[child], child_item)
def getOutlines(self, doc): toc = doc.toc() if not toc: self.dockWidget.hide() return self.dockWidget.show() outline_model = QStandardItemModel(self) parent_item = outline_model.invisibleRootItem() node = toc.firstChild() loadOutline(doc, node, parent_item) self.treeView.setModel(outline_model) if parent_item.rowCount() < 4: self.treeView.expandToDepth(0) self.treeView.setHeaderHidden(True) self.treeView.header().setSectionResizeMode(0, 1) self.treeView.header().setSectionResizeMode(1, 3) self.treeView.header().setStretchLastSection(False)
class TreeView(QTreeView): """ TreeView contains the detailed list of packages for a given recipe. """ def __init__(self): super(TreeView, self).__init__() self.setAlternatingRowColors(True) self.model = QStandardItemModel(0, 2, self) self.model.setHeaderData(0, Qt.Horizontal, "Package") self.model.setHeaderData(1, Qt.Horizontal, "Values") self.rootNode = self.model.invisibleRootItem() self.setModel(self.model) self.setColumnWidth(0, 150) self.expandAll() def populate(self, info, clear=False): if clear: if self.rootNode.rowCount() > 0: self.rootNode.removeRows(0, self.rootNode.rowCount()) if info == []: branch = QStandardItem("No packages found.") else: for package in info: branch = QStandardItem(package["id"]) for key, value in package.items(): if key == "id": # Already got it continue if isinstance(value, list): p = QStandardItem(key) branch.appendRow([p]) for item in value: p.appendRow(item) elif isinstance(value, dict): p = QStandardItem(key) branch.appendRow([p]) for key_, value_ in value.items(): p.appendRow( [QStandardItem(key_), QStandardItem(value_)]) else: p = QStandardItem(key) q = QStandardItem(str(value)) branch.appendRow([p, q]) self.rootNode.appendRow([branch])
def createCentralWidget(self): # Create table self.centralWidget = QSplitter(Qt.Horizontal) self.treeView = QTreeView() self.treeView.setHeaderHidden(True) standardModel = QStandardItemModel() rootNode = standardModel.invisibleRootItem() self.ports = QStandardItem("本地端口") self.attackerIP = QStandardItem("攻击者IP") self.ports.setEditable(False) self.attackerIP.setEditable(False) rootNode.appendRow(self.ports) rootNode.appendRow(self.attackerIP) self.treeView.setModel(standardModel) self.tableWidget = QTableWidget(self) self.tableWidget.setRowCount(1500) self.tableWidget.setColumnCount(11) self.tableWidget.verticalHeader().setVisible(False) self.tableWidget.setHorizontalHeaderLabels([ '日期', '时间', '远程IP', '远程端口', '方向', '本地IP', '本地端口', '协议', '字节', '国家', '数据包详细信息' ]) self.tableWidget.setColumnWidth(0, 100) self.tableWidget.setColumnWidth(2, self.width * 0.1) self.tableWidget.setColumnWidth(3, self.width * 0.07) self.tableWidget.setColumnWidth(4, self.width * 0.05) self.tableWidget.setColumnWidth(5, self.width * 0.1) self.tableWidget.setColumnWidth(6, self.width * 0.06) self.tableWidget.setColumnWidth(7, self.width * 0.05) self.tableWidget.setColumnWidth(8, self.width * 0.04) self.tableWidget.setColumnWidth(10, self.width * 0.095) # self.tableWidget.move(30,10) # table selection change self.tableWidget.doubleClicked.connect(self.on_click) self.treeView.setMinimumWidth(self.width * 0.15) self.tableWidget.setMinimumWidth(self.width * 0.85) self.centralWidget.addWidget(self.treeView) self.centralWidget.addWidget(self.tableWidget) self.centralWidget.setMinimumHeight(self.height * 0.95)
def createCentralWidget(self): # Create table self.centralWidget = QSplitter(Qt.Horizontal) self.treeView = QTreeView() self.treeView.setHeaderHidden(True) standardModel = QStandardItemModel() rootNode = standardModel.invisibleRootItem() self.ports = QStandardItem("Local Ports") self.attackerIP = QStandardItem("Attacker IPs") self.ports.setEditable(False) self.attackerIP.setEditable(False) rootNode.appendRow(self.ports) rootNode.appendRow(self.attackerIP) self.treeView.setModel(standardModel) self.tableWidget = QTableWidget(self) self.tableWidget.setRowCount(1500) self.tableWidget.setColumnCount(11) self.tableWidget.verticalHeader().setVisible(False) self.tableWidget.setHorizontalHeaderLabels([ 'Date', 'Time', 'RemoteIP', 'Remote Port', 'Direction', 'Local IP', 'Local Port', 'Protocol', 'Bytes', 'Country', 'Packet Detail' ]) self.tableWidget.setColumnWidth(0, 100) self.tableWidget.setColumnWidth(2, self.width * 0.1) self.tableWidget.setColumnWidth(3, self.width * 0.07) self.tableWidget.setColumnWidth(4, self.width * 0.05) self.tableWidget.setColumnWidth(5, self.width * 0.1) self.tableWidget.setColumnWidth(6, self.width * 0.06) self.tableWidget.setColumnWidth(7, self.width * 0.05) self.tableWidget.setColumnWidth(8, self.width * 0.04) self.tableWidget.setColumnWidth(10, self.width * 0.095) # self.tableWidget.move(30,10) # table selection change self.tableWidget.doubleClicked.connect(self.on_click) self.treeView.setMinimumWidth(self.width * 0.15) self.tableWidget.setMinimumWidth(self.width * 0.85) self.centralWidget.addWidget(self.treeView) self.centralWidget.addWidget(self.tableWidget) self.centralWidget.setMinimumHeight(self.height * 0.95)
class TreeView(QTreeView): """ TreeView contains the list of packages for each remote. It reads a cache file """ def __init__(self, cache): super(TreeView, self).__init__() self.setAlternatingRowColors(False) self.model = QStandardItemModel(0, 1, self) self.model.setHeaderData(0, Qt.Horizontal, "Remote") self.rootNode = self.model.invisibleRootItem() for remote in cache: branch = QStandardItem(remote["name"]) for package in remote["packages"]: p = QStandardItem(package) branch.appendRow([p]) self.rootNode.appendRow([branch]) self.setModel(self.model) self.setColumnWidth(0, 150) self.expandAll()
def set_items(self, items): self.items = items self.itemsTree = QTreeView() self.itemsTree.setHeaderHidden(True) treeModel = QStandardItemModel() rootNode = treeModel.invisibleRootItem() groups = {} for item in items: category = item['data']['category'] node = self.__get_node(item['name']) if (category not in groups): groups[category] = self.__get_node(category) groups[category].appendRow(node) for key in groups: rootNode.appendRow(groups[key]) self.itemsTree.setModel(treeModel) self.itemsTree.expandAll() self.setWidget(self.itemsTree)
def get_tree_model(self): item_model = QStandardItemModel() root = item_model.invisibleRootItem() item_model.setHorizontalHeaderLabels( ['名称', '账号', '交易类型', '金额', '进度', '委托详情', '开始时间', '结束时间']) row1 = [ '组合指令2', '37000033/37000034', '买入', '1.50万', '1500/3600', '15', '13:01:12', '13:01:12' ] for idx, ele in enumerate(row1): row1[idx] = QStandardItem(ele) row1_1 = ['37000033', '', '买入', '7032.00', '700/1600', '7', ''] for idx, ele in enumerate(row1_1): row1_1[idx] = QStandardItem(ele) row1_1_1 = [ 'SZ000002 万科A', '', '买入', '1183.00', '100/100', '1', '', '' ] for idx, ele in enumerate(row1_1_1): # 每一个元素都是一个item!!!!!!!!!! row1_1_1[idx] = QStandardItem(ele) root.appendRow(row1) row1[0].appendRow(row1_1) row1_1[0].appendRow(row1_1_1) row1[2].setData(QBrush(Qt.red), Qt.ForegroundRole) row1_1[2].setData(QBrush(Qt.red), Qt.ForegroundRole) row1_1_1[2].setData(QBrush(Qt.red), Qt.ForegroundRole) row1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole) row1_1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole) row1_1_1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole) return item_model
def to_model(self): """ Convert history to Model vor QTreeView """ from PyQt5.QtGui import QStandardItemModel, QStandardItem from PyQt5.QtGui import QColor, QBrush model = QStandardItemModel() root = model.invisibleRootItem() for turn in range(self.turns_count): color = QColor(0, 0, 0) if self.is_history_log( turn, 0, 0) else QColor(255, 0, 0) _round = QStandardItem('Round {}'.format(turn)) _round.setForeground(color) _round.setData((turn, None, None)) root.appendRow(_round) player_turn = self.__turns[turn] for p_turn in range(len(player_turn)): color = QColor(0, 0, 0) if self.is_history_log( turn, p_turn, 0) else QColor(255, 0, 0) player = QStandardItem('Player {} - {}'.format( p_turn, self.__players[p_turn].name)) player.setForeground(color) player.setData((turn, p_turn, None)) _round.appendRow(player) actions = player_turn[p_turn] for i, action in enumerate(actions): color = QColor(0, 0, 0) if self.is_history_log( turn, p_turn, i) else QColor(255, 0, 0) _action = QStandardItem(str(action)) _action.setForeground(QBrush(color)) _action.setToolTip(str(action)) _action.setData((turn, p_turn, i)) player.appendRow(_action) return model
def __update_tree_parameters(self, current): model = QStandardItemModel() parent_item = model.invisibleRootItem() # type: QStandardItem for m in sorted(current): # skip modules if m == 'modules': continue text_item = QStandardItem(m) text_item.setEditable(False) for i in sorted(current[m]): item = QStandardItem(i + " = " + current[m][i]) item.setEditable(False) font = QFont() font.setItalic(True) item.setFont(font) text_item.appendRow(item) parent_item.appendRow(text_item) model.setHeaderData(0, Qt.Horizontal, "Parameters") self.ui.parameters.setModel(model)
class StacktraceWidget(QWidget): def __init__(self, parent): super().__init__(parent) self.parent = parent self.tree = QTreeView(self) layout = QVBoxLayout(self) layout.addWidget(self.tree) self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(["Level", "Values"]) self.tree.header().setDefaultSectionSize(180) self.tree.setModel(self.model) def importData(self, data): self.model.setRowCount(0) root = self.model.invisibleRootItem() for index, stack_values in enumerate(data): parent = QStandardItem( str(stack_values.f_code.co_name) + str( inspect.signature( types.FunctionType(stack_values.f_code, {}) ) ) ) parent.setEditable(False) for key, value in stack_values.f_locals.items(): keyWidget = QStandardItem(str(key)) keyWidget.setEditable(False) try: value_as_str = repr(value) except BaseException: value_as_str = "Can't see" valueWidget = ValueWidget( self.parent, value_as_str, str(key), str(index) ) parent.appendRow([keyWidget, valueWidget]) root.appendRow(parent)
class TapeWidget(QWidget): def __init__(self, parent = None): super().__init__(parent) self._main_layout = QVBoxLayout(self) self._search_box = QLineEdit(self) self._button_layout = QHBoxLayout() self._view = QTreeView() self._view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self._view.setSelectionMode(QAbstractItemView.ExtendedSelection) self._view.setHeaderHidden(True) self._add_note_button = QPushButton(self) self._add_note_button.setText("New note") self._add_child_button = QPushButton(self) self._add_child_button.setText("New child") self._add_sibling_button = QPushButton(self) self._add_sibling_button.setText("New sibling") self._delete_note_button = QPushButton(self) self._delete_note_button.setText("Delete note") self._button_layout.addWidget(self._add_note_button) self._button_layout.addWidget(self._add_sibling_button) self._button_layout.addWidget(self._add_child_button) self._button_layout.addWidget(self._delete_note_button) self._button_layout.addStretch() self._main_layout.addWidget(self._search_box) self._main_layout.addLayout(self._button_layout) self._main_layout.addWidget(self._view) self._tape_filter_proxy_model = TapeFilterProxyModel() self._note_delegate = NoteDelegate() self._tape_model = QStandardItemModel() self.set_model(self._tape_model) self._view.setItemDelegate(self._note_delegate) self._view.setModel(self._tape_filter_proxy_model) self._add_note_button.clicked.connect(lambda checked: self.add_and_focus_note()) self._add_sibling_button.clicked.connect(self._new_sibling_handler) self._add_child_button.clicked.connect(self._new_child_handler) self._delete_note_button.clicked.connect(self.delete_selected_notes) self._search_box.textChanged.connect(self._tape_filter_proxy_model.setFilterFixedString) def model(self): """ Returns the model that contains all notes managed by the tape. The model should be treated as read-only. You can only modify it indirectly through the methods provided by TapeWidget. """ return self._tape_model def proxy_model(self): """ Returns the model that contains notes matching current filter. The model should be treated as read-only. You can only modify it indirectly through the methods provided by TapeWidget. """ return self._tape_filter_proxy_model def set_model(self, model): assert ( len(set([item_to_id(item) for item in all_items(model) if item_to_id(item) != None])) == len( [item_to_id(item) for item in all_items(model) if item_to_id(item) != None]) ) # NOTE: If there's an exception in setSourceModel(), we can hope that the source model # remains unchanged. That's why we assing to _tape_model only if that instruction succeeds. self._tape_filter_proxy_model.setSourceModel(model) self._tape_model = model def notes(self): return all_notes(self._tape_model) def assign_ids(self): assign_note_ids(self._tape_model) def create_empty_note(self): return Note( body = "", tags = [], created_at = datetime.utcnow() ) def add_note(self, note = None, parent_index = None): # NOTE: Remember to use indexes from _tape_model, not _tape_filter_proxy_model here assert parent_index == None or self._tape_model.itemFromIndex(parent_index) != None and parent_index.isValid() root_item = self._tape_model.invisibleRootItem() if parent_index == None: parent_item = root_item else: parent_item = self._tape_model.itemFromIndex(parent_index) if note != None: assert note not in self.notes() else: note = self.create_empty_note() item = QStandardItem() set_item_note(item, note) parent_item.appendRow(item) def add_and_focus_note(self, parent_proxy_index = None): if parent_proxy_index != None: parent_index = self._tape_filter_proxy_model.mapToSource(parent_proxy_index) else: parent_index = None self.add_note(parent_index = parent_index) if parent_proxy_index != None: self._view.expand(parent_proxy_index) parent_item = self._tape_model.itemFromIndex(parent_index) else: parent_item = self._tape_model.invisibleRootItem() # NOTE: It's likely that the new note does not match the filter and won't not be present # in the proxy model. We want to select it and focus on it so the filter must be cleared. # And it must be cleared before taking the index in the proxy because changing the filter # may change the set of notes present in the proxy and invalidate the index. self.set_filter('') new_note_index = parent_item.child(parent_item.rowCount() - 1).index() new_note_proxy_index = self._tape_filter_proxy_model.mapFromSource(new_note_index) self.clear_selection() self.set_note_selection(new_note_proxy_index, True) self._view.scrollTo(new_note_proxy_index) def remove_notes(self, indexes): remove_items(self._tape_model, indexes) def clear(self): self._tape_model.clear() def set_filter(self, text): # NOTE: This triggers textChanged() signal which applies the filter self._search_box.setText(text) def get_filter(self): return self._search_box.text() def selected_proxy_indexes(self): return self._view.selectedIndexes() def selected_indexes(self): return [self._tape_filter_proxy_model.mapToSource(proxy_index) for proxy_index in self.selected_proxy_indexes()] def set_note_selection(self, proxy_index, select): assert proxy_index != None and proxy_index.isValid() assert self._tape_model.itemFromIndex(self._tape_filter_proxy_model.mapToSource(proxy_index)) != None self._view.selectionModel().select( QItemSelection(proxy_index, proxy_index), QItemSelectionModel.Select if select else QItemSelectionModel.Deselect ) def clear_selection(self): self._view.selectionModel().clear() def delete_selected_notes(self): self.remove_notes(self.selected_indexes()) def _new_sibling_handler(self): selected_proxy_indexes = self._view.selectedIndexes() if len(selected_proxy_indexes) > 1: self.clear_selection() selected_proxy_indexes = [] if len(selected_proxy_indexes) == 0 or selected_proxy_indexes[0].parent() == QModelIndex(): self.add_and_focus_note() else: self.add_and_focus_note(selected_proxy_indexes[0].parent()) def add_child_to_selected_element(self): selected_proxy_indexes = self._view.selectedIndexes() if len(selected_proxy_indexes) != 1: return False else: self.add_and_focus_note(selected_proxy_indexes[0]) return True def _new_child_handler(self): added = self.add_child_to_selected_element() if not added: QMessageBox.warning(self, "Can't add note", "To be able to add a new child note select exactly one parent")
class TapeFilterProxyModelTest(unittest.TestCase): def setUp(self): self.source_model = QStandardItemModel() self.tape_filter_proxy_model = TapeFilterProxyModel() self.notes = [ Note( body = "H+X", tags = ["Z"], created_at = datetime.utcnow() ), Note( body = "B", tags = ["C", "PPP RRR"], created_at = datetime.utcnow() ), Note( body = "2", tags = ["3", "PPP\tRRR"], created_at = datetime.utcnow() ), Note( body = "b", tags = ["VVV", "III"], created_at = datetime.utcnow() ) ] root_item = self.source_model.invisibleRootItem() for note in self.notes: item = QStandardItem() set_item_note(item, note) root_item.appendRow(item) assert self.source_model.rowCount() == len(self.notes) self.tape_filter_proxy_model.setSourceModel(self.source_model) def select_note_dicts(self, model, mask = None): assert mask == None or model.rowCount() == len(mask) assert mask == None or all(bit in [True, False] for bit in mask) dicts = [] for i in range(model.rowCount()): if mask == None or mask[i]: index = model.index(i, 0) dicts.append(model.data(index).to_dict()) return dicts def test_unfiltered_model_should_contain_all_notes(self): mask = [True, True, True, True] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask)) def test_filtered_model_should_contain_all_notes_if_searching_for_empty_string(self): self.tape_filter_proxy_model.setFilterFixedString('') mask = [True, True, True, True] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask)) def test_filtered_model_should_contain_only_matching_notes(self): keyword = 'B' assert keyword in self.notes[1].body assert not keyword.lower() in self.notes[0].body.lower() assert not keyword.lower() in self.notes[2].body.lower() assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:3]) self.tape_filter_proxy_model.setFilterFixedString(keyword) mask = [False, True, False, True] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask)) def test_filtered_model_should_treat_fixed_string_as_case_insensitive(self): keyword = 'B' assert keyword != keyword.lower() assert keyword in self.notes[1].body assert keyword.lower() in self.notes[3].body assert not keyword.lower() in self.notes[0].body.lower() assert not keyword.lower() in self.notes[2].body.lower() assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:4]) self.tape_filter_proxy_model.setFilterFixedString(keyword) mask = [False, True, False, True] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask)) def test_filtered_model_should_contain_items_with_matching_tags(self): keyword = 'III' assert all(keyword.lower() not in note.body.lower() for note in self.notes[0:4]) assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:3]) assert keyword.lower() in self.notes[3].tags[1].lower() self.tape_filter_proxy_model.setFilterFixedString(keyword) mask = [False, False, False, True] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask)) def test_filtered_model_should_only_contain_notes_with_exactly_matching_whitespace(self): keyword = 'PPP RRR' assert all(keyword.lower() not in note.body.lower() for note in self.notes[0:4]) assert 'PPP RRR' in self.notes[1].tags[1] assert 'PPP\tRRR' in self.notes[2].tags[1] self.tape_filter_proxy_model.setFilterFixedString(keyword) mask = [False, True, False, False] self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))
class NoteModelHelpersTest(unittest.TestCase): def setUp(self): self.model = QStandardItemModel() def sample_note_dict(self, id, parent_id, prev_item_id): timestamp = Note.serialize_timestamp(datetime.utcnow()) return { 'body': 'body\n\t\n', 'tags': ['a tag', 'another tag'], 'created_at': timestamp, 'modified_at': timestamp, 'id': id, 'parent_id': parent_id, 'prev_sibling_id': prev_item_id } def create_note_and_append(self, parent_item, body): note = Note(body = body) item = QStandardItem() set_item_note(item, note) parent_item.appendRow(item) return item def prepare_tree(self): root_item = self.model.invisibleRootItem() self.item_0 = self.create_note_and_append(root_item, "Note 0") self.item_0_0 = self.create_note_and_append(self.item_0, "Note 0_0") self.item_0_0_0 = self.create_note_and_append(self.item_0_0, "Note 0_0_0") self.item_0_0_0_0 = self.create_note_and_append(self.item_0_0_0, "Note 0_0_0_0") self.item_1 = self.create_note_and_append(root_item, "Note 1") self.item_1_0 = self.create_note_and_append(self.item_1, "Note 1_0") self.item_1_0_0 = self.create_note_and_append(self.item_1_0, "Note 1_0_0") self.item_1_0_1 = self.create_note_and_append(self.item_1_0, "Note 1_0_1") self.item_1_0_2 = self.create_note_and_append(self.item_1_0, "Note 1_0_2") self.item_1_0_2_0 = self.create_note_and_append(self.item_1_0_2, "Note 1_0_2_0") self.item_1_0_2_0_0 = self.create_note_and_append(self.item_1_0_2_0, "Note 1_0_2_0_0") self.item_1_0_3 = self.create_note_and_append(self.item_1_0, "Note 1_0_3") self.item_1_1 = self.create_note_and_append(self.item_1, "Note 1_1") self.item_1_1_0 = self.create_note_and_append(self.item_1_1, "Note 1_1_0") self.item_2 = self.create_note_and_append(root_item, "Note 2") self.item_2_0 = self.create_note_and_append(self.item_2, "Note 2_0") self.item_3 = self.create_note_and_append(root_item, "Note 3") def test_all_items_should_iterate_over_all_model_items_inorder(self): self.prepare_tree() expected_order = [ item_to_note(self.item_0), item_to_note(self.item_0_0), item_to_note(self.item_0_0_0), item_to_note(self.item_0_0_0_0), item_to_note(self.item_1), item_to_note(self.item_1_0), item_to_note(self.item_1_0_0), item_to_note(self.item_1_0_1), item_to_note(self.item_1_0_2), item_to_note(self.item_1_0_2_0), item_to_note(self.item_1_0_2_0_0), item_to_note(self.item_1_0_3), item_to_note(self.item_1_1), item_to_note(self.item_1_1_0), item_to_note(self.item_2), item_to_note(self.item_2_0), item_to_note(self.item_3) ] result = [] for note in all_notes(self.model): result.append(note) self.assertEqual(result, expected_order) def test_assign_note_ids_should_put_unique_integer_id_in_each_note(self): self.prepare_tree() assert all(note.id == None for note in all_notes(self.model)) assign_note_ids(self.model) ids = [note.id for note in all_notes(self.model)] self.assertEqual(len(set(ids)), len(ids)) self.assertEqual(min(ids), 1) self.assertEqual(max(ids), len(ids)) def test_assign_note_ids_should_not_crash_if_given_empty_model(self): empty_model = QStandardItemModel() assign_note_ids(empty_model) self.assertEqual(empty_model.rowCount(), 0) def test_assign_note_ids_should_not_modify_ids_in_model_that_already_has_ids(self): self.prepare_tree() assert all(note.id == None for note in all_notes(self.model)) next_id = 1 for note in all_notes(self.model): note.id = next_id next_id += 1 ids_before = list(range(1, next_id)) assign_note_ids(self.model) ids_after = [note.id for note in all_notes(self.model)] self.assertEqual(ids_after, ids_before) def test_assign_note_ids_should_assign_ids_only_to_notes_that_do_not_already_have_them(self): self.prepare_tree() assert all(note.id == None for note in all_notes(self.model)) next_id = 0 for note in all_notes(self.model): if next_id % 2 == 0: note.id = next_id next_id += 1 ids_before = [note.id for note in all_notes(self.model)] assert all(id == None for id in ids_before[1::2]) assign_note_ids(self.model) ids_after = [note.id for note in all_notes(self.model)] self.assertEqual(ids_after[::2], ids_before[::2]) self.assertTrue(all(id != None for id in ids_after[1::2])) def test_assign_note_ids_should_assign_ids_not_colliding_with_already_assigned_ones(self): self.prepare_tree() assert all(note.id == None for note in all_notes(self.model)) next_id = 0 for note in all_notes(self.model): if next_id % 2 == 0: note.id = next_id next_id += 1 ids_before = [note.id for note in all_notes(self.model)] assert all(id == None for id in ids_before[1::2]) assign_note_ids(self.model) ids_after = [note.id for note in all_notes(self.model)] self.assertEqual(set(ids_after) & set(ids_before[1::2]), set()) def test_dump_notes_should_serialize_note_tree_into_a_list_of_dicts_of_primitives(self): self.prepare_tree() notes = list(all_notes(self.model)) assign_note_ids(self.model) assert all(note.id != None for note in notes) serialized_notes = dump_notes(self.model) self.assertEqual(len(serialized_notes), len(notes)) for key in ['body', 'tags', 'created_at', 'modified_at', 'id', 'parent_id', 'prev_sibling_id']: self.assertTrue(all(key in note_dict for note_dict in serialized_notes)) for key in ['body', 'created_at', 'modified_at']: self.assertTrue(all(isinstance(note_dict[key], str) for note_dict in serialized_notes)) for key in ['id', 'parent_id', 'prev_sibling_id']: self.assertTrue((note_dict[key] == None or all(isinstance(note_dict[key], int)) for note_dict in serialized_notes)) self.assertTrue(all(all(isinstance(tag, str) for tag in note_dict['tags']) for note_dict in serialized_notes)) def test_dump_notes_should_serialize_tree_structure_correctly(self): self.prepare_tree() assign_note_ids(self.model) items = list(all_items(self.model)) assert all(item_to_id(item) != None for item in items) expected_tree = { item_to_id(self.item_0): (None, None), item_to_id(self.item_0_0): (self.item_0, None), item_to_id(self.item_0_0_0): (self.item_0_0, None), item_to_id(self.item_0_0_0_0): (self.item_0_0_0, None), item_to_id(self.item_1): (None, self.item_0), item_to_id(self.item_1_0): (self.item_1, None), item_to_id(self.item_1_0_0): (self.item_1_0, None), item_to_id(self.item_1_0_1): (self.item_1_0, self.item_1_0_0), item_to_id(self.item_1_0_2): (self.item_1_0, self.item_1_0_1), item_to_id(self.item_1_0_2_0): (self.item_1_0_2, None), item_to_id(self.item_1_0_2_0_0): (self.item_1_0_2_0, None), item_to_id(self.item_1_0_3): (self.item_1_0, self.item_1_0_2), item_to_id(self.item_1_1): (self.item_1, self.item_1_0), item_to_id(self.item_1_1_0): (self.item_1_1, None), item_to_id(self.item_2): (None, self.item_1), item_to_id(self.item_2_0): (self.item_2, None), item_to_id(self.item_3): (None, self.item_2) } serialized_notes = dump_notes(self.model) serialized_id_set = set(note_dict['id'] for note_dict in serialized_notes) note_id_set = set(item_to_id(item) for item in items) self.assertEqual(serialized_id_set, note_id_set) for note_dict in serialized_notes: expected_node = expected_tree[note_dict['id']] expected_parent_id = item_to_id(expected_node[0]) if expected_node[0] != None else None expected_prev_sibling_id = item_to_id(expected_node[1]) if expected_node[1] != None else None self.assertEqual(note_dict['parent_id'], expected_parent_id) self.assertEqual(note_dict['prev_sibling_id'], expected_prev_sibling_id) def test_dump_notes_should_handle_empty_model(self): empty_model = QStandardItemModel() serialized_notes = dump_notes(empty_model) self.assertEqual(serialized_notes, []) def test_load_notes_should_deserialize_tree_structure_correctly(self): self.prepare_tree() assign_note_ids(self.model) serialized_notes_before = dump_notes(self.model) assert all(note_dict['id'] != None for note_dict in serialized_notes_before) new_model = load_notes(serialized_notes_before) serialized_notes_after = dump_notes(new_model) note_id = lambda note_dict: note_dict['id'] self.assertEqual(sorted(serialized_notes_after, key = note_id), sorted(serialized_notes_before, key = note_id)) def test_load_notes_should_raise_error_if_tree_contains_sibling_cycle(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, 4), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 3) ] with self.assertRaises(SiblingCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_sibling_cycle_that_does_not_include_all_siblings(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(5, 1, None), self.sample_note_dict(6, 1, 5), self.sample_note_dict(7, 1, 6), self.sample_note_dict(2, 1, 4), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 3) ] with self.assertRaises(SiblingCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_an_element_which_is_its_own_prev_sibling(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 4) ] with self.assertRaises(SiblingCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_parent_cycle(self): serialized_notes = [ self.sample_note_dict(1, 4, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 2, None), self.sample_note_dict(4, 3, None) ] with self.assertRaises(ParentCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_parent_cycle_that_does_not_reach_top_level(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 2, None), self.sample_note_dict(4, 3, None), self.sample_note_dict(5, 8, None), self.sample_note_dict(6, 5, None), self.sample_note_dict(7, 6, None), self.sample_note_dict(8, 7, None), self.sample_note_dict(9, 8, 5) ] with self.assertRaises(ParentCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_an_element_which_is_its_own_parent(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 2, None), self.sample_note_dict(4, 4, None) ] with self.assertRaises(ParentCycle): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_siblings_with_the_same_prev_sibling_id(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 2), self.sample_note_dict(5, 1, 4) ] with self.assertRaises(ConflictingSiblingIds): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_siblings_with_the_same_prev_sibling_id_being_none(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, None), self.sample_note_dict(4, 1, 2), self.sample_note_dict(5, 1, 4) ] with self.assertRaises(ConflictingSiblingIds): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_note_with_empty_id(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 3), self.sample_note_dict(None, 1, 4) ] with self.assertRaises(EmptyNoteId): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_note_without_parent_id_attribute(self): # NOTE: It's about the attribute missing from the dict, not being None serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 3), self.sample_note_dict(5, 1, 4) ] del serialized_notes[-1]['parent_id'] with self.assertRaises(MissingParentId): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_tree_contains_note_without_prev_sibling_id_attribute(self): # NOTE: It's about the attribute missing from the dict, not being None serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 3), self.sample_note_dict(5, 1, 4) ] del serialized_notes[-1]['prev_sibling_id'] with self.assertRaises(MissingPrevSiblingId): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_prev_sibling_id_does_not_exist_in_tree(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 1, 666), self.sample_note_dict(5, 1, 4) ] with self.assertRaises(MissingNote): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_parent_id_does_not_exist_in_tree(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 666, 3), self.sample_note_dict(5, 1, 4) ] with self.assertRaises(MissingNote): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_prev_sibling_has_different_parent(self): serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(4, 5, 3), self.sample_note_dict(5, None, 4) ] with self.assertRaises(InconsistentParentIds): load_notes(serialized_notes) def test_load_notes_should_raise_error_if_prev_sibling_at_a_different_level(self): # This can also be classified as siblings having different parents but # the structure here is a bit different so the example is included for completeness. serialized_notes = [ self.sample_note_dict(1, None, None), self.sample_note_dict(2, 1, None), self.sample_note_dict(3, 2, None), self.sample_note_dict(4, 2, 3), self.sample_note_dict(5, 1, 4) ] with self.assertRaises(InconsistentParentIds): load_notes(serialized_notes) def test_load_notes_should_correctly_handle_notes_not_in_the_final_order(self): # This means note's prev sibling and/or parent coming after the note serialized_notes_before = [ self.sample_note_dict(15, 7, 14), self.sample_note_dict(7, 5, 6), self.sample_note_dict(2, 1, None), self.sample_note_dict(14, 7, 10), self.sample_note_dict(4, 1, 3), self.sample_note_dict(17, 5, 7), self.sample_note_dict(18, 5, 17), self.sample_note_dict(10, 7, 9), self.sample_note_dict(11, 10, None), self.sample_note_dict(3, 1, 2), self.sample_note_dict(12, 10, 11), self.sample_note_dict(9, 7, 8), self.sample_note_dict(8, 7, None), self.sample_note_dict(16, 15, None), self.sample_note_dict(13, 10, 12), self.sample_note_dict(6, 5, None), self.sample_note_dict(20, 19, None), self.sample_note_dict(19, None, 5), self.sample_note_dict(5, None, 1), self.sample_note_dict(1, None, None) ] new_model = load_notes(serialized_notes_before) serialized_notes_after = dump_notes(new_model) note_id = lambda note_dict: note_dict['id'] self.assertEqual(sorted(serialized_notes_after, key = note_id), sorted(serialized_notes_before, key = note_id)) def test_load_notes_should_detect_wrong_attribute_types(self): note_dict = { 'body': "Y", 'tags': ["a", "b", "c"], 'created_at': "2013-06-16T00:00:00.000000", 'modified_at': "2013-07-16T00:00:00.000000", 'id': 1, 'parent_id': None, 'prev_sibling_id': None } # ASSUMPTION: This does not raise exceptions load_notes([note_dict]) wrong_type_samples = [ ('body', 1), ('tags', ("a", "b", "c")), ('tags', ()), ('tags', {}), ('tags', set()), ('tags', deque(["a", "b", "c"])), ('tags', [1, 2, 3]), ('created_at', 1234567890), ('created_at', datetime(2013, 1, 1)), ('modified_at', 1234567890), ('modified_at', datetime(2013, 1, 1)), ('id', "10"), ('id', []), ('parent_id', "10"), ('parent_id', []), ('prev_sibling_id', "10"), ('prev_sibling_id', []) ] for tested_attribute, wrong_value in wrong_type_samples: filtered_note_dict = {attribute: note_dict[attribute] if attribute != tested_attribute else wrong_value for attribute in note_dict} with self.assertRaises(WrongAttributeType): load_notes([filtered_note_dict])
new_path = get_path(new_selection_indexes[0]) print(old_path, " -> ", new_path) if __name__ == '__main__': app = QApplication(sys.argv) tree_view = QTreeView() ### model = QStandardItemModel(None) rootItem = model.invisibleRootItem() # Defining a couple of items americaItem = QStandardItem("America") canadaItem = QStandardItem("Canada") europeItem = QStandardItem("Europe") franceItem = QStandardItem("France") brittanyItem = QStandardItem("Brittany") # Building up the hierarchy rootItem.appendRow(americaItem) rootItem.appendRow(europeItem) americaItem.appendRow(canadaItem) europeItem.appendRow(franceItem) franceItem.appendRow(brittanyItem)
class FittingAdvancedDlg(QDialog, Ui_Dialog): ''' The tree should provide any fittable parameter of any layers layer 1 value *what to change* - thickness layer.thickness - srough_thickness (if model is on) if layer.srough: layer.sroughThickness - haze reflection (if model is on) if layer.srough: layer.sroughHazeR - haze transmission (if model is on) if layer.srough: layer.sroughHazeT - constant n (if source is constant) if layer.criSource=='constant': layer.criConstant[0] - constant k (if source is constant) if layer.criSource=='constant': layer.criConstant[1] - grading (constant) (if source is constant) if layer.criSource=='graded' && layer.criGrading['mode']=='constant': layer.criGrading['value'] + dielectric function (if source) if layer.criSource=='dielectric function' - e0 layer.dielectricFunction['e0'] + oscillator 0 for each oscillator: layer.dielectricFunction['oscillators'][#of Osci]['name'] : [{'name': 'Lorentz', 'values': [1, 3, 0.2], 'active': True}], - value 1 layer.dielectricFunction['oscillators'][#of Osci]['value'][0] - value 2 ... + oscillator 1 - value 1 .. - collection function (constant) (if selected) if layer.collection['source'] == 'from collection function' && layer.collection['mode'] == 'constant': layer.collection['value'] + diff length model if layer.collection['source'] == 'from diffusion length' - space charge region width layer.collection['SCRwidth'] - diff length layer.collection['diffLength'] - surface rec. velocity layer.collection['recVel'] layer 2 ... ''' 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 fillReferences(self): for value in self.referenceList: item = QStandardItem(value[0]) check = Qt.Checked if value[1] else Qt.Unchecked item.setCheckState(check) item.setCheckable(True) self.referenceListModel.appendRow(item) def updateReferences(self): self.referenceDataSelected = {} for row in range(self.referenceListModel.rowCount()): item = self.referenceListModel.item(row) if item.checkState() == Qt.Checked: self.referenceList[row][1] = True self.referenceDataSelected[item.text()] = self.referenceData[item.text()] else: self.referenceList[row][1] = False self.updatePlot() #print(len(self.referenceDataSelected)) #print('{} {}'.format(row, self.references[row])) def updatePlot(self): plotDict = {} for ref in self.referenceList: if ref[1]: if ref[0] == 'R reference': plotDict['R reference'] = self.referenceData['R reference'] plotDict['R'] = self.optics.RspectrumSystem if ref[0] == 'T reference': plotDict['T reference'] = self.referenceData['T reference'] plotDict['T'] = self.optics.TspectrumSystem if ref[0] == 'EQE reference': plotDict['EQE reference'] = self.referenceData['EQE reference'] plotDict['EQE'] = self.optics.EQE if ref[0] == 'psi reference': plotDict['psi reference'] = self.referenceData['psi reference'] plotDict['psi'] = self.optics.psi if ref[0] == 'delta reference': plotDict['delta reference'] = self.referenceData['delta reference'] plotDict['delta'] = self.optics.delta x = self.optics.wavelength if plotDict: self.plotView.showCurves(x, plotDict, 'wavelength (nm)', 'value [a.u.]') else: self.plotView.ax.clear() self.plotView.canvas.draw() def fillParameterTree(self): rows = self.parameterModel.rowCount() if rows: while self.parameterModel.rowCount() > 0: self.parameterModel.removeRow(0) self.parameterList = [] parameterStr = 'self.stack[' for i, layer in enumerate(self.stack): parameterStr += '{}].'.format(i) layerBranch = QStandardItem(layer.name) self.root.appendRow(layerBranch) self.addTreeEntry(layerBranch, 'thickness (nm)', layer.thickness, self.changeThickness) if layer.srough: self.addTreeEntry(layerBranch, 'thickness roughness layer (nm)', layer.sroughThickness, self.changeSroughThickness) self.addTreeEntry(layerBranch, 'Haze R', layer.sroughHazeR, self.changeSroughHazeR) self.addTreeEntry(layerBranch, 'Haze T', layer.sroughHazeT, self.changeSroughHazeT) if layer.criSource=='constant': self.addTreeEntry(layerBranch, 'constant n', layer.criConstant[0], self.changeConstantn) self.addTreeEntry(layerBranch, 'constant k', layer.criConstant[1], self.changeConstantk) if layer.criSource=='graded' and layer.criGrading['mode']=='constant': self.addTreeEntry(layerBranch, 'constant grading', layer.criGrading['value'], self.changeConstantGrading) if layer.criSource=='dielectric function': criBranch = QStandardItem('dielectric function parameters') layerBranch.appendRow(criBranch) self.addTreeEntry(criBranch, 'e0', layer.dielectricFunction['e0'], self.changeConstante, level = 2) for idx, oscillator in enumerate(layer.dielectricFunction['oscillators']): osciBranch = QStandardItem('{} {}'.format(idx, oscillator['name'])) criBranch.appendRow(osciBranch) parameterNames = MODELS[oscillator['name']]['parameter'] for i, value in enumerate(oscillator['values']): self.addTreeEntry(osciBranch, parameterNames[i], value, self.changeOscillator, level = 3) if layer.collection['source'] == 'from collection function' and layer.collection['mode'] == 'constant': self.addTreeEntry(layerBranch, 'constant collection efficiency', layer.collection['value'], self.changeConstantCollection) if layer.collection['source'] == 'from diffusion length': collectionBranch = QStandardItem('collection model') layerBranch.appendRow(collectionBranch) self.addTreeEntry(collectionBranch, 'space charge region width (nm)', layer.collection['SCRwidth'], self.changeSCR, level = 2) self.addTreeEntry(collectionBranch, 'diffusion length (nm)', layer.collection['diffLength'], self.changeDiffL, level = 2) self.addTreeEntry(collectionBranch, 'recombination velocity (cm/s)', layer.collection['recVel'], self.changerecVel, level = 2) self.parameterTreeView.setColumnWidth(1, 80) self.parameterTreeView.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.parameterTreeView.expandAll() def addTreeEntry(self, parent, name, parameter, func, level = 1): child = QStandardItem(name) child.setCheckable(True) value = QStandardItem(str(parameter)) parent.appendRow([child, value]) if level == 3: osciNum = parent.parent().rowCount() - 2 itemNum = parent.rowCount() - 1 self.parameterList.append([parameter, func, osciNum, itemNum]) else: self.parameterList.append([parameter, func]) def getSelectedValues(self): selected = [] # name, layer number, initial value, function to change i = 0 for row in range(self.parameterModel.rowCount()): layer = self.parameterModel.item(row) for row1 in range(layer.rowCount()): child1 = layer.child(row1) if not child1.hasChildren(): if child1.checkState() == Qt.Checked: selected.append([child1.text(), row, self.parameterList[i][0], self.parameterList[i][1]]) i += 1 else: for row2 in range(child1.rowCount()): child2 = child1.child(row2) if not child2.hasChildren(): if child2.checkState() == Qt.Checked: selected.append([child2.text(), row, self.parameterList[i][0], self.parameterList[i][1]]) i += 1 else: for row3 in range(child2.rowCount()): child3 = child2.child(row3) if child3.checkState() == Qt.Checked: selected.append([child3.text(), row, self.parameterList[i][0], self.parameterList[i][1], self.parameterList[i][2], self.parameterList[i][3]]) i += 1 return selected @pyqtSlot() def on_testPB_clicked(self): selected = self.getSelectedValues() str = '' #print(selected) for item in selected: str += '{} {}\n'.format(item[0], item[1]) self.resultTextEdit.setText(str) self.plot() if selected: layer = selected[0][1] func = selected[0][2] value = 250 func(layer, value) #print(self.parameterList) #self.parameterList[0][0] = 300 #print('stack {}'.format(self.stack[0].thickness)) def runOptics(self): input = LayerStack(self.StackName, self.stack, self.settings, self.getCRI) self.optics = Optics(self.StackName, input, self.references, self.settings) self.optics.calcStack() self.optics.createReferenceCurves() self.optics.calcFieldIntensity() self.optics.calcAbsorption() self.optics.calcQE() self.optics.calcEllipsometry() #get reference data self.referenceData = {} for ref in self.referenceList: if ref[0] == 'R reference': self.referenceData['R reference'] = self.optics.R_reference elif ref[0] == 'T reference': self.referenceData['T reference'] = self.optics.T_reference elif ref[0] == 'EQE reference': self.referenceData['EQE reference'] = self.optics.EQE_reference elif ref[0] == 'psi reference': self.referenceData['psi reference'] = self.optics.psi_reference elif ref[0] == 'delta reference': self.referenceData['delta reference'] = self.optics.delta_reference @pyqtSlot() def on_startFittingPB_clicked(self): if not self.referenceDataSelected: QMessageBox.warning(self, "error", 'Error - no reference curve selected!\n', QMessageBox.StandardButtons(QMessageBox.Close)) return parameterList = self.getSelectedValues() if not parameterList: QMessageBox.warning(self, "error", 'Error - no fitting parameter selected!\n', QMessageBox.StandardButtons(QMessageBox.Close)) return self.resultTextEdit.setPlainText("") start_time = time.time() #get initial deviation #get initial values parameters = [] for item in parameterList: parameters.append(item[2]) # run fitting try: self.resultTextEdit.setText("busy fitting ...") minResult = minimize(self.minimizeFunction, parameters, args = (parameterList), method= self.configuration['method'], tol=self.configuration['tolerance'], options = {'maxiter' : self.configuration['noOfIterations']}) #, tol=1e-6 except RuntimeError as e: QMessageBox.warning(self, "fitting error", 'Error - curve fitting failed!\n{}'.format(e.args[0]), QMessageBox.StandardButtons(QMessageBox.Close)) return # run all optics to get other curves when references are changed self.runOptics() # to make sure at least the last result is plotted self.updatePlot() duration = time.time() - start_time message = "The optimized parameters are:\n" for i, item in enumerate(parameterList): message += "{} of {} --> {}\n".format(item[0], self.stack[item[1]].name, minResult.x[i]) message += "Details: {}\nNumber of Iterations: {}\nNumber of function calls: {}\nChi-square: {:7.4f}\nFitting time: {:7.2f} seconds".format( minResult.message, minResult.nit, minResult.nfev, minResult.fun, duration) self.resultTextEdit.setText(message) self.fillParameterTree() #logging.info('\n' + 50 * '#' + '\n' + message + '\n do final calculation ...\n' + 50 * '#') def minimizeFunction(self, values, parameterList): #set the parameters for i, value in enumerate(values): layer = parameterList[i][1] func = parameterList[i][3] if func == self.changeOscillator: osciNum = parameterList[i][4] itemNum = parameterList[i][5] func(layer, osciNum, itemNum, value) else: func(layer, value) input = LayerStack(self.StackName, self.stack, self.settings, self.getCRI) self.optics = Optics(self.StackName, input, self.references, self.settings) self.optics.calcStack() #print(len(self.referenceDataSelected)) errorArray = np.zeros(len(self.optics.wavelength)) for key, exp in self.referenceDataSelected.items(): if key == 'R reference': model = self.optics.RspectrumSystem errorArray += ((model - exp)/exp)**2 elif key == 'T reference': model = self.optics.TspectrumSystem errorArray += ((model - exp)/exp)**2 elif key == 'EQE reference': self.optics.calcFieldIntensity() self.optics.calcAbsorption() self.optics.calcQE() model = self.optics.EQE errorArray += ((model - exp)/exp)**2 elif key == 'psi reference': self.optics.calcEllipsometry() model = self.optics.psi errorArray += ((model - exp)/exp)**2 elif key == 'delta reference': self.optics.calcEllipsometry() model = self.optics.delta errorArray += ((model - exp)/exp)**2 #N = len(errorArray) #M = len(parameterList) if self.configuration['plotInBetween']: self.updatePlot() return np.sum(errorArray) # chi² or MSE = 1/(2N-M) * chi² @pyqtSlot(str) def on_methodCB_currentIndexChanged(self, p0): self.configuration['method'] = p0 @pyqtSlot(int) def on_noOfIterationsSB_valueChanged(self, p0): self.configuration['noOfIterations'] = p0 def changeThickness(self, layer, value): self.stack[layer].thickness = int(value) def changeSroughThickness(self, layer, value): self.stack[layer].sroughThickness = int(value) def changeSroughHazeR(self, layer, value): self.stack[layer].sroughHazeR = value def changeSroughHazeT(self, layer, value): self.stack[layer].sroughHazeT = value def changeConstantn(self, layer, value): self.stack[layer].criConstant[0] = value def changeConstantk(self, layer, value): self.stack[layer].criConstant[1] = value def changeConstantGrading(self, layer, value): self.stack[layer].criGrading['value'] = value def changeConstante(self, layer, value): self.stack[layer].dielectricFunction['e0'] = value e1, e2, self.stack[layer].dielectricFunction, eV = calcOsciFunction(self.stack[layer].dielectricFunction) def changeConstantCollection(self, layer, value): self.stack[layer].collection['value'] = value self.stack[layer].makeXcollection() def changeSCR(self, layer, value): self.stack[layer].collection['SCRwidth'] = int(value) self.stack[layer].makeXcollection() def changeDiffL(self, layer, value): self.stack[layer].collection['diffLength'] = int(value) self.stack[layer].makeXcollection() def changerecVel(self, layer, value): self.stack[layer].collection['recVel'] = value self.stack[layer].makeXcollection() def changeOscillator(self, layer, osciNum, itemNum, value): self.stack[layer].dielectricFunction['oscillators'][osciNum]['values'][itemNum] = value e1, e2, self.stack[layer].dielectricFunction, eV = calcOsciFunction(self.stack[layer].dielectricFunction) @pyqtSlot() def on_reloadPB_clicked(self): self.stack = self.originalStack self.fillParameterTree() @pyqtSlot(float) def on_toleranceSB_valueChanged(self, p0): self.configuration['tolerance'] = p0 @pyqtSlot(bool) def on_plotInBetweenCB_toggled(self, checked): self.configuration['plotInBetween'] = checked
class ProgramInfoFiles(QWidget, Ui_ProgramInfoFiles): def __init__(self, context, update_main_ui_state, set_widget_enabled, is_alive, show_upload_files_wizard, show_download_wizard): QWidget.__init__(self) self.setupUi(self) self.session = context.session self.script_manager = context.script_manager self.program = context.program self.update_main_ui_state = update_main_ui_state self.set_widget_enabled = set_widget_enabled self.is_alive = is_alive self.show_download_wizard = show_download_wizard self.bin_directory = posixpath.join(self.program.root_directory, 'bin') self.refresh_in_progress = False self.any_refresh_in_progress = False # set from ProgramInfoMain.update_ui_state self.available_files = [] self.available_directories = [] self.folder_icon = QIcon(load_pixmap('folder-icon.png')) self.file_icon = QIcon(load_pixmap('file-icon.png')) self.tree_files_model = QStandardItemModel(self) self.tree_files_model_header = ['Name', 'Size', 'Last Modified'] self.tree_files_proxy_model = FilesProxyModel(self) self.last_download_directory = get_home_path() self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header) self.tree_files_proxy_model.setSourceModel(self.tree_files_model) self.tree_files.setModel(self.tree_files_model) self.tree_files.setModel(self.tree_files_proxy_model) self.tree_files.setColumnWidth(0, 210) self.tree_files.setColumnWidth(1, 85) self.tree_files.selectionModel().selectionChanged.connect(self.update_ui_state) self.tree_files.activated.connect(self.rename_activated_file) self.button_upload_files.clicked.connect(show_upload_files_wizard) self.button_download_files.clicked.connect(self.download_selected_files) self.button_rename_file.clicked.connect(self.rename_selected_file) self.button_change_file_permissions.clicked.connect(self.change_permissions_of_selected_file) self.button_delete_files.clicked.connect(self.delete_selected_files) self.label_error.setVisible(False) def update_ui_state(self): selection_count = len(self.tree_files.selectionModel().selectedRows()) self.set_widget_enabled(self.button_upload_files, not self.any_refresh_in_progress) self.set_widget_enabled(self.button_download_files, not self.any_refresh_in_progress and selection_count > 0) self.set_widget_enabled(self.button_rename_file, not self.any_refresh_in_progress and selection_count == 1) self.set_widget_enabled(self.button_change_file_permissions, not self.any_refresh_in_progress and selection_count == 1) self.set_widget_enabled(self.button_delete_files, not self.any_refresh_in_progress and selection_count > 0) def close_all_dialogs(self): pass def refresh_files_done(self): self.refresh_in_progress = False self.update_main_ui_state() def refresh_files(self): def cb_walk(result): okay, message = check_script_result(result, decode_stderr=True) if not okay: self.label_error.setText('<b>Error:</b> ' + html.escape(message)) self.label_error.setVisible(True) self.refresh_files_done() return self.label_error.setVisible(False) def expand_async(data): try: walk = json.loads(zlib.decompress(memoryview(data)).decode('utf-8')) except: walk = None if walk == None or not isinstance(walk, dict): available_files = [] available_directories = [] walk = None else: available_files, available_directories = expand_walk_to_lists(walk) return walk, available_files, available_directories def cb_expand_success(result): walk, available_files, available_directories = result self.available_files = available_files self.available_directories = available_directories if walk != None: expand_walk_to_model(walk, self.tree_files_model, self.folder_icon, self.file_icon) else: self.label_error.setText('<b>Error:</b> Received invalid data') self.label_error.setVisible(True) self.tree_files.header().setSortIndicator(0, Qt.AscendingOrder) self.refresh_files_done() def cb_expand_error(): self.label_error.setText('<b>Error:</b> Internal async error') self.label_error.setVisible(True) self.refresh_files_done() async_call(expand_async, result.stdout, cb_expand_success, cb_expand_error) self.refresh_in_progress = True self.update_main_ui_state() width1 = self.tree_files.columnWidth(0) width2 = self.tree_files.columnWidth(1) self.tree_files_model.clear() self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header) self.tree_files.setColumnWidth(0, width1) self.tree_files.setColumnWidth(1, width2) self.script_manager.execute_script('walk', cb_walk, [self.bin_directory], max_length=1024*1024, decode_output_as_utf8=False) def get_directly_selected_name_items(self): selected_indexes = self.tree_files.selectedIndexes() selected_name_items = [] for selected_index in selected_indexes: if selected_index.column() == 0: mapped_index = self.tree_files_proxy_model.mapToSource(selected_index) selected_name_items.append(self.tree_files_model.itemFromIndex(mapped_index)) return selected_name_items def download_selected_files(self): selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) == 0: return downloads = [] def expand(name_item): item_type = name_item.data(USER_ROLE_ITEM_TYPE) if item_type == ITEM_TYPE_DIRECTORY: for i in range(name_item.rowCount()): expand(name_item.child(i, 0)) elif item_type == ITEM_TYPE_FILE: filename = get_full_item_path(name_item) downloads.append(Download(filename, QDir.toNativeSeparators(filename))) for selected_name_item in selected_name_items: expand(selected_name_item) if len(downloads) == 0: return download_directory = get_existing_directory(get_main_window(), 'Download Files', self.last_download_directory) if len(download_directory) == 0: return self.last_download_directory = download_directory self.show_download_wizard('files', download_directory, downloads) def rename_activated_file(self, index): if index.column() == 0 and not self.any_refresh_in_progress: mapped_index = self.tree_files_proxy_model.mapToSource(index) name_item = self.tree_files_model.itemFromIndex(mapped_index) item_type = name_item.data(USER_ROLE_ITEM_TYPE) # only rename files via activation, because directories are expanded if item_type == ITEM_TYPE_FILE: self.rename_item(name_item) def rename_selected_file(self): selection_count = len(self.tree_files.selectionModel().selectedRows()) if selection_count != 1: return selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) != 1: return self.rename_item(selected_name_items[0]) def rename_item(self, name_item): item_type = name_item.data(USER_ROLE_ITEM_TYPE) if item_type == ITEM_TYPE_FILE: title = 'Rename File' type_name = 'file' else: title = 'Rename Directory' type_name = 'directory' old_name = name_item.text() # get new name dialog = ExpandingInputDialog(get_main_window()) dialog.setModal(True) dialog.setWindowTitle(title) dialog.setLabelText('Enter new {0} name:'.format(type_name)) dialog.setInputMode(QInputDialog.TextInput) dialog.setTextValue(old_name) dialog.setOkButtonText('Rename') if dialog.exec_() != QDialog.Accepted: return new_name = dialog.textValue() if new_name == old_name: return # check that new name is valid if len(new_name) == 0 or new_name == '.' or new_name == '..' or '/' in new_name: QMessageBox.critical(get_main_window(), title + ' Error', 'A {0} name cannot be empty, cannot be one dot [.], cannot be two dots [..] and cannot contain a forward slash [/].' .format(type_name)) return # check that new name is not already in use name_item_parent = name_item.parent() if name_item_parent == None: name_item_parent = self.tree_files_model.invisibleRootItem() for i in range(name_item_parent.rowCount()): if new_name == name_item_parent.child(i).text(): QMessageBox.critical(get_main_window(), title + ' Error', 'The new {0} name is already in use.'.format(type_name)) return absolute_old_name = posixpath.join(self.bin_directory, get_full_item_path(name_item)) absolute_new_name = posixpath.join(posixpath.split(absolute_old_name)[0], new_name) def cb_rename(result): if not report_script_result(result, title + ' Error', 'Could not rename {0}'.format(type_name)): return name_item.setText(new_name) if self.tree_files.header().sortIndicatorSection() == 0: self.tree_files.header().setSortIndicator(0, self.tree_files.header().sortIndicatorOrder()) self.script_manager.execute_script('rename', cb_rename, [absolute_old_name, absolute_new_name]) def change_permissions_of_selected_file(self): selection_count = len(self.tree_files.selectionModel().selectedRows()) if selection_count != 1: return selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) != 1: return name_item = selected_name_items[0] item_type = name_item.data(USER_ROLE_ITEM_TYPE) old_permissions = name_item.data(USER_ROLE_PERMISSIONS) if item_type == ITEM_TYPE_FILE: title = 'Change File Permissions' type_name = 'file' else: title = 'Change Directory Permissions' type_name = 'directory' dialog = ProgramInfoFilesPermissions(get_main_window(), title, old_permissions) if dialog.exec_() != QDialog.Accepted: return new_permissions = dialog.get_permissions() if new_permissions == (old_permissions & 0o777): return absolute_name = posixpath.join(self.bin_directory, get_full_item_path(name_item)) def cb_change_permissions(result): if not report_script_result(result, title + ' Error', 'Could change {0} permissions'.format(type_name)): return name_item.setData(new_permissions, USER_ROLE_PERMISSIONS) self.script_manager.execute_script('change_permissions', cb_change_permissions, [absolute_name, str(new_permissions)]) def delete_selected_files(self): button = QMessageBox.question(get_main_window(), 'Delete Files', 'Irreversibly deleting selected files and directories.', QMessageBox.Ok, QMessageBox.Cancel) if not self.is_alive() or button != QMessageBox.Ok: return selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) == 0: return script_instance_ref = [None] def progress_canceled(): script_instance = script_instance_ref[0] if script_instance == None: return self.script_manager.abort_script(script_instance) progress = ExpandingProgressDialog(self) progress.set_progress_text_visible(False) progress.setModal(True) progress.setWindowTitle('Delete Files') progress.setLabelText('Collecting files and directories to delete') progress.setRange(0, 0) progress.canceled.connect(progress_canceled) progress.show() files_to_delete = [] dirs_to_delete = [] all_done = False while not all_done: all_done = True for selected_name_item in list(selected_name_items): item_done = False parent = selected_name_item.parent() while not item_done and parent != None: if parent in selected_name_items: selected_name_items.remove(selected_name_item) item_done = True else: parent = parent.parent() if item_done: all_done = False break for selected_name_item in selected_name_items: path = get_full_item_path(selected_name_item) item_type = selected_name_item.data(USER_ROLE_ITEM_TYPE) if item_type == ITEM_TYPE_DIRECTORY: dirs_to_delete.append(posixpath.join(self.bin_directory, path)) else: files_to_delete.append(posixpath.join(self.bin_directory, path)) message = 'Deleting ' if len(files_to_delete) == 1: message += '1 file ' elif len(files_to_delete) > 1: message += '{0} files '.format(len(files_to_delete)) if len(dirs_to_delete) == 1: if len(files_to_delete) > 0: message += 'and ' message += '1 directory' elif len(dirs_to_delete) > 1: if len(files_to_delete) > 0: message += 'and ' message += '{0} directories'.format(len(dirs_to_delete)) progress.setLabelText(message) def cb_delete(result): script_instance = script_instance_ref[0] if script_instance != None: aborted = script_instance.abort else: aborted = False script_instance_ref[0] = None progress.cancel() self.refresh_files() if aborted: QMessageBox.information(get_main_window(), 'Delete Files', 'Delete operation was aborted.') return report_script_result(result, 'Delete Files Error', 'Could not delete selected files/directories:') script_instance_ref[0] = self.script_manager.execute_script('delete', cb_delete, [json.dumps(files_to_delete), json.dumps(dirs_to_delete)], execute_as_user=True)
class SetupDialog(QDialog, Ui_SetupDialog): """ Function and Event handling class for the Ui_SetupDialog. """ def __init__(self, parent, host_infos): QDialog.__init__(self, parent, get_modeless_dialog_flags()) self._gui_logger = GUILogger("GUILogger", logging.INFO) self._gui_job = None EventLogger.add_logger(self._gui_logger) self.data_logger_thread = None self.tab_debug_warning = False self.device_dialog = None self.last_host_index = -1 self.setupUi(self) self.model_data = QStandardItemModel(self) self.model_data.setHorizontalHeaderLabels(['Time', 'Name', 'UID', 'Var', 'Raw', 'Unit']) self.table_data.setModel(self.model_data) self.table_data.setColumnWidth(0, 160) self.table_data.setColumnWidth(1, 170) self.table_data.setColumnWidth(2, 50) self.table_data.setColumnWidth(3, 110) self.table_data.setColumnWidth(4, 70) self.table_data.setColumnWidth(5, 100) self.model_devices = QStandardItemModel(self) self.model_devices.setHorizontalHeaderLabels(['Device', 'Value']) self.tree_devices.setModel(self.model_devices) self.tree_devices.setColumnWidth(0, 300) self.signal_initialization() self.check_authentication.stateChanged.connect(self.authentication_state_changed) self.label_secret.hide() self.edit_secret.hide() self.edit_secret.setEchoMode(QLineEdit.Password) self.check_secret_show.hide() self.check_secret_show.stateChanged.connect(self.secret_show_state_changed) self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/start-icon.png'))) self.example_timestamp = time.time() self.edit_csv_file_name.setText(os.path.join(get_home_path(), 'logger_data_{0}.csv'.format(int(self.example_timestamp)))) self.edit_log_file_name.setText(os.path.join(get_home_path(), 'logger_debug_{0}.log'.format(int(self.example_timestamp)))) self.combo_data_time_format.addItem(utils.timestamp_to_de(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_data_time_format.addItem(utils.timestamp_to_de_msec(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS,000)', 'de-msec') self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count()) self.combo_data_time_format.addItem(utils.timestamp_to_us(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_data_time_format.addItem(utils.timestamp_to_us_msec(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS.000)', 'us-msec') self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count()) self.combo_data_time_format.addItem(utils.timestamp_to_iso(self.example_timestamp) + ' (ISO 8601)', 'iso') self.combo_data_time_format.addItem(utils.timestamp_to_iso_msec(self.example_timestamp) + ' (ISO 8601 + Milliseconds)', 'iso-msec') self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count()) self.combo_data_time_format.addItem(utils.timestamp_to_unix(self.example_timestamp) + ' (Unix)', 'unix') self.combo_data_time_format.addItem(utils.timestamp_to_unix_msec(self.example_timestamp) + ' (Unix + Milliseconds)', 'unix-msec') self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count()) t = utils.timestamp_to_strftime(self.example_timestamp, self.edit_data_time_format_strftime.text()) if len(t) == 0: t = '<empty>' self.combo_data_time_format.addItem((t + ' (strftime)'), 'strftime') self.combo_debug_time_format.addItem(utils.timestamp_to_de(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_debug_time_format.addItem(utils.timestamp_to_us(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_debug_time_format.addItem(utils.timestamp_to_iso(self.example_timestamp) + ' (ISO 8601)', 'iso') self.combo_debug_time_format.addItem(utils.timestamp_to_unix(self.example_timestamp) + ' (Unix)', 'unix') self.combo_log_level.addItem('Debug', 'debug') self.combo_log_level.addItem('Info', 'info') self.combo_log_level.addItem('Warning', 'warning') self.combo_log_level.addItem('Error', 'error') self.combo_log_level.addItem('Critical', 'critical') self.combo_log_level.setCurrentIndex(0) # debug self.combo_debug_level.addItem('Debug', logging.DEBUG) self.combo_debug_level.addItem('Info', logging.INFO) self.combo_debug_level.addItem('Warning', logging.WARNING) self.combo_debug_level.addItem('Error', logging.ERROR) self.combo_debug_level.addItem('Critical', logging.CRITICAL) self.combo_debug_level.setCurrentIndex(1) # info for host_info in host_infos: self.combo_host.addItem(host_info.host, (host_info.port, host_info.use_authentication, host_info.secret)) self._host_index_changed(0) self.update_ui_state() def update_ui_state(self): index = self.combo_data_time_format.currentIndex() if index > 0: time_format = self.combo_data_time_format.itemData(index) else: time_format = 'unknown' data_to_csv_file = self.check_data_to_csv_file.isChecked() debug_to_log_file = self.check_debug_to_log_file.isChecked() self.edit_data_time_format_strftime.setVisible(time_format == 'strftime') self.label_data_time_format_strftime_help.setVisible(time_format == 'strftime') self.label_csv_file_name.setVisible(data_to_csv_file) self.edit_csv_file_name.setVisible(data_to_csv_file) self.btn_browse_csv_file_name.setVisible(data_to_csv_file) self.label_log_file_name.setVisible(debug_to_log_file) self.edit_log_file_name.setVisible(debug_to_log_file) self.btn_browse_log_file_name.setVisible(debug_to_log_file) self.label_log_level.setVisible(debug_to_log_file) self.combo_log_level.setVisible(debug_to_log_file) def signal_initialization(self): """ Init of all important Signals and connections. """ # Buttons self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked) self.btn_save_config.clicked.connect(self.btn_save_config_clicked) self.btn_load_config.clicked.connect(self.btn_load_config_clicked) self.combo_data_time_format.currentIndexChanged.connect(self.update_ui_state) self.edit_data_time_format_strftime.textChanged.connect(self.edit_data_time_format_strftime_changed) self.check_data_to_csv_file.stateChanged.connect(self.update_ui_state) self.check_debug_to_log_file.stateChanged.connect(self.update_ui_state) self.btn_browse_csv_file_name.clicked.connect(self.btn_browse_csv_file_name_clicked) self.btn_browse_log_file_name.clicked.connect(self.btn_browse_log_file_name_clicked) self.btn_clear_debug.clicked.connect(self.btn_clear_debug_clicked) self.combo_debug_level.currentIndexChanged.connect(self.combo_debug_level_changed) self.btn_add_device.clicked.connect(self.btn_add_device_clicked) self.btn_remove_device.clicked.connect(self.btn_remove_device_clicked) self.btn_remove_all_devices.clicked.connect(self.btn_remove_all_devices_clicked) self.tab_widget.currentChanged.connect(self.tab_reset_warning) self.btn_clear_data.clicked.connect(self.btn_clear_data_clicked) self._gui_logger.newEventMessage.connect(self.add_debug_message) self._gui_logger.newEventTabHighlight.connect(self.highlight_debug_tab) self.combo_host.currentIndexChanged.connect(self._host_index_changed) def btn_start_logging_clicked(self): """ Start/Stop of the logging process """ if (self.data_logger_thread is not None) and (not self.data_logger_thread.stopped): self.btn_start_logging.clicked.disconnect() self.data_logger_thread.stop() self._reset_stop() elif self.data_logger_thread is None: from brickv.data_logger import main self._gui_job = GuiDataJob(name="GuiData-Writer") self._gui_job.signalNewData.connect(self.table_add_row) self.data_logger_thread = main.main(None, GuiConfigHandler.create_config(self), self._gui_job, None, None, None) if self.data_logger_thread is not None: self.btn_start_logging.setText("Stop Logging") self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/stop-icon.png'))) self.tab_devices.setEnabled(False) self.tab_setup.setEnabled(False) self.tab_widget.setCurrentIndex(self.tab_widget.indexOf(self.tab_data)) self.tab_reset_warning() def _reset_stop(self): self.tab_devices.setEnabled(True) self.tab_setup.setEnabled(True) self.btn_start_logging.setText("Start Logging") self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/start-icon.png'))) self._gui_job.signalNewData.disconnect(self.table_add_row) self.data_logger_thread = None self._gui_job = None self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked) def authentication_state_changed(self, state): visible = state == Qt.Checked self.label_secret.setVisible(visible) self.edit_secret.setVisible(visible) self.check_secret_show.setVisible(visible) def secret_show_state_changed(self, state): if state == Qt.Checked: self.edit_secret.setEchoMode(QLineEdit.Normal) else: self.edit_secret.setEchoMode(QLineEdit.Password) def edit_data_time_format_strftime_changed(self): index = self.combo_data_time_format.findData('strftime') if index < 0: return t = utils.timestamp_to_strftime(self.example_timestamp, self.edit_data_time_format_strftime.text()) if len(t) == 0: t = '<empty>' self.combo_data_time_format.setItemText(index, (t + ' (strftime)')) if self.edit_data_time_format_strftime.isVisible(): self.edit_data_time_format_strftime.setFocus() def btn_save_config_clicked(self): filename = get_save_file_name(self, 'Save Config', get_home_path(), 'JSON Files (*.json)') if len(filename) == 0: return if not filename.lower().endswith('.json'): filename += '.json' config = GuiConfigHandler.create_config(self) if not save_config(config, filename): QMessageBox.warning(self, 'Save Config', 'Could not save config to file! See Debug tab for details.', QMessageBox.Ok) def btn_load_config_clicked(self): filename = get_open_file_name(self, 'Load Config', get_home_path(), 'JSON Files (*.json)') if len(filename) == 0: return config = load_and_validate_config(filename) if config == None: QMessageBox.warning(self, 'Load Config', 'Could not load config from file! See Debug tab for details.', QMessageBox.Ok) return self.update_setup_tab(config) self.update_devices_tab(config) def btn_browse_csv_file_name_clicked(self): if len(self.edit_csv_file_name.text()) > 0: last_dir = os.path.dirname(os.path.realpath(self.edit_csv_file_name.text())) else: last_dir = get_home_path() filename = get_save_file_name(self, 'Choose CSV File', last_dir, "CSV Files (*.csv)") if len(filename) > 0: if not filename.lower().endswith('.csv'): filename += '.csv' self.edit_csv_file_name.setText(filename) def btn_browse_log_file_name_clicked(self): if len(self.edit_log_file_name.text()) > 0: last_dir = os.path.dirname(os.path.realpath(self.edit_log_file_name.text())) else: last_dir = get_home_path() filename = get_save_file_name(self, 'Choose Log File', last_dir, "Log Files (*.log)") if len(filename) > 0: if not filename.lower().endswith('.log'): filename += '.log' self.edit_log_file_name.setText(filename) def btn_add_device_clicked(self): """ Opens the DeviceDialog in Add-Mode. """ if self.device_dialog is None: self.device_dialog = DeviceDialog(self) self.device_dialog.btn_refresh_clicked() self.device_dialog.show() def btn_remove_device_clicked(self): selection = self.tree_devices.selectionModel().selectedIndexes() while len(selection) > 0: index = selection[0] while index.parent() != self.model_devices.invisibleRootItem().index(): index = index.parent() self.model_devices.removeRows(index.row(), 1) # get new selection, because row removal might invalid indices selection = self.tree_devices.selectionModel().selectedIndexes() def btn_remove_all_devices_clicked(self): self.model_devices.removeRows(0, self.model_devices.rowCount()) def btn_clear_data_clicked(self): self.model_data.removeRows(0, self.model_data.rowCount()) def tab_reset_warning(self): """ Resets the Warning @ the debug tab. """ if not self.tab_debug_warning or self.tab_widget.currentIndex() != self.tab_widget.indexOf(self.tab_debug): return self.tab_debug_warning = False self.tab_set(self.tab_widget.indexOf(self.tab_debug), self.palette().color(QPalette.WindowText), None) def combo_debug_level_changed(self): """ Changes the log level dynamically. """ self._gui_logger.level = self.combo_debug_level.itemData(self.combo_debug_level.currentIndex()) def tab_set(self, tab_index, color, icon=None): """ Sets the font Color and an icon, if given, at a specific tab. """ self.tab_widget.tabBar().setTabTextColor(tab_index, color) if icon is not None: self.tab_widget.setTabIcon(tab_index, QIcon(icon)) else: self.tab_widget.setTabIcon(tab_index, QIcon()) def _host_index_changed(self, i): if self.last_host_index >= 0: self.combo_host.setItemData(self.last_host_index, (self.spin_port.value(), self.check_authentication.isChecked(), self.edit_secret.text())) self.last_host_index = i if i < 0: return host_info = self.combo_host.itemData(i) self.spin_port.setValue(host_info[0]) self.check_authentication.setChecked(host_info[1]) self.edit_secret.setText(host_info[2]) def update_setup_tab(self, config): EventLogger.debug('Updating setup tab from config') name = config['hosts']['default']['name'] port = config['hosts']['default']['port'] secret = config['hosts']['default']['secret'] i = self.combo_host.findText(name) if i >= 0: self.combo_host.setCurrentIndex(i) else: self.combo_host.insertItem(0, name, (port, secret != None, secret)) self.combo_host.setCurrentIndex(0) self.spin_port.setValue(port) self.check_authentication.setChecked(secret != None) self.edit_secret.setText(secret if secret != None else '') self.combo_data_time_format.setCurrentIndex(max(self.combo_data_time_format.findData(config['data']['time_format']), 0)) self.edit_data_time_format_strftime.setText(config['data']['time_format_strftime']) self.check_data_to_csv_file.setChecked(config['data']['csv']['enabled']) self.edit_csv_file_name.setText(config['data']['csv']['file_name']) self.combo_debug_time_format.setCurrentIndex(max(self.combo_debug_time_format.findData(config['debug']['time_format']), 0)) self.check_debug_to_log_file.setChecked(config['debug']['log']['enabled']) self.edit_log_file_name.setText(config['debug']['log']['file_name']) self.combo_log_level.setCurrentIndex(max(self.combo_debug_time_format.findData(config['debug']['log']['level']), 0)) def update_devices_tab(self, config): EventLogger.debug('Updating devices tab from config') self.model_devices.removeRows(0, self.model_data.rowCount()) for device in config['devices']: self.add_device_to_tree(device) def add_device_to_tree(self, device): # check if device is already added if len(device['uid']) > 0: for row in range(self.model_devices.rowCount()): existing_name = self.model_devices.item(row, 0).text() exisitng_uid = self.tree_devices.indexWidget(self.model_devices.item(row, 1).index()).text() if device['name'] == existing_name and device['uid'] == exisitng_uid: EventLogger.info('Ignoring duplicate device "{0}" with UID "{1}"' .format(device['name'], device['uid'])) return # add device name_item = QStandardItem(device['name']) uid_item = QStandardItem('') self.model_devices.appendRow([name_item, uid_item]) edit_uid = QLineEdit() edit_uid.setPlaceholderText('Enter UID') edit_uid.setValidator(QRegExpValidator(QRegExp('^[{0}]{{1,6}}$'.format(BASE58)))) # FIXME: use stricter logic edit_uid.setText(device['uid']) self.tree_devices.setIndexWidget(uid_item.index(), edit_uid) value_specs = device_specs[device['name']]['values'] parent_item = QStandardItem('Values') name_item.appendRow([parent_item, QStandardItem('')]) self.tree_devices.expand(parent_item.index()) # add values for value_spec in value_specs: value_name_item = QStandardItem(value_spec['name']) value_interval_item = QStandardItem('') parent_item.appendRow([value_name_item, value_interval_item]) spinbox_interval = IntervalWidget() spinbox_interval.set_interval(device['values'][value_spec['name']]['interval']) self.tree_devices.setIndexWidget(value_interval_item.index(), spinbox_interval) if value_spec['subvalues'] != None: for subvalue_name in value_spec['subvalues']: subvalue_name_item = QStandardItem(subvalue_name) subvalue_check_item = QStandardItem('') value_name_item.appendRow([subvalue_name_item, subvalue_check_item]) check_subvalue = QCheckBox() check_subvalue.setChecked(device['values'][value_spec['name']]['subvalues'][subvalue_name]) self.tree_devices.setIndexWidget(subvalue_check_item.index(), check_subvalue) self.tree_devices.expand(name_item.index()) # add options option_specs = device_specs[device['name']]['options'] if option_specs != None: parent_item = QStandardItem('Options') name_item.appendRow([parent_item, QStandardItem('')]) for option_spec in option_specs: option_name_item = QStandardItem(option_spec['name']) option_widget_item = QStandardItem('') parent_item.appendRow([option_name_item, option_widget_item]) if option_spec['type'] == 'choice': widget_option_value = QComboBox() for option_value_spec in option_spec['values']: widget_option_value.addItem(option_value_spec[0], option_value_spec[1]) widget_option_value.setCurrentIndex(widget_option_value.findText(device['options'][option_spec['name']]['value'])) elif option_spec['type'] == 'int': widget_option_value = QSpinBox() widget_option_value.setRange(option_spec['minimum'], option_spec['maximum']) widget_option_value.setSuffix(option_spec['suffix']) widget_option_value.setValue(device['options'][option_spec['name']]['value']) elif option_spec['type'] == 'bool': widget_option_value = QCheckBox() widget_option_value.setChecked(device['options'][option_spec['name']]['value']) self.tree_devices.setIndexWidget(option_widget_item.index(), widget_option_value) def add_debug_message(self, message): self.text_debug.append(message) while self.text_debug.document().blockCount() > 1000: cursor = QTextCursor(self.text_debug.document().begin()) cursor.select(QTextCursor.BlockUnderCursor) cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor) cursor.removeSelectedText() if self.checkbox_debug_auto_scroll.isChecked(): self.text_debug.verticalScrollBar().setValue(self.text_debug.verticalScrollBar().maximum()) def btn_clear_debug_clicked(self): self.text_debug.clear() def highlight_debug_tab(self): """ SIGNAL function: Highlight the debug tab when an error occurs. """ if not self.tab_debug_warning and self.tab_widget.currentIndex() != self.tab_widget.indexOf(self.tab_debug): self.tab_debug_warning = True self.tab_set(self.tab_widget.indexOf(self.tab_debug), QColor(255, 0, 0), get_resources_path("warning-icon-16.png")) def table_add_row(self, csv_data): """ SIGNAL function: Adds new CSV Data into the Table. """ rows = self.model_data.rowCount() while rows >= 1000: self.model_data.removeRow(0) rows = self.model_data.rowCount() row_number = None if rows > 0: try: row_number = int(self.model_data.headerData(rows - 1, Qt.Vertical)) except ValueError: pass self.model_data.appendRow([QStandardItem(csv_data.timestamp), QStandardItem(csv_data.name), QStandardItem(csv_data.uid), QStandardItem(csv_data.var_name), QStandardItem(str(csv_data.raw_data)), QStandardItem(csv_data.var_unit)]) if row_number != None: self.model_data.setHeaderData(rows, Qt.Vertical, str(row_number + 1)) if self.checkbox_data_auto_scroll.isChecked(): self.table_data.scrollToBottom()