def update(self, structure): for n, v in structure.items(): items = self.findItems(n, Qt.MatchExactly) if len(items) == 0: item = QTreeWidgetItem([n, '{} points'.format(v['nValues'])]) for m, w in v['axes'].items(): childItem = QTreeWidgetItem( [m, '{} points'.format(w['nValues'])]) childItem.setDisabled(True) item.addChild(childItem) self.addTopLevelItem(item) item.setExpanded(True) else: item = items[0] item.setText(1, '{} points'.format(v['nValues'])) for m, w in v['axes'].items(): for k in range(item.childCount()): if item.child(k).text(0) == m: item.child(k).setText( 1, '{} points'.format(w['nValues'])) curSelection = self.selectedItems() if len(curSelection) == 0: item = self.topLevelItem(0) if item: item.setSelected(True)
def on_tree_item_expanded(self, item: QTreeWidgetItem): """ 展开时从父LE中载入数据 :param item: :return: """ logging.info("on_tree_item_expanded") try: if item.text(0) == "File Version": logging.info("File Version->expanded") for index in range(item.childCount()): child = item.child(index) v = self.file_version_le.text() le: QLineEdit = self.tree.itemWidget(child, 1) le.setText(str(eval(v)[index])) elif item.text(0) == "Product Version": logging.info("Product Version->expanded") for index in range(item.childCount()): child = item.child(index) v = self.product_version_le.text() le: QLineEdit = self.tree.itemWidget(child, 1) le.setText(str(eval(v)[index])) else: logging.info("not concern item->expanded") except Exception as e: logging.error(e)
def __init__(self, model, view): self.model = model self.view = view tw = view.tw tw.setHeaderLabels(['MyTest']) tctx = QTreeWidgetItem(["CTX"]) tvdx = QTreeWidgetItem(["ROIs"]) tdos = QTreeWidgetItem(["DOSs"]) tlet = QTreeWidgetItem(["LETs"]) tctx.setCheckState(0, Qt.Checked) # tctx.addChild(QTreeWidgetItem([model.ctx])) for i, item in enumerate(model.vdx): # child = QTreeWidgetItem(parent) tvdx.addChild(QTreeWidgetItem([item])) child = tvdx.child(i) child.setCheckState(0, Qt.Checked) for i, item in enumerate(model.dos): tdos.addChild(QTreeWidgetItem([item])) child = tdos.child(i) child.setCheckState(0, Qt.Checked) for item in model.let: tlet.addChild(QTreeWidgetItem([item])) tw.addTopLevelItem(tctx) tw.addTopLevelItem(tvdx) tw.addTopLevelItem(tdos) tw.addTopLevelItem(tlet) tctx.setExpanded( True) # should be set, after it was added to the TreeWidget tvdx.setExpanded(True) tdos.setExpanded(True) tlet.setExpanded(True) self.setup_callbacks(view) self.tvdx = tvdx self.popup_menu_ctx = self.create_popup_menu_ctx() self.popup_menu_vdx = self.create_popup_menu_vdx()
def getSubItemFromSubTask(self, item: QTreeWidgetItem, sub_task: PlotSubTask): for i in range(item.childCount()): sub_item = item.child(i) if sub_item.data(0, Qt.UserRole) == sub_task: return sub_item return None
def on_point_toggle(self, item: QtWidgets.QTreeWidgetItem, column: int) -> None: """ Callback for toggling point selection Adds/removes points to background removal queue Args: item (QtWidgets.QTreeWidgetItme): toggled widget item column (int): mandatory unused argument in signal """ if item.childCount() == 0: # a bit inefficient here (e.g dynamic programming could help) treepath = '' node = item while node is not None: treepath = '/' + node.text(0) + treepath node = node.parent() # remove prepended '/' treepath = treepath[1:] index = self.pointPlotSelect.findText(treepath) if index < 0 and item.checkState(0): self.pointPlotSelect.addItem(treepath) elif index >= 0 and not item.checkState(0): self.pointPlotSelect.removeItem(index) else: for child in [ item.child(index) for index in range(item.childCount()) ]: child.setCheckState(0, item.checkState(0))
def _update_checkboxes(self, item: QTreeWidgetItem, column: int): if column != 0: return new_check_state = item.checkState(0) self._set_check_state_to_tree(item, new_check_state) while True: item = item.parent() if item is None: break has_checked_children = False has_partially_checked_children = False has_unchecked_children = False for i in range(item.childCount()): state = item.child(i).checkState(0) if state == Qt.Checked: has_checked_children = True elif state == Qt.PartiallyChecked: has_partially_checked_children = True else: has_unchecked_children = True if not has_partially_checked_children and \ not has_unchecked_children: new_state = Qt.Checked elif has_checked_children or has_partially_checked_children: new_state = Qt.PartiallyChecked else: new_state = Qt.Unchecked item.setCheckState(0, new_state) self._update_selection_label()
def get_timestamp_from_child(self, child: QTreeWidgetItem): """ Returns the timestamp of a given tree widget item to identify specific items. Args: child: The item from which to get the timestamp """ return child.child(1).text(1)
def _update_checkboxes(self, item: QTreeWidgetItem, column: int): if column != 0: return new_check_state = item.checkState(0) self._set_check_state_to_tree(item, new_check_state) while True: item = item.parent() if item is None: break has_checked_children = False has_partially_checked_children = False has_unchecked_children = False for i in range(item.childCount()): state = item.child(i).checkState(0) if state == Qt.Checked: has_checked_children = True elif state == Qt.PartiallyChecked: has_partially_checked_children = True else: has_unchecked_children = True if not has_partially_checked_children and not has_unchecked_children: new_state = Qt.Checked elif has_checked_children or has_partially_checked_children: new_state = Qt.PartiallyChecked else: new_state = Qt.Unchecked item.setCheckState(0, new_state) self._update_selection_label()
def del_option(self, parent: QTreeWidgetItem, child: QTreeWidgetItem): self.blockSignals(True) parent.removeChild(child) selected_option = False for i in range(parent.childCount()): parent.child(i).setData(0, 35, i) if parent.child(i).checkState(0) == Qt.Checked: selected_option = True if parent.childCount() > 0 and not selected_option: parent.child(0).setCheckState(0, Qt.Checked) self.blockSignals(False) self.itemRemoved.emit(parent, parent.indexOfChild(child)) self.update_size()
def set_gray(self, item: QtWidgets.QTreeWidgetItem): """ 将item置为灰色,不用 setDisabled 的原因是会导致 currentItem() 失效 """ item.setForeground(0, QtCore.Qt.gray) data = item.data(0, QtCore.Qt.UserRole) if data is not None: item.setIcon(0, QtGui.QIcon(':/icon/not_connect_16.png')) for i in range(item.childCount()): self.set_gray(item.child(i))
def getTreeWidgetItemJsonData(treeWidgetItem: QTreeWidgetItem): """ 从TreeWidgetItem解析出json数据 :param treeWidgetItem: treeWidgetItem :return: json数据 """ text = treeWidgetItem.text(0) if text == "[]": jsonData = [] for i in range(0, treeWidgetItem.childCount()): res = WidgetUtil.getTreeWidgetItemJsonData( treeWidgetItem.child(i)) jsonData.append(res) print(jsonData) return jsonData elif text == "{}": jsonData = {} for i in range(0, treeWidgetItem.childCount()): child = treeWidgetItem.child(i) res = WidgetUtil.getTreeWidgetItemJsonData(child) print("root key: " + child.text(0) + " value: " + str(res)) jsonData = {**jsonData, **res} print(jsonData) return jsonData elif treeWidgetItem.data(0, Qt.UserRole): # 末端节点 dataType = treeWidgetItem.data(1, Qt.UserRole) print(DataTypeUtil.parseByType(text, dataType)) res = DataTypeUtil.parseByType(text, dataType) print("末端节点 -> %s dataType -> %d parse res -> %s" % (text, dataType, str(res))) return res else: jsonData = {} list = [] for i in range(0, treeWidgetItem.childCount()): child = treeWidgetItem.child(i) res = WidgetUtil.getTreeWidgetItemJsonData(child) list.append(res) if len(list) == 1: jsonData[text] = list[0] else: jsonData[text] = list print(jsonData) return jsonData
def recurse(parent_item: QTreeWidgetItem): for i in range(parent_item.childCount()): child = parent_item.child(i) grand_children = child.childCount() if grand_children > 0: recurse(child) else: if child.checkState(0) == Qt.Checked: checked_items.append(child)
def populate(self): model = self.model settings = model.settings item_store: ItemStore = settings[settings.P_ITEM_STORE] self.tree.clear() imgs.sig_image_load.connect(self.image_loaded) for k, v in item_store.store_items.items(): prices = v.prices if prices is not None: tli = QTreeWidgetItem( self.tree, [k, v.name, '', str(v.expires)]) self.tree.addTopLevelItem(tli) ret = self.load_gear_icon(k, tli) tli.setText(2, MONNIES_FORMAT.format(prices[0])) for i, p in enumerate(v.prices[1:]): twi = QTreeWidgetItem( ['', v.name, MONNIES_FORMAT.format(p), '']) tli.addChild(twi) lV = 0 if ret is not None: name, grade, itype = ret res_class_str = class_enum_to_str(itype) res_grade_str = grade_enum_to_str(grade) gt_str = class_grade_to_gt_str(res_class_str, res_grade_str, name) gear_type = gear_types[gt_str] for idx, lvl in gear_type.idx_lvl_map.items(): if idx > lV: lV = idx lvl_e_t = gear_type.bin_mp(idx) child = tli.child(lvl_e_t - 1) if child is not None: lvl = gear_type.idx_lvl_map[idx - 1] prev_text = child.text(0) if prev_text.strip() == '': text = str(lvl) else: text = '{}, {}'.format(prev_text, lvl) child.setText(0, text) child = tli.child(tli.childCount() - 1) child.setText(0, gear_type.idx_lvl_map[lV])
def treelist_creatgrpitem(self, item_group): """Create group item.""" treelist = self.maintabwidget.tab_classify.treelist # Creat TopLevel Group tree_group = treelist.findItems(item_group[0], Qt.MatchFixedString, 0) if tree_group: group = tree_group[0] else: group = QTreeWidgetItem(treelist) group.setText(0, item_group[0]) # Creat SubGroup subgroup = None childcount = group.childCount() for i in range(childcount): if item_group[1] == group.child(i).text(0): subgroup = group.child(i) break if not subgroup: subgroup = QTreeWidgetItem(group) subgroup.setText(0, item_group[1]) return subgroup
def tree_elem_generator(tree_elem: ElementTree.Element, tree_item: QTreeWidgetItem): for i in range(tree_item.childCount()): child_item = tree_item.child(i) attrib = dict() for i in range(1, self.columnNum): if child_item.text(i): attrib[self.header_labels_list[i]] = child_item.text(i) child_elem = ElementTree.SubElement(tree_elem, child_item.text(0), attrib=attrib) tree_elem_generator(child_elem, child_item)
def del_option(self, parent: QTreeWidgetItem, child: QTreeWidgetItem): """ Called to remove option from parent. """ self.blockSignals(True) parent.removeChild(child) selected_option = False for i in range(parent.childCount()): parent.child(i).setData(0, INDEX_SLOT, i) if parent.child(i).checkState(0) == Qt.Checked: selected_option = True if parent.childCount() > 0 and not selected_option: parent.child(0).setCheckState(0, Qt.Checked) # Deselects if no options left if not parent.childCount(): parent.setCheckState(0, Qt.Unchecked) self.blockSignals(False) self.update_size()
def _select_children(self, top_item: QtWidgets.QTreeWidgetItem, value: bool): """Recursive select children from parent.""" pi.logger.debug("RevPiFiles._select_children") for i in range(top_item.childCount()): item = top_item.child(i) if item.type() == NodeType.DIR: item.setSelected(value) self._select_children(item, value) elif item.type() == NodeType.FILE: item.setSelected(value)
def populate(self): model = self.model settings = model.settings item_store: ItemStore = settings[settings.P_ITEM_STORE] self.tree.clear() imgs.sig_image_load.connect(self.image_loaded) for k, v in item_store.store_items.items(): prices = v.prices if prices is not None: tli = QTreeWidgetItem( self.tree, [k, v.name, '', str(v.expires)]) self.tree.addTopLevelItem(tli) gd = self.load_gear_icon(k, tli) tli.setText(2, MONNIES_FORMAT.format(prices[0])) for i, p in enumerate(v.prices[1:]): twi = QTreeWidgetItem( ['', v.name, MONNIES_FORMAT.format(p), '']) tli.addChild(twi) if gd is not None: # If ret is none this is a gear item not a material gear_type = gd.get_gear_type() for idx, lvl in gear_type.idx_lvl_map.items(): if idx == 0: continue lvl_e_t = gear_type.bin_mp(idx) child = tli.child(lvl_e_t - 1) if child is not None: lvl = gear_type.idx_lvl_map[ idx - 1] # MP cost of PRI is, target DUO's cost prev_text = child.text(0) if prev_text.strip() == '': text = str(lvl) else: text = '{}, {}'.format(prev_text, lvl) child.setText(0, text) child = tli.child(tli.childCount() - 1) child.setText( 0, gear_type.idx_lvl_map[len(gear_type.map) - 1])
def add(self): # gets selected item and makes a child parent = self.ui.treeWidget.currentItem() child = QTreeWidgetItem() # adds to tree, expands, makes the child editable, and adds a checkbox parent.addChild(child) parent.setExpanded(True) if child.child(0) is None: child.setFlags(child.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsEditable | Qt.ItemIsEnabled) child.setCheckState(0, Qt.Unchecked)
def findSubItemByName( self, name: str, root: QtWidgets.QTreeWidgetItem) -> QtWidgets.QTreeWidgetItem: for i in range(root.childCount()): item: QtWidgets.QTreeWidgetItem = root.child(i) if item.type() == 0: rec = self.findSubItemByName(name, item) if rec is not None: return rec else: if item.text(0) == name: return item return None
def update_index(master: QTreeWidgetItem) -> None: """ 更新子节点 索引信息 :return: """ # QTreeWidgetItem(self.group_tree).text(0) # 获取子节点个数 count = master.childCount() # 根据索引获取子节点 for index in range(count): child = master.child(index) # 在线主机 (0) child.setText(0, str(index + 1))
def set_default(self, item: QtWidgets.QTreeWidgetItem): """ 将 item 恢复为默认颜色 """ style = self.parent().ui_config.get('main_window', 'style', fallback='normal_style') data = item.data(0, QtCore.Qt.UserRole) if data is not None: item.setIcon(0, self.icons[0]) if style == "dark_style": item.setForeground(0, QtCore.Qt.white) else: item.setForeground(0, QtCore.Qt.black) for i in range(item.childCount()): self.set_default(item.child(i))
def item_removed(self, item: QTreeWidgetItem, index): """ Parent who had child removed. Updates settings and numbering of settings_data 35 TODO: Apply named constant variables to data entries instead of numbers. Constants defined in parameter_tree.py """ def get_index(data, option_name): try: return data[parameter_name]['options'].index(option_name) except KeyError: # TODO: Logging # print(f'Profile {profile} has no parameter {parameter_name}, skipping') return None except ValueError: # print(f'Profile {profile} does not have the option {option_name}, skipping') return None parameter_name = item.data(0, DISPLAY_NAME_SLOT) option_name = self.settings.parameters[parameter_name]['options'][index] has_option = [] for profile, data in self.settings.profiles_data.items(): new_index = get_index(data, option_name) if new_index is not None and data[parameter_name]['active option'] == new_index: has_option.append(profile) if has_option: self.alert_message('Error', f'One or more profiles has this as the selected option:', f'\t{", ".join(has_option)}') return item.treeWidget().del_option(item, item.child(index)) self.settings.remove_parameter_option(item.data(0, DISPLAY_NAME_SLOT), index) # Deletes from profiles for profile, data in self.settings.profiles_data.items(): new_index = get_index(data, option_name) if new_index is None: continue del data[parameter_name]['options'][new_index] new_index = data[parameter_name]['active option'] new_index -= 1 if new_index > 0 else 0 data[parameter_name]['active option'] = new_index self.file_handler.save_profiles(self.settings.profiles_data) self.file_handler.save_settings(self.settings.settings_data)
def parameter_updater(self, item: QTreeWidgetItem, col=None, save=True): """Handles updating the options for a parameter.""" if 'Custom' != self.tab1.profile_dropdown.currentText(): self.tab1.profile_dropdown.addItem('Custom') self.tab1.profile_dropdown.setCurrentText('Custom') self.settings.user_options['current_profile'] = '' if item.data(0, LEVEL_SLOT) == 0: if item.data(0, DATA_SLOT) in self.settings.need_parameters: result = self.alert_message('Warning!', 'This parameter needs an option!', 'There are no options!\n' 'Would you make one?', True) if result == QMessageBox.Yes: success = self.add_option(item) if not success: item.treeWidget().blockSignals(True) item.setCheckState(0, Qt.Unchecked) item.treeWidget().blockSignals(False) item.treeWidget().check_dependency(item) else: item.treeWidget().blockSignals(True) item.setCheckState(0, Qt.Unchecked) item.treeWidget().blockSignals(False) item.treeWidget().check_dependency(item) if item.checkState(0) == Qt.Checked: self.settings[item.data(0, DATA_SLOT)]['state'] = True if item.data(0, DATA_SLOT) == 'Download location': for i in range(item.childCount()): self.parameter_updater(item.child(i), save=False) else: self.settings[item.data(0, DATA_SLOT)]['state'] = False if item.data(0, DATA_SLOT) == 'Download location': self.tab2.download_lineedit.setText(path_shortener(self.local_dl_path)) self.tab2.download_lineedit.setToolTip(self.local_dl_path) elif item.data(0, LEVEL_SLOT) == 1: # Settings['Settings'][Name of setting]['active option']] = index of child self.settings[item.parent().data(0, DATA_SLOT)]['active option'] = item.data(0, INDEX_SLOT) if item.parent().data(0, DATA_SLOT) == 'Download location': if item.checkState(0) == Qt.Checked: self.tab2.download_lineedit.setText(item.data(0, DISPLAY_NAME_SLOT)) self.tab2.download_lineedit.setToolTip(item.data(0, DATA_SLOT)) if save: self.file_handler.save_settings(self.settings.settings_data)
def recursive_tree_item(self, item: QTreeWidgetItem, depth=0): # Root 아이템 부터 돌면서 아이템 내용을 Dict 형태로 생성 for child in [item.child(i) for i in range(item.childCount())]: columns = [child.data(i, Qt.DisplayRole) for i in range(child.columnCount())] # 위젯 및 체크박스 사용 여부 검사 buf = '' w = child.treeWidget().itemWidget(child, 1) check = (child.data(1, Qt.CheckStateRole)) if w: buf = w.get_value() if check: buf = ["checked", "---", "unchecked"][child.checkState(check)] qDebug("{} {}".format("\t" * depth, str(columns) + ' ' + str(buf))) if child.childCount(): self.recursive_tree_item(child, depth + 1)
def set_choices( self, item: QTreeWidgetItem = None, choices: List[TriggerChoice] = None ): if not item: item = self.root choices = profile.trigger_choices for choice in choices: for i in range(item.childCount()): child = item.child(i) if isinstance(child, TriggerGroup): if child.container.name == choice.name and choice.type_ == "group": child.setCheckState( 0, Qt.Checked if choice.enabled else Qt.Unchecked ) if choice.group: self.set_choices(child, choice.group) else: if child.trigger.name == choice.name and choice.type_ == "trigger": child.setCheckState( 0, Qt.Checked if choice.enabled else Qt.Unchecked )
def get_choices(self, item: QTreeWidgetItem = None): choices = [] if not item: item = self.root for i in range(item.childCount()): child = item.child(i) if isinstance(child, TriggerGroup): choices.append( TriggerChoice( name=child.container.name, enabled=True if child.checkState(0) else False, group=self.get_choices(child), ) ) elif isinstance(child, TriggerItem): choices.append( TriggerChoice( name=child.trigger.name, enabled=True if child.checkState(0) else False, type_="trigger", ) ) return choices
def _filter_branch(self, search_terms: List[str], parent: QtWidgets.QTreeWidgetItem) -> int: visible_children = 0 for c in range(parent.childCount()): child = parent.child(c) item_type = child.data(0, self.ROLE_ITEM_TYPE) if item_type == self.ITEM_TYPE_TOOL: child_text = child.text(0).lower() child_help = child.toolTip(0).lower() visible_children += 1 item_hidden = False for term in search_terms: if term not in child_text and term not in child_help: item_hidden = True break child.setHidden(item_hidden) if item_hidden: visible_children -= 1 elif item_type == self.ITEM_TYPE_COLLECTION: visible_children += self._filter_branch(search_terms, child) else: raise NotImplementedError parent.setHidden(visible_children == 0) return visible_children
def _set_check_state_to_tree(self, item: QTreeWidgetItem, check_state: Qt.CheckState): for i in range(item.childCount()): child = item.child(i) child.setCheckState(0, check_state) self._set_check_state_to_tree(child, check_state)
class TreeController(object): """ Idea is that the tree is entirely controlled by modifying the main_model. After modification, update_tree() is called, which will populate accordingly. """ def __init__(self, model, view, ctrl): """ :param MyModel model: :param view: """ self.model = model self.view = view self.pctrl = ctrl.plot # this is only needed to trigger canvas update, if tree change. tw = view.treeWidget # QTreeWidgetItem placeholders, only the top level nodes. self.tctx = None self.tvdx = None self.tplans = None self.tdos = None self.tlet = None # These "articial" objects are made since they do not exist in pytrip.model self._doscol = DosCollection() self._letcol = LetCollection() self._plancol = PlanCollection() # setup the submenus: self.tmc = TreeMenuController(model, view, ctrl) # self, else it goes out of scope? # connect checkbox change state to callback tw.itemClicked.connect(self.on_checked_changed) def on_checked_changed(self, pos): """ If checkbox is changed in the TreeWidget, then then corresponding object is removed or added to the plot_model. """ logger.debug("on_checked_changed() {}".format(pos)) pm = self.model.plot obj = pos.data(0, Qt.UserRole) # state = pos.data(0, Qt.CheckStateRole) # tw = self.view.tw if pos.checkState(0) == Qt.Unchecked: if isinstance(obj, pt.CtxCube): logger.debug("set pm.ctx = None") pm.ctx = None if isinstance(obj, pt.Voi): logger.debug("remove Voi {}".format(obj.name)) if obj in pm.vois: pm.vois.remove(obj) else: logger.warning("Tried to remove Voi {} which is not in pm.vois.") if isinstance(obj, pte.Plan): logger.debug("remove Plan {}".format(obj.name)) if obj in pm.plans: pm.plans.remove(obj) else: logger.warning("Tried to remove Plan {} which is not in pm.plans.") # TODO: Field if isinstance(obj, pt.DosCube): logger.debug("set pm.dos = None") pm.dos = None if isinstance(obj, pt.LETCube): logger.debug("set pm.let = None") pm.let = None else: # select something and add it to model.plot logger.debug("{} isChecked(True)".format(pos)) if isinstance(obj, pt.CtxCube): pm.ctx = obj if isinstance(obj, pt.Voi): if obj not in pm.vois: pm.vois.append(obj) if isinstance(obj, pt.DosCube): pm.dos = obj if isinstance(obj, pt.LETCube): pm.let = obj # trigger update plot after model was changed. self.pctrl.update_viewcanvas() for i, item in enumerate(pm.vois): logger.debug("pm.vois {}:{}".format(i, item.name)) def update_tree(self): """ Syncs the tree with the main_model, adding and removing items accordingly. """ logger.debug("update_tree()") self._model_sync_add_items() self._model_sync_remove_items() def _model_sync_add_items(self): """ Syncs the tree with the main_model, adding and removing items accordingly. TODO: this can probably be programmed more elegantly. """ self._add_ctx() self._add_vdxvoi() self._add_plans() self._add_dos() self._add_let() def _add_ctx(self): """ """ model = self.model tw = self.view.treeWidget # CTX data if model.ctx and not self._in_tree(model.ctx): # Add CTX to tree widget. tw.setHeaderLabels(["'{}'".format(model.ctx.basename)]) # TODO:patient name self.tctx = QTreeWidgetItem([model.ctx.basename]) self.tctx.setData(0, Qt.UserRole, model.ctx) tw.addTopLevelItem(self.tctx) self.tctx.setCheckState(0, Qt.Checked) def _add_vdxvoi(self): """ """ model = self.model tw = self.view.treeWidget # VDX data if model.vdx and not self._in_tree(model.vdx): self.tvdx = QTreeWidgetItem(["ROIs: " + model.vdx.basename]) self.tvdx.setData(0, Qt.UserRole, model.vdx) tw.addTopLevelItem(self.tvdx) self.tvdx.setExpanded(True) # VOIs if model.vdx and model.vdx.vois: vois = model.vdx.vois for i, voi in enumerate(vois): # Add only Vois which are not in the tree. if not self._in_tree(voi): self.tvdx.addChild(QTreeWidgetItem([voi.name])) child = self.tvdx.child(i) child.setData(0, Qt.UserRole, voi) child.setCheckState(0, Qt.Checked) def _add_plans(self): """ """ model = self.model tw = self.view.treeWidget # Plans node: if model.plans and not self.tplans: self.tplans = QTreeWidgetItem(["Plans:"]) self.tplans.setData(0, Qt.UserRole, self._plancol) tw.addTopLevelItem(self.tplans) self.tplans.setExpanded(True) # Plans has one child for each plan. if model.plans: for i, plan in enumerate(model.plans): # Add only plans, which are not already in the tree if not self._in_tree(plan): self.tplans.addChild(QTreeWidgetItem([plan.basename])) child = self.tplans.child(i) child.setData(0, Qt.UserRole, plan) child.setCheckState(0, Qt.Checked) def _add_dos(self): """ """ model = self.model tw = self.view.treeWidget # Add the top level DOS node: if model.dos and not self.tdos: self.tdos = QTreeWidgetItem(["Dose Cubes"]) self.tdos.setData(0, Qt.UserRole, self._doscol) tw.addTopLevelItem(self.tdos) self.tdos.setExpanded(True) # Each DosCube will be treated as a child to the top level DOS node. if model.dos: for i, dos in enumerate(model.dos): if not self._in_tree(dos): self.tdos.addChild(QTreeWidgetItem([dos.basename])) child = self.tdos.child(i) child.setData(0, Qt.UserRole, dos) child.setCheckState(0, Qt.Checked) def _add_let(self): """ """ model = self.model tw = self.view.treeWidget # Add the top level LET node: if model.let and not self.tlet: self.tlet = QTreeWidgetItem(["LET Cubes"]) self.tlet.setData(0, Qt.UserRole, self._letcol) tw.addTopLevelItem(self.tlet) self.tlet.setExpanded(True) # Each LETCube will be treated as a child to the top level DOS node. if model.let: for i, let in enumerate(model.let): if not self._in_tree(let): self.tlet.addChild(QTreeWidgetItem([let.basename])) child = self.tlet.child(i) child.setData(0, Qt.UserRole, let) child.setCheckState(0, Qt.Checked) def _model_sync_remove_items(self): """ Sync TreeWidget with data model. If items are found in TreeWidget, which are not found in data model, the item will be removed from TreeWidget. """ tw = self.view.treeWidget lo = self._flat_model() root = tw.invisibleRootItem() count = root.childCount() # Check if TreeWidget item data object is found in model. # if not, remove it from TreeWidget. for i in range(count): item = root.child(i) if item: _obj = item.data(0, Qt.UserRole) if _obj not in lo: (item.parent() or root).removeChild(item) count2 = item.childCount() for j in range(count2): item2 = item.child(j) if item2: _obj = item2.data(0, Qt.UserRole) if _obj not in lo: (item2.parent() or root).removeChild(item) def _flat_model(self): """ Produces a searchable and flat array of model data which should be displayed in the TreeWidget. This array will be used for syncing the treeWidget items with the model items. """ model = self.model # Check for items to be removed. # First lets make a flat list of all pytrip objects in the model (called "lo"): lo = [model.ctx, model.vdx] if model.vdx: if model.vdx.vois: lo += model.vdx.vois # extend the list with a list of voi objects if model.dos: lo += model.dos if model.let: lo += model.let if model.plans: lo += model.plans for plan in model.plans: if plan.fields: lo += plan.fields # TODO: this part needs some rework. # The top level nodes: plans, dos and let # should not be removed, if they hold data. They do not have a class, tough # Therefore this little hack for now: if model.dos: lo += [self._doscol] if model.let: lo += [self._letcol] if model.plans: lo += [self._plancol] return lo def _in_tree(self, obj): """ Crawls the entire treewidget, and search for the object. Returns corresponding QTreeWidgetItem, if found, else None. :params PyTRiPobject obj: such as CtxCube, DosCube, VdxCube, Plan, ...etc """ tw = self.view.treeWidget root = tw.invisibleRootItem() count = root.childCount() for i in range(count): child = root.child(i) _obj = child.data(0, Qt.UserRole) if obj == _obj: return child count2 = child.childCount() for j in range(count2): child2 = child.child(j) _obj = child2.data(0, Qt.UserRole) if obj == _obj: return child2 return None
class ExtensionMenu(QDialog): def __init__(self, parent): QDialog.__init__(self, parent=parent) self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.categoryTW.header().setSectionResizeMode(0, QHeaderView.Fixed) self.ui.categoryTW.header().setSectionResizeMode(1, QHeaderView.Fixed) self.setFixedSize(self.size()) self.groupHead = None self.extensions = [] self.stat = {} self.user_defined = 0 self.extFile = 'extenstion_Category' self.read() self.ui.categoryTW.itemDoubleClicked.connect(self.modify) self.ui.addPB.clicked.connect(self.addRow) self.ui.removePB.clicked.connect(self.removeRow) self.ui.buttonBox.accepted.connect(self.write) self.ui.buttonBox.rejected.connect(self.reject) def addRow(self): editcategory = EditCategory(self, self.extensions) reply = editcategory.run() if reply != None: category, extensions = reply self.extensions += extensions.split(', ') treeitem = QTreeWidgetItem(self.groupHead, [category, extensions]) treeitem.setTextAlignment(0, Qt.AlignTop | Qt.AlignLeft) def modify(self, item, column): parent = item.parent() if parent == None or parent.text(0) == 'Primitive': return None editcategory = EditCategory(self, self.extensions, item.text(0), item.text(1)) previous = item.text(1).split(', ') reply = editcategory.run() if reply != None: category, extensions = reply if extensions != item.text(1): for p in previous: self.extensions.remove(p) self.extensions += extensions.split(', ') item.setText(0, category) item.setText(1, extensions) def read(self): stat = {} with open(self.extFile, 'r', encoding='utf-8') as fle: stat = json.load(fle) self.stat['Primitive'] = stat['Primitive'] self.user_defined = len(list(stat['User-defined'].keys())) for label, categorydict in stat.items(): self.groupHead = QTreeWidgetItem(self.ui.categoryTW, [label]) for category, extensionList in categorydict.items(): self.extensions += extensionList treeitem = QTreeWidgetItem( self.groupHead, [category, ", ".join(extensionList)]) treeitem.setTextAlignment(0, Qt.AlignTop | Qt.AlignLeft) self.ui.categoryTW.setItemDelegate(MyDelegate()) def removeRow(self): items = self.ui.categoryTW.selectedItems() flag = False for item in items: parent = item.parent() if parent == None or parent.text(0) == 'Primitive': flag = True else: parent.removeChild(item) if flag: QMessageBox.warning(self, "Alert", "You can't delete primitive category.") def write(self): if self.groupHead.childCount() == self.user_defined: self.reject() else: self.stat['User-defined'] = {} for index in range(self.groupHead.childCount()): category = self.groupHead.child(index).text(0) extensionList = self.groupHead.child(index).text(1).split(', ') self.stat['User-defined'][category] = extensionList with open(self.extFile, 'w', encoding='utf-8') as fle: json.dump(self.stat, fle, ensure_ascii=False, indent=4) QMessageBox.information(self, "Info", "Data saved.") self.accept()
class MainDialog(QDialog, Ui_MainDialog): """The main dialog of QGIS2Web plugin.""" items = {} def __init__(self, iface): QDialog.__init__(self) self.setupUi(self) self.iface = iface self.previewUrl = None self.layer_search_combo = None self.exporter_combo = None self.feedback = FeedbackDialog(self) self.feedback.setModal(True) stgs = QSettings() self.restoreGeometry(stgs.value("qgis2web/MainDialogGeometry", QByteArray(), type=QByteArray)) if stgs.value("qgis2web/previewOnStartup", Qt.Checked) == Qt.Checked: self.previewOnStartup.setCheckState(Qt.Checked) else: self.previewOnStartup.setCheckState(Qt.Unchecked) if (stgs.value("qgis2web/closeFeedbackOnSuccess", Qt.Checked) == Qt.Checked): self.closeFeedbackOnSuccess.setCheckState(Qt.Checked) else: self.closeFeedbackOnSuccess.setCheckState(Qt.Unchecked) self.previewFeatureLimit.setText( stgs.value("qgis2web/previewFeatureLimit", "1000")) self.paramsTreeOL.setSelectionMode(QAbstractItemView.SingleSelection) self.preview = None if webkit_available: widget = QWebView() self.preview = widget try: # if os.environ["TRAVIS"]: self.preview.setPage(WebPage()) except: print("Failed to set custom webpage") webview = self.preview.page() webview.setNetworkAccessManager(QgsNetworkAccessManager.instance()) self.preview.settings().setAttribute( QWebSettings.DeveloperExtrasEnabled, True) else: widget = QTextBrowser() widget.setText(self.tr('Preview is not available since QtWebKit ' 'dependency is missing on your system')) self.right_layout.insertWidget(0, widget) self.populateConfigParams(self) self.populate_layers_and_groups(self) self.populateLayerSearch() writer = WRITER_REGISTRY.createWriterFromProject() self.setStateToWriter(writer) self.exporter = EXPORTER_REGISTRY.createFromProject() self.exporter_combo.setCurrentIndex( self.exporter_combo.findText(self.exporter.name())) self.exporter_combo.currentIndexChanged.connect( self.exporterTypeChanged) self.toggleOptions() if webkit_available: if self.previewOnStartup.checkState() == Qt.Checked: self.autoUpdatePreview() self.buttonPreview.clicked.connect(self.previewMap) else: self.buttonPreview.setDisabled(True) self.layersTree.model().dataChanged.connect(self.populateLayerSearch) self.ol3.clicked.connect(self.changeFormat) self.leaflet.clicked.connect(self.changeFormat) self.buttonExport.clicked.connect(self.saveMap) helpText = os.path.join(os.path.dirname(os.path.realpath(__file__)), "helpFile.md") self.helpField.setSource(QUrl.fromLocalFile(helpText)) if webkit_available: self.devConsole = QWebInspector(self.verticalLayoutWidget_2) self.devConsole.setFixedHeight(0) self.devConsole.setObjectName("devConsole") self.devConsole.setPage(self.preview.page()) self.devConsole.hide() self.right_layout.insertWidget(1, self.devConsole) self.filter = devToggleFilter() self.filter.devToggle.connect(self.showHideDevConsole) self.installEventFilter(self.filter) self.setModal(False) @pyqtSlot(bool) def showHideDevConsole(self, visible): self.devConsole.setVisible(visible) def changeFormat(self): self.autoUpdatePreview() self.toggleOptions() def exporterTypeChanged(self): new_exporter_name = self.exporter_combo.currentText() try: self.exporter = [ e for e in EXPORTER_REGISTRY.getExporters() if e.name() == new_exporter_name][0]() except: pass def currentMapFormat(self): """ Returns the currently selected map writer type """ return self.getWriterFactory().type() def getWriterFactory(self): """ Returns a factory to create the currently selected map writer """ if self.mapFormat.checkedButton() == self.ol3: return OpenLayersWriter elif self.mapFormat.checkedButton() == self.leaflet: return LeafletWriter def createWriter(self): """ Creates a writer object reflecting the current settings in the dialog """ writer = self.getWriterFactory()() (writer.layers, writer.groups, writer.popup, writer.visible, writer.json, writer.cluster, writer.getFeatureInfo) = self.getLayersAndGroups() writer.params = self.getParameters() return writer def showErrorMessage(self, error): """ Shows an error message in the preview window """ html = "<html>" html += "<head></head>" html += "<style>body {font-family: sans-serif;}</style>" html += "<body><h1>Error</h1>" html += "<p>qgis2web produced an error:</p><code>" html += error html += "</code></body></html>" if self.preview: self.preview.setHtml(html) def showFeedbackMessage(self, title, message): """ Shows a feedback message in the preview window """ html = "<html>" html += "<head></head>" html += "<style>body {font-family: sans-serif;}</style>" html += "<body><h1>{}</h1>".format(title) html += "<p>{}</p>".format(message) html += "</body></html>" if self.preview: self.preview.setHtml(html) def toggleOptions(self): currentWriter = self.getWriterFactory() for param, value in specificParams.items(): treeParam = self.paramsTreeOL.findItems(param, (Qt.MatchExactly | Qt.MatchRecursive))[0] if currentWriter == OpenLayersWriter: if value == "OL3": treeParam.setDisabled(False) else: treeParam.setDisabled(True) else: if value == "OL3": treeParam.setDisabled(True) else: treeParam.setDisabled(False) for option, value in specificOptions.items(): treeOptions = self.layersTree.findItems(option, (Qt.MatchExactly | Qt.MatchRecursive)) for treeOption in treeOptions: if currentWriter == OpenLayersWriter: if value == "OL3": treeOption.setDisabled(False) else: treeOption.setDisabled(True) else: if value == "OL3": treeOption.setDisabled(True) else: treeOption.setDisabled(False) def createPreview(self): writer = self.createWriter() return writer.write(self.iface, dest_folder=utils.tempFolder()).index_file def shouldAutoPreview(self): """ Returns a tuple, with a bool for whether the preview should automatically be generated, and a string for explanations as to why the preview cannot be automatically generated """ writer = self.createWriter() total_features = 0 for layer in writer.layers: if isinstance(layer, QgsVectorLayer): total_features += layer.featureCount() if total_features > int(self.previewFeatureLimit.text()): # Too many features => too slow! return (False, self.tr('<p>A large number of features are ' 'present in the map. Generating the ' 'preview may take some time.</p>' '<p>Click Update Preview to generate the ' 'preview anyway.</p>')) return (True, None) def autoUpdatePreview(self): """ Triggered when a preview will be automatically generated, i.e. not as a result of the user manually clicking the Update Preview button. """ (auto_preview, message) = self.shouldAutoPreview() if not auto_preview: self.showFeedbackMessage(self.tr('Preview Map'), message) else: self.previewMap() def previewMap(self): preview_file = self.createPreview() self.loadPreviewFile(preview_file) def saveMap(self): writer = self.createWriter() write_folder = self.exporter.exportDirectory() if not write_folder: return self.feedback.reset() self.feedback.show() results = writer.write(self.iface, dest_folder=write_folder, feedback=self.feedback) self.feedback.showFeedback('Success') if self.closeFeedbackOnSuccess.checkState() == Qt.Checked: self.feedback.close() result = self.exporter.postProcess(results, feedback=self.feedback) if result and (not os.environ.get('CI') and not os.environ.get('TRAVIS')): webbrowser.open_new_tab(self.exporter.destinationUrl()) def populate_layers_and_groups(self, dlg): """Populate layers on QGIS into our layers and group tree view.""" root_node = QgsProject.instance().layerTreeRoot() tree_groups = [] tree_layers = root_node.findLayers() self.layers_item = QTreeWidgetItem() self.layers_item.setText(0, "Layers and Groups") self.layersTree.setColumnCount(3) for tree_layer in tree_layers: layer = tree_layer.layer() if (layer.type() != QgsMapLayer.PluginLayer and layer.customProperty("ol_layer_type") is None): try: if layer.type() == QgsMapLayer.VectorLayer: testDump = layer.renderer().dump() layer_parent = tree_layer.parent() if layer_parent.parent() is None: item = TreeLayerItem(self.iface, layer, self.layersTree, dlg) self.layers_item.addChild(item) else: if layer_parent not in tree_groups: tree_groups.append(layer_parent) except: QgsMessageLog.logMessage(traceback.format_exc(), "qgis2web", level=Qgis.Critical) for tree_group in tree_groups: group_name = tree_group.name() group_layers = [ tree_layer.layer() for tree_layer in tree_group.findLayers()] item = TreeGroupItem(group_name, group_layers, self.layersTree) self.layers_item.addChild(item) self.layersTree.addTopLevelItem(self.layers_item) self.layersTree.expandAll() self.layersTree.resizeColumnToContents(0) self.layersTree.resizeColumnToContents(1) for i in range(self.layers_item.childCount()): item = self.layers_item.child(i) if item.checkState(0) != Qt.Checked: item.setExpanded(False) def populateLayerSearch(self): self.layer_search_combo.clear() self.layer_search_combo.addItem("None") (layers, groups, popup, visible, json, cluster, getFeatureInfo) = self.getLayersAndGroups() for count, layer in enumerate(layers): if layer.type() == layer.VectorLayer: options = [] fields = layer.fields() for f in fields: fieldIndex = fields.indexFromName(unicode(f.name())) editorWidget = layer.editorWidgetSetup(fieldIndex).type() if editorWidget == 'Hidden': continue options.append(unicode(f.name())) for option in options: displayStr = unicode(layer.name() + ": " + option) self.layer_search_combo.insertItem(0, displayStr) sln = utils.safeName(layer.name()) self.layer_search_combo.setItemData( self.layer_search_combo.findText(displayStr), sln + "_" + unicode(count)) def configureExporter(self): self.exporter.configure() def populateConfigParams(self, dlg): """ Populates the dialog with option items and widgets """ self.items = defaultdict(dict) tree = dlg.paramsTreeOL configure_export_action = QAction('...', self) configure_export_action.triggered.connect(self.configureExporter) params = getParams(configure_exporter_action=configure_export_action) for group, settings in params.items(): item = QTreeWidgetItem() item.setText(0, group) for param, value in settings.items(): subitem = self.createOptionItem(tree_widget=tree, parent_item=item, parameter=param, default_value=value) item.addChild(subitem) self.items[group][param] = subitem self.paramsTreeOL.addTopLevelItem(item) item.sortChildren(0, Qt.AscendingOrder) self.paramsTreeOL.expandAll() self.paramsTreeOL.resizeColumnToContents(0) self.paramsTreeOL.resizeColumnToContents(1) self.layer_search_combo.removeItem(1) def createOptionItem(self, tree_widget, parent_item, parameter, default_value): """create the tree item corresponding to an option parameter""" action = None if isinstance(default_value, dict): action = default_value['action'] default_value = default_value['option'] subitem = TreeSettingItem(parent_item, tree_widget, parameter, default_value, action) if parameter == 'Layer search': self.layer_search_combo = subitem.combo elif parameter == 'Exporter': self.exporter_combo = subitem.combo return subitem def setStateToWriter(self, writer): """ Sets the dialog state to match the specified writer """ self.selectMapFormat(writer) self.setStateToParams(writer.params) def setStateToParams(self, params): """ Sets the dialog state to match the specified parameters """ for group, settings in self.items.items(): for param, item in settings.items(): value = params[group][param] item.setValue(value) def selectMapFormat(self, writer): """ Updates dialog state to match the specified writer format """ self.ol3.setChecked(isinstance(writer, OpenLayersWriter)) self.leaflet.setChecked(isinstance(writer, LeafletWriter)) def loadPreviewFile(self, file): """ Loads a web based preview from a local file path """ self.previewUrl = QUrl.fromLocalFile(file) if self.preview: self.preview.settings().clearMemoryCaches() self.preview.setUrl(self.previewUrl) def getParameters(self): parameters = defaultdict(dict) for group, settings in self.items.items(): for param, item in settings.items(): parameters[group][param] = item.value() if param == "Layer search": parameters["Appearance"]["Search layer"] = ( self.layer_search_combo.itemData( self.layer_search_combo.currentIndex())) return parameters def saveParameters(self): """ Saves current dialog state to project """ WRITER_REGISTRY.saveWriterToProject(self.createWriter()) EXPORTER_REGISTRY.writeToProject(self.exporter) def getLayersAndGroups(self): layers = [] groups = {} popup = [] visible = [] json = [] cluster = [] getFeatureInfo = [] for i in range(self.layers_item.childCount()): item = self.layers_item.child(i) if isinstance(item, TreeLayerItem): if item.checkState(0) == Qt.Checked: layers.append(item.layer) popup.append(item.popup) visible.append(item.visible) json.append(item.json) cluster.append(item.cluster) getFeatureInfo.append(item.getFeatureInfo) else: group = item.name groupLayers = [] if item.checkState(0) != Qt.Checked: continue for layer in item.layers: groupLayers.append(layer) layers.append(layer) popup.append({}) if item.visible: visible.append(True) else: visible.append(False) if hasattr(item, "json") and item.json: json.append(True) else: json.append(False) if hasattr(item, "cluster") and item.cluster: cluster.append(True) else: cluster.append(False) if hasattr(item, "getFeatureInfo") and item.getFeatureInfo: getFeatureInfo.append(True) else: getFeatureInfo.append(False) groups[group] = groupLayers[::-1] return (layers[::-1], groups, popup[::-1], visible[::-1], json[::-1], cluster[::-1], getFeatureInfo[::-1]) def reject(self): self.saveParameters() (layers, groups, popup, visible, json, cluster, getFeatureInfo) = self.getLayersAndGroups() for layer, pop, vis in zip(layers, popup, visible): attrDict = {} for attr in pop: attrDict['attr'] = pop[attr] layer.setCustomProperty("qgis2web/popup/" + attr, pop[attr]) layer.setCustomProperty("qgis2web/Visible", vis) QSettings().setValue( "qgis2web/MainDialogGeometry", self.saveGeometry()) QSettings().setValue("qgis2web/previewOnStartup", self.previewOnStartup.checkState()) QSettings().setValue("qgis2web/closeFeedbackOnSuccess", self.closeFeedbackOnSuccess.checkState()) QSettings().setValue("qgis2web/previewFeatureLimit", self.previewFeatureLimit.text()) QDialog.close(self) def closeEvent(self, event): if self.devConsole or self.devConsole.isVisible() and self.preview: del self.devConsole del self.preview self.reject() event.accept()
def addOverlaysToTreeWidget(self, overlayDict, forbiddenOverlays, preSelectedOverlays, singleOverlaySelection): self.singleOverlaySelection = singleOverlaySelection testItem = QTreeWidgetItem("a") for keys in list(overlayDict.keys()): if overlayDict[keys] in forbiddenOverlays: continue else: boolStat = False split = keys.split("/") for i in range(len(split)): if len(split) == 1: newItemsChild = OverlayTreeWidgetItem( overlayDict[keys], keys) self.addTopLevelItem(newItemsChild) boolStat = False if overlayDict[keys] in preSelectedOverlays: newItemsChild.setCheckState(0, Qt.Checked) else: newItemsChild.setCheckState(0, Qt.Unchecked) elif i + 1 == len(split) and len(split) > 1: newItemsChild = OverlayTreeWidgetItem( overlayDict[keys], keys) testItem.addChild(newItemsChild) if overlayDict[keys] in preSelectedOverlays: newItemsChild.setCheckState(0, Qt.Checked) else: newItemsChild.setCheckState(0, Qt.Unchecked) elif self.topLevelItemCount() == 0 and i + 1 < len(split): newItem = QTreeWidgetItem([split[i]]) self.addTopLevelItem(newItem) testItem = newItem boolStat = True elif self.topLevelItemCount() != 0 and i + 1 < len(split): if boolStat == False: for n in range(self.topLevelItemCount()): if self.topLevelItem(n).text(0) == split[i]: testItem = self.topLevelItem(n) boolStat = True break elif n + 1 == self.topLevelItemCount(): newItem = QTreeWidgetItem([split[i]]) self.addTopLevelItem(newItem) testItem = newItem boolStat = True elif testItem.childCount() == 0: newItem = QTreeWidgetItem([split[i]]) testItem.addChild(newItem) testItem = newItem boolStat = True else: for x in range(testItem.childCount()): if testItem.child(x).text(0) == split[i]: testItem = testItem.child(x) boolStat = True break elif x + 1 == testItem.childCount(): newItem = QTreeWidgetItem([split[i]]) testItem.addChild(newItem) testItem = newItem boolStat = True
class DeviceDialog(QDialog, Ui_DeviceDialog): """ Function and Event handling class for the Ui_DeviceDialog. """ qtcb_enumerate = pyqtSignal(str, str, str, type((0,)), type((0,)), int, int) qtcb_connected = pyqtSignal(int) def __init__(self, parent): QDialog.__init__(self, parent, get_modeless_dialog_flags()) self._logger_window = parent self.device_name_by_device_identifier = {} for display_name, device_spec in device_specs.items(): self.device_name_by_device_identifier[device_spec['class'].DEVICE_IDENTIFIER] = display_name self.qtcb_enumerate.connect(self.cb_enumerate) self.qtcb_connected.connect(self.cb_connected) self.host = None self.port = None self.secret = None self.ipcon = IPConnection() self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, self.qtcb_connected.emit) self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, self.qtcb_enumerate.emit) self.setupUi(self) self.btn_add_device.clicked.connect(self.btn_add_device_clicked) self.btn_refresh.clicked.connect(self.btn_refresh_clicked) self.btn_close.clicked.connect(self.btn_close_clicked) self.tree_widget.itemActivated.connect(self.add_item) self.connected_uids = [] self.available_item = QTreeWidgetItem(['No devices available']) self.supported_item = QTreeWidgetItem(['Supported devices']) self.tree_widget.addTopLevelItem(self.available_item) self.tree_widget.addTopLevelItem(self.supported_item) for device_name in device_specs: self.supported_item.addChild(QTreeWidgetItem([device_name])) self.supported_item.sortChildren(0, Qt.AscendingOrder) self.supported_item.setExpanded(True) def cb_connected(self, connect_reason): self.tree_widget.clearSelection() self.available_item.takeChildren() self.available_item.setExpanded(True) self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port)) self.connected_uids = [] if self.secret != None: self.ipcon.set_auto_reconnect(False) # don't auto-reconnect on authentication error try: self.ipcon.authenticate(self.secret) except: try: self.ipcon.disconnect() except: pass if connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT: extra = ' after auto-reconnect' else: extra = '' self.available_item.setText(0, 'Could not authenticate' + extra) return self.ipcon.set_auto_reconnect(True) try: self.ipcon.enumerate() except: pass def cb_enumerate(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type): if enumeration_type in [IPConnection.ENUMERATION_TYPE_AVAILABLE, IPConnection.ENUMERATION_TYPE_CONNECTED]: if uid not in self.connected_uids: display_name = self.device_name_by_device_identifier.get(device_identifier) if display_name != None: self.connected_uids.append(uid) self.available_item.addChild(QTreeWidgetItem(['{0} [{1}]'.format(display_name, uid)])) self.available_item.setText(0, 'Devices available at {0}:{1}'.format(self.host, self.port)) self.available_item.sortChildren(0, Qt.AscendingOrder) else: if uid in self.connected_uids: self.connected_uids.remove(uid) for i in range(self.available_item.childCount()): child = self.available_item.child(i) if '[{0}]'.format(uid) in child.text(0): self.available_item.takeChild(i) break if self.available_item.childCount() == 0: self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port)) def btn_add_device_clicked(self): for item in self.tree_widget.selectedItems(): if item == self.available_item or item == self.supported_item: continue self._logger_window.add_device_to_tree(self.create_device_config(item.text(0))) def btn_refresh_clicked(self): try: self.ipcon.disconnect() except: pass self.tree_widget.clearSelection() self.available_item.takeChildren() self.available_item.setExpanded(True) self.connected_uids = [] self.host = self._logger_window.combo_host.currentText() self.port = self._logger_window.spin_port.value() if self._logger_window.check_authentication.isChecked(): self.secret = self._logger_window.edit_secret.text() try: self.secret.encode('ascii') except: self.secret = None self.available_item.setText(0, 'Authentication secret cannot contain non-ASCII characters') return else: self.secret = None try: self.ipcon.connect(self.host, self.port) self.available_item.setText(0, 'No devices available at {0}:{1}'.format(self.host, self.port)) except: self.available_item.setText(0, 'Could not connect to {0}:{1}'.format(self.host, self.port)) def btn_close_clicked(self): self.close() def add_item(self, item): if item == self.available_item or item == self.supported_item: return self._logger_window.add_device_to_tree(self.create_device_config(item.text(0))) def create_device_config(self, item_text): name, uid = Utilities.parse_device_name(item_text) # FIXME device_spec = device_specs[name] if uid == None: # FIXME uid = '' device = { 'host': 'default', 'name': name, 'uid': uid, 'values': {}, 'options': {} } for value_spec in device_spec['values']: device['values'][value_spec['name']] = {'interval': 0} if value_spec['subvalues'] != None: device['values'][value_spec['name']]['subvalues'] = {} for subvalue_name in value_spec['subvalues']: device['values'][value_spec['name']]['subvalues'][subvalue_name] = True if device_spec['options'] != None: for option_spec in device_spec['options']: device['options'][option_spec['name']] = {'value': option_spec['default']} return device
def update(self, *, network: Network, servers: dict, use_tor: bool): self.clear() # connected servers connected_servers_item = QTreeWidgetItem([_("Connected nodes"), '']) connected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) chains = network.get_blockchains() n_chains = len(chains) for chain_id, interfaces in chains.items(): b = blockchain.blockchains.get(chain_id) if b is None: continue name = b.get_name() if n_chains > 1: x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()]) x.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CHAIN) x.setData(0, self.CHAIN_ID_ROLE, b.get_id()) else: x = connected_servers_item for i in interfaces: star = ' *' if i == network.interface else '' item = QTreeWidgetItem([f"{i.server.to_friendly_name()}" + star, '%d'%i.tip]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, i.server) item.setToolTip(0, str(i.server)) x.addChild(item) if n_chains > 1: connected_servers_item.addChild(x) # disconnected servers disconnected_servers_item = QTreeWidgetItem([_("Other known servers"), ""]) disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces]) protocol = PREFERRED_NETWORK_PROTOCOL for _host, d in sorted(servers.items()): if _host in connected_hosts: continue if _host.endswith('.onion') and not use_tor: continue port = d.get(protocol) if port: server = ServerAddr(_host, port, protocol=protocol) item = QTreeWidgetItem([server.net_addr_str(), ""]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, server) disconnected_servers_item.addChild(item) self.addTopLevelItem(connected_servers_item) self.addTopLevelItem(disconnected_servers_item) connected_servers_item.setExpanded(True) for i in range(connected_servers_item.childCount()): connected_servers_item.child(i).setExpanded(True) disconnected_servers_item.setExpanded(True) # headers h = self.header() h.setStretchLastSection(False) h.setSectionResizeMode(0, QHeaderView.Stretch) h.setSectionResizeMode(1, QHeaderView.ResizeToContents) super().update()
def addOverlaysToTreeWidget(self, overlayDict, forbiddenOverlays, preSelectedOverlays, singleOverlaySelection): self.singleOverlaySelection = singleOverlaySelection testItem = QTreeWidgetItem("a") for keys in list(overlayDict.keys()): if overlayDict[keys] in forbiddenOverlays: continue else: boolStat = False split = keys.split("/") for i in range(len(split)): if len(split) == 1: newItemsChild = OverlayTreeWidgetItem(overlayDict[keys], keys) self.addTopLevelItem(newItemsChild) boolStat = False if overlayDict[keys] in preSelectedOverlays: newItemsChild.setCheckState(0, Qt.Checked) else: newItemsChild.setCheckState(0, Qt.Unchecked) elif i+1 == len(split) and len(split) > 1: newItemsChild = OverlayTreeWidgetItem(overlayDict[keys], keys) testItem.addChild(newItemsChild) if overlayDict[keys] in preSelectedOverlays: newItemsChild.setCheckState(0, Qt.Checked) else: newItemsChild.setCheckState(0, Qt.Unchecked) elif self.topLevelItemCount() == 0 and i+1 < len(split): newItem = QTreeWidgetItem([split[i]]) self.addTopLevelItem(newItem) testItem = newItem boolStat = True elif self.topLevelItemCount() != 0 and i+1 < len(split): if boolStat == False: for n in range(self.topLevelItemCount()): if self.topLevelItem(n).text(0) == split[i]: testItem = self.topLevelItem(n) boolStat = True break elif n+1 == self.topLevelItemCount(): newItem = QTreeWidgetItem([split[i]]) self.addTopLevelItem(newItem) testItem = newItem boolStat = True elif testItem.childCount() == 0: newItem = QTreeWidgetItem([split[i]]) testItem.addChild(newItem) testItem = newItem boolStat = True else: for x in range(testItem.childCount()): if testItem.child(x).text(0) == split[i]: testItem = testItem.child(x) boolStat = True break elif x+1 == testItem.childCount(): newItem = QTreeWidgetItem([split[i]]) testItem.addChild(newItem) testItem = newItem boolStat = True