def initializePage(self): model = QStandardItemModel() # using a document model, we can obtain all the documents to list inside this view... all_docs = DocumentStorage.documents() for doc_filename in all_docs: # find out the last scan date, number of files, etc document = PersistentScanningState(doc_filename) logger.debug("found info: {0}".format(document.info)) creation_date_str = str(document.info.date_created) last_date = str(document.info.date_last_scanned) num_scanned = "{0:,}".format(document.info.files_scanned) num_merged = "{0:,}".format(document.info.files_merged) is_merged = document.info.merge_complete if not is_merged: last_date_str = "" else: last_date_str = last_date doc = os.path.split(doc_filename)[1][:-len('.sqlite')] items = [ QStandardItem(doc), QStandardItem(str(num_scanned)), QStandardItem(creation_date_str), QStandardItem(str(num_merged)), QStandardItem(last_date_str), ] items[1].setData(Qt.AlignRight, Qt.TextAlignmentRole) items[3].setData(Qt.AlignRight, Qt.TextAlignmentRole) model.invisibleRootItem().appendRow(items) self.ui.treeView.setModel(model) header = self.ui.treeView.header() model.setHeaderData(0, Qt.Horizontal, "Name") model.setHeaderData(1, Qt.Horizontal, "# First Scan") model.setHeaderData(2, Qt.Horizontal, "Date Created") model.setHeaderData(3, Qt.Horizontal, "# Second Scan") model.setHeaderData(4, Qt.Horizontal, "Date Scanned") header.setResizeMode(0, QHeaderView.ResizeToContents) header.setResizeMode(1, QHeaderView.ResizeToContents) header.setResizeMode(2, QHeaderView.ResizeToContents) header.setResizeMode(3, QHeaderView.ResizeToContents) header.setResizeMode(4, QHeaderView.ResizeToContents) self.ui.treeView.selectionModel().currentRowChanged.connect( self.__onSelectionChanged)
def initializePage(self): model = QStandardItemModel() # using a document model, we can obtain all the documents to list inside this view... all_docs = DocumentStorage.documents() for doc_filename in all_docs: # find out the last scan date, number of files, etc document = PersistentScanningState(doc_filename) logger.debug("found info: {0}".format(document.info)) creation_date_str = str(document.info.date_created) last_date = str(document.info.date_last_scanned) num_scanned = "{0:,}".format(document.info.files_scanned) num_merged = "{0:,}".format(document.info.files_merged) is_merged = document.info.merge_complete if not is_merged: last_date_str = "" else: last_date_str = last_date doc = os.path.split(doc_filename)[1][:-len('.sqlite')] items = [ QStandardItem(doc), QStandardItem(str(num_scanned)), QStandardItem(creation_date_str), QStandardItem(str(num_merged)), QStandardItem(last_date_str), ] items[1].setData(Qt.AlignRight, Qt.TextAlignmentRole) items[3].setData(Qt.AlignRight, Qt.TextAlignmentRole) model.invisibleRootItem().appendRow(items) self.ui.treeView.setModel(model) header = self.ui.treeView.header() model.setHeaderData(0, Qt.Horizontal, "Name") model.setHeaderData(1, Qt.Horizontal, "# First Scan") model.setHeaderData(2, Qt.Horizontal, "Date Created") model.setHeaderData(3, Qt.Horizontal, "# Second Scan") model.setHeaderData(4, Qt.Horizontal, "Date Scanned") header.setResizeMode(0, QHeaderView.ResizeToContents) header.setResizeMode(1, QHeaderView.ResizeToContents) header.setResizeMode(2, QHeaderView.ResizeToContents) header.setResizeMode(3, QHeaderView.ResizeToContents) header.setResizeMode(4, QHeaderView.ResizeToContents) self.ui.treeView.selectionModel().currentRowChanged.connect(self.__onSelectionChanged)
def on_ions_updated(self, new_ions): qmodel = QStandardItemModel() qmodel.setColumnCount(2) qmodel.setHorizontalHeaderItem(0, QStandardItem('Ion')) qmodel.setHorizontalHeaderItem(1, QStandardItem('Abundance (%)')) root = qmodel.invisibleRootItem() element_keyfunc = lambda x: x.isotope.element sorted_ions = sorted(new_ions, key=element_keyfunc) for element, ions in itertools.groupby(sorted_ions, key=element_keyfunc): element_item = QStandardItem(element) element_item.setCheckable(True) element_item.setCheckState(2) root.appendRow(element_item) for ion in ions: ion_name = QStandardItem(ion.name) ion_name.setData(ion,32) ion_name.emitDataChanged() ion_abundance = QStandardItem(str(ion.isotope.abundance)) element_item.appendRow([ion_name, ion_abundance]) self.ionlistTree.setModel(qmodel) self.ionlistTree.expandAll() self.addionsButton.setEnabled(True) self._qmodel=qmodel
def on_analyses_viewmodel_updated(self, view_model): qmodel = QStandardItemModel() qmodel.itemChanged.connect(self.on_qmodel_itemChanged) qmodel.setColumnCount(5) qmodel.setHorizontalHeaderItem(0, QStandardItem('Ion')) qmodel.setHorizontalHeaderItem(1, QStandardItem('Method')) qmodel.setHorizontalHeaderItem(2, QStandardItem('Start')) qmodel.setHorizontalHeaderItem(3, QStandardItem('End')) qmodel.setHorizontalHeaderItem(4, QStandardItem('Reason')) root = qmodel.invisibleRootItem() for ion, analysis in view_model.analyses.items(): ion_name = QStandardItem(ion.name) ion_name.setData(ion, Qt.UserRole) method = QStandardItem(analysis.method) start = QStandardItem(str(round(analysis.range.start,2))) end = QStandardItem(str(round(analysis.range.end,2))) reason = QStandardItem(analysis.reason) root.appendRow([ion_name, method, start, end, reason]) self.rangedTable.setModel(qmodel) self.rangedTable.setItemDelegateForColumn(1, MethodsComboDelegate(view_model.methods, self.rangedTable)) for row in range(0, qmodel.rowCount()): self.rangedTable.openPersistentEditor(qmodel.index(row, 1)) self.rangedTable.setColumnWidth(1, 95) self.rangedTable.setContextMenuPolicy(3) self.rangedTable.customContextMenuRequested.connect(self._context_menu_requested) shortcut = QShortcut(QKeySequence('Del'), self.rangedTable, self._delete_ion,self._delete_ion, context=0)
class BreakpointsViewer(QTreeView): """ showing bps """ def __init__(self, parent): super(QTreeView, self).__init__(parent) self.setAutoScroll(True) self.source_files = {} self.focus_signal = None self.header().setResizeMode(QHeaderView.ResizeToContents) self._show_args = None self.bp_data = QStandardItemModel() self.setModel(self.bp_data) self.setAlternatingRowColors(True) def set_focus_signal(self, signal): """ set callback to focus source file line""" self.focus_signal = signal def clear(self): """ clear the widget""" self.bp_data.clear() self.bp_data.setHorizontalHeaderLabels(['ID', 'Hits', 'Ignore Count', 'Condition']) def update_bp_info(self, target): """ update breakpoint info """ self.clear() root = self.bp_data.invisibleRootItem() for breakpoint in target.breakpoint_iter(): if not breakpoint.IsValid() or breakpoint.IsInternal(): continue bp_item = QStandardItem(str(breakpoint.id)) bp_row =[bp_item, QStandardItem(str(breakpoint.GetHitCount())), QStandardItem(str(breakpoint.GetIgnoreCount())), QStandardItem(str(breakpoint.GetCondition()))] for loc in breakpoint: loc_row = [QStandardItem(str(loc.GetID())), QStandardItem(str(loc.GetAddress().GetLineEntry()))] bp_item.appendRow(loc_row) root.appendRow(bp_row) self.expandToDepth(1) def mousePressEvent(self, event): """ overrided """ idx = self.indexAt(event.pos()) if idx.isValid() and self.focus_signal: model = idx.model() idx = idx.sibling(idx.row(), 0) if idx.isValid(): item = model.itemFromIndex(idx) if item and item.isSelectable(): if item in self.source_files: file_info = self.source_files[item] if self.focus_signal: self.focus_signal.emit(file_info.GetFileSpec().fullpath, file_info.GetLine()) self.frame_changed.emit(self.frames[item]) else: logging.error('frame cannot find associated source file') QTreeView.mousePressEvent(self, event)
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 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)
class Menu(TreeViewTela): def __init__(self, altura, parent=None): super().__init__(altura, parent) self._model = QStandardItemModel(0, 1) self._model.setHorizontalHeaderItem(0, QStandardItem("Menu")) self._itemsFuncoes = [] def setMenu(self, menu): self._adicionarSubMenu(menu, self._model.invisibleRootItem()) self.setSelecionado(self._model.index(0,0)) def getMenuSelecionado(self): sel = self.getSelecionado() s = '' while sel.isValid(): s = '/' + sel.data() + s sel = sel.parent() return s def getFuncaoItem(self, item): for i in self._itemsFuncoes: if i.item == item.data(): return i.funcao def getFuncaoItemSelecionado(self): return self.getFuncaoItem(self.getSelecionado()) def _adicionarSubMenu(self, subMenu, pai): if isinstance(subMenu, ItemFuncao): item = QStandardItem(subMenu.item) self._itemsFuncoes.append(subMenu) pai.appendRow(item) elif isinstance(subMenu, str): pai.appendRow(QStandardItem(subMenu)) elif isinstance(subMenu, (tuple, list)): for i in subMenu: self._adicionarSubMenu(i, pai) else: for key, value in subMenu.items(): p = QStandardItem(key) pai.appendRow(p) self._adicionarSubMenu(value, p)
class ConfigDialog(BASE, WIDGET): def __init__(self, toolbox): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.toolbox = toolbox self.groupIcon = QIcon() self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(self.tr('Search...')) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) self.searchBox.textChanged.connect(self.fillTree) self.fillTree() self.tree.expanded.connect(self.adjustColumns) def fillTree(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels([self.tr('Setting'), self.tr('Value')]) text = unicode(self.searchBox.text()) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) for setting in settings[group]: if setting.hidden or setting.name.startswith("MENU_"): continue if text == '' or text.lower() in setting.description.lower(): labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) if text != '': self.tree.expand(groupItem.index()) providersItem = QStandardItem(self.tr('Providers')) icon = QIcon(os.path.join(pluginPath, 'images', 'alg.png')) providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in settings.keys(): if group in priorityKeys or group == menusSettingsGroup: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue if text == '' or text.lower() in setting.description.lower(): labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) menusItem = QStandardItem(self.tr('Menus (requires restart)')) icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) menusItem.setIcon(icon) menusItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [menusItem, emptyItem]) providers = Processing.providers for provider in providers: groupItem = QStandardItem(provider.getDescription()) icon = provider.getIcon() groupItem.setIcon(icon) groupItem.setEditable(False) for alg in provider.algs: labelItem = QStandardItem(alg.name) labelItem.setIcon(icon) labelItem.setEditable(False) try: setting = ProcessingConfig.settings["MENU_" + alg.commandLineName()] except: continue self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) menusItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def accept(self): for setting in self.items.keys(): if isinstance(setting.value, bool): setting.setValue(self.items[setting].checkState() == Qt.Checked) else: try: setting.setValue(unicode(self.items[setting].text())) except ValueError as e: QMessageBox.warning(self, self.tr('Wrong value'), self.tr('Wrong value for parameter "%s":\n\n%s' % (setting.description, unicode(e)))) return setting.save() Processing.updateAlgsList() updateMenus() QDialog.accept(self) def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class SubPowerWidget(QWidget): """ @brief Zeigt alle Unterkräfte in einer Baumstruktur an. """ def __init__(self, template, character, parent=None): super(SubPowerWidget, self).__init__(parent) self.__storage = template self.__character = character self.__model = QStandardItemModel() # Das ungenutzte Model dient dazu, alle Unterkräfte aufzunehmen, die ich nicht darstellen möchte. Ist einfacher, als diese im View zu verstecken. self.__modelUnused = QStandardItemModel() self._layout = QVBoxLayout() self.setLayout(self._layout) self.__view = QTreeView() self.__view.setHeaderHidden(True) self.__view.setModel(self.__model) self._layout.addWidget(self.__view) self._typ = "Subpower" categories = self.__storage.categories(self._typ) self.__items = {} self.__rootItem = QStandardItem() self.__rootItem = self.__model.invisibleRootItem() self.__rootItemUnused = QStandardItem() self.__rootItemUnused = self.__modelUnused.invisibleRootItem() for item in categories: categoryItem = QStandardItem(item) self.__rootItem.appendRow(categoryItem) ## Ich benötige diese Items auch im ungenutzten Model. categoryItemUnused = QStandardItem(item) self.__rootItemUnused.appendRow(categoryItemUnused) traitList = list(self.__character.traits[self._typ][item].items()) traitList.sort() for trait in traitList: traitItem = QStandardItem(trait[1].name) traitItem.setCheckable(True) ## Unhashable Type self.__items[trait[1]] = traitItem categoryItem.appendRow(traitItem) ## Funktioniert mit PySide nicht: #trait[1].availableChanged.connect(traitItem.setEnabled) ## Funktioniert auch mit PySide: trait[1].availableChanged.connect( lambda enable, item=traitItem: item.setEnabled(enable)) trait[1].valueChanged.connect(lambda val, trait=trait[ 1], item=traitItem: self.__setItemValue(trait, item)) self.__model.itemChanged.connect(self.__getItemValue) self.__character.speciesChanged.connect(self.hideOrShowToolPage) self.__character.breedChanged.connect(self.hideOrShowToolPage) self.__character.factionChanged.connect(self.hideOrShowToolPage) def __setItemValue(self, trait, item): """ Setzt den Wert der Angezeigten Items. """ if trait.value == 0: item.setCheckState(Qt.Unchecked) elif trait.value == 1: item.setCheckState(Qt.PartiallyChecked) else: item.setCheckState(Qt.Checked) def __getItemValue(self, item): """ Setzt den Wert der Eigenschaft im Speicher. """ for trait in self.__items.items(): if id(trait[1]) == id(item): trait[0].value = item.checkState() break def hideOrShowToolPage(self, res): """ Alle Eigenschaften, die nicht zur Verfügung stehen, werden verborgen, indem sie in ein anderes Model verschoben werden. \bug Möglicher Fehler in PySide: Der Aufruf von QStandardItem.model() führt beim Beenden des Programms zu einem Segmentation Fault. """ # Versteckt alle Unterkräfte, die zu gewähltem Charakter nicht passen. for item in self.__items.items(): if ((item[0].species and item[0].species != self.__character.species) or (item[0].only and self.__character.breed not in item[0].only and self.__character.faction not in item[0].only)): #self.__view.setRowHidden(item[1].index().row(), item[1].parent().index(), True) #Debug.debug(item[1].model()) ## Hier wird beispielsweise besagter Aufruf getätigt, der zu einem segfault führt. if item[1].model() == self.__model: parent = item[1].parent() itemUnused = parent.takeRow(item[1].index().row()) parentUnused = self.__modelUnused.findItems( parent.text())[0] parentUnused.appendRow(itemUnused) else: #self.__view.setRowHidden(item[1].index().row(), item[1].parent().index(), False) if item[1].model() == self.__modelUnused: parent = item[1].parent() itemUsed = parent.takeRow(item[1].index().row()) parentUsed = self.__model.findItems(parent.text())[0] parentUsed.appendRow(itemUsed) ## Versteckt alle Elternzeilen, wenn sie keine Kinder enthalten. for i in range(self.__model.rowCount()): categoryItem = self.__model.item(i) if categoryItem.hasChildren(): self.__view.setRowHidden(categoryItem.index().row(), self.__rootItem.index(), False) else: self.__view.setRowHidden(categoryItem.index().row(), self.__rootItem.index(), True)
class ConfigManagerDialog(ui_configmanager.Ui_ProjectInstallerDialog, QDialog): def __init__(self, roamapp, parent=None): super(ConfigManagerDialog, self).__init__(parent) self.setupUi(self) self.bar = roam.messagebaritems.MessageBar(self) self.roamapp = roamapp # Nope! self.projectwidget.roamapp = roamapp self.projectwidget.bar = self.bar self.treemodel = QStandardItemModel() self.projectList.setModel(self.treemodel) self.projectList.setHeaderHidden(True) self.projectList.selectionModel().currentChanged.connect( self.nodeselected) self.projectwidget.adjustSize() self.setWindowFlags(Qt.Window) self.projectwidget.projectupdated.connect(self.projectupdated) self.projectwidget.setaboutinfo() self.projectwidget.projects_page.projectlocationchanged.connect( self.loadprojects) self.setuprootitems() ConfigEvents.deleteForm.connect(self.delete_form) def raiseerror(self, *exinfo): self.bar.pushError(*exinfo) import roam.errors roam.errors.send_exception(exinfo) def setuprootitems(self): rootitem = self.treemodel.invisibleRootItem() self.roamnode = RoamNode() rootitem.appendRow(self.roamnode) self.projectsnode = ProjectsNode(folder=None) rootitem.appendRow(self.projectsnode) self.pluginsnode = PluginsNode() pluginpath = os.path.join(self.roamapp.apppath, "plugins") rootitem.appendRow(self.pluginsnode) self.pluginsnode.add_plugin_paths([pluginpath]) def delete_form(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if not node.type() == Treenode.FormNode: return title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes print "Delete" if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) print parentindex self.projectList.setCurrentIndex(parentindex) def delete_project(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.type() == Treenode.ProjectNode: self.projectwidget._closeqgisproject() title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) self.projectList.setCurrentIndex(newindex) def addprojectfolders(self, folders): self.projectwidget.projects_page.setprojectfolders(folders) def loadprojects(self, projectpath): projects = roam.project.getProjects([projectpath]) self.projectsnode.loadprojects(projects, projectsbase=projectpath) index = self.treemodel.indexFromItem(self.projectsnode) self.projectList.setCurrentIndex(index) self.projectList.expand(index) def nodeselected(self, index, _): node = index.data(Qt.UserRole) if node is None: return project = node.project if project and not self.projectwidget.project == project: # Only load the project if it's different the current one. self.projectwidget.setproject(project) node.create_children() validateresults = list(project.validate()) if validateresults: text = "Here are some reasons we found: \n\n" for message in validateresults: text += "- {} \n".format(message) self.projectwidget.reasons_label.setText(text) if node.nodetype == Treenode.RoamNode: self.projectwidget.projectlabel.setText( "IntraMaps Roam Config Manager") if node.nodetype == Treenode.AddNew: try: item = node.additem() except ValueError: return newindex = self.treemodel.indexFromItem(item) self.projectList.setCurrentIndex(newindex) return self.projectwidget.projectbuttonframe.setVisible(not project is None) self.projectwidget.setpage(node.page, node) def projectupdated(self): index = self.projectList.currentIndex() node = find_node(index) node.refresh()
class FileTypes(base2, form2): def __init__(self, parent=None): super(base2, self).__init__(parent) self.setupUi(self) self.model = QStandardItemModel() self.model.itemChanged.connect(self.on_item_changed) self.model.setHorizontalHeaderItem(0, QStandardItem("")) self.model_init() self.saveButton.clicked.connect(self.save) self.okCancelBox.accepted.connect(self.accept) self.okCancelBox.rejected.connect(self.reject) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.customContextMenuRequested.connect(self.openMenu) self.treeView.setToolTip( 'Here you can select file types that you want to find. Also you can\nadd new category or file type. Click right button on it.' ) def model_init(self): categories = {} if not categories: with open('categories.json') as f: categories = load(f) for element in categories: catItem = QStandardItem(element.keys()[0]) catItem.setCheckable(True) catItem.setCheckState(element[element.keys()[0]]) for type_name, check_state in element["Types"].items(): typeItem = QStandardItem(type_name) typeItem.setCheckable(True) typeItem.setCheckState(check_state) catItem.appendRow(typeItem) self.model.appendRow(catItem) self.treeView.setModel(self.model) self.submit_file_types() def quit(self): self.close() def on_item_changed(self, item): if item.checkState() == Qt.Checked: if item.hasChildren(): for row in range(item.rowCount()): item.child(row).setCheckState(Qt.Checked) else: item.parent().setCheckState(Qt.PartiallyChecked) elif item.checkState() == Qt.Unchecked: if item.hasChildren(): for row in range(item.rowCount()): item.child(row).setCheckState(Qt.Unchecked) else: children = range(item.parent().rowCount()) children.pop(item.index().row()) for row in children: if item.parent().child(row).checkState(): return item.parent().setCheckState(Qt.Unchecked) def submit_file_types(self): categories = [] root = self.model.invisibleRootItem() for num_cat in range(root.rowCount()): category = root.child(num_cat, 0) categories.append({ str(category.text()): category.checkState(), "Types": {} }) for num_type in range(category.rowCount()): type = category.child(num_type, 0) categories[-1]["Types"].update( {str(type.text()): type.checkState()}) return categories def openMenu(self, position): level = 0 index = self.treeView.selectedIndexes()[0] while index.parent().isValid(): index = index.parent() level += 1 menu = QMenu() if level == 0: menu.addAction(self.tr("Add category"), self.add_category) menu.addAction(self.tr("Add type"), self.add_type) menu.addAction(self.tr("Remove"), self.remove) elif level == 1: menu.addAction(self.tr("Add type"), self.add_type) menu.addAction(self.tr("Remove"), self.remove) menu.exec_(self.treeView.viewport().mapToGlobal(position)) def add_category(self): text, ok = QInputDialog.getText(self, 'Create new category', 'Category name:') if ok: catItem = QStandardItem(text) catItem.setCheckable(True) self.model.appendRow(catItem) #self.label.setText(unicode(text)) def add_type(self): text, ok = QInputDialog.getText(self, 'Add new type', 'Postfix:') if ok: catType = QStandardItem(text) catType.setCheckable(True) index = self.treeView.selectedIndexes()[0] if self.model.itemFromIndex(index).hasChildren(): self.model.itemFromIndex(index).appendRow(catType) else: self.model.itemFromIndex(index).parent().appendRow(catType) def save(self): with open('categories.json', 'w') as f: dump(self.submit_file_types(), f) def remove(self): index = self.treeView.selectedIndexes()[0] parent = self.model.itemFromIndex(index).parent() if parent: self.model.removeRow(index.row(), parent.index()) else: parent = self.model.invisibleRootItem() self.model.removeRow(index.row(), parent.index()) @staticmethod def call(): dialog = FileTypes() result = dialog.exec_() categories = dialog.submit_file_types() return categories, result == QDialog.Accepted
class TreeviewWidgetSelectProve(QMainWindow): def __init__(self): super(TreeviewWidgetSelectProve, self).__init__() # self.uiw = loadUi("~/link/ROS/groovy_quantal/catkin_ws/src/rqt_prove/resource/treeview.ui") # self.uiw = loadUi("/resource/treeview.ui") self.uiw = loadUi("/home/n130s/link/ROS/groovy_quantal/catkin_ws/src/rqt_prove/resource/treeview.ui") # self._treeview = QTreeView(self) # self._treeview.SelectionMode = QAbstractItemView.ContiguousSelection # rp = rospkg.RosPack() # ui_file = os.path.join(rp.get_path('rqt_prove'), # 'resource', 'treeview.ui') # loadUi(ui_file, self) self._std_model = QStandardItemModel() self._rootitem = self._std_model.invisibleRootItem() item_r_1 = QStandardItem("r1") # item_r_2 = QStandardItem("r2") # item_r_3 = QStandardItem("r3") # self.item_r_3_1 = QStandardItem("r3-1") # self.item_r_3_1_1 = QStandardItem("child_c") # item_r_3.appendRow(self.item_r_3_1) # self.item_r_3_1.appendRow(self.item_r_3_1_1) # item_r_4 = QStandardItem("r4") # item_r_5 = QStandardItem("r5") # item_r_1 = TreenodeQstdItem("/a/rowrowrowrow1") # item_r_2 = TreenodeQstdItem("/b/rowrowrowrow2") # item_r_3 = TreenodeQstdItem("/c/rowrow3") # self.item_r_3_1 = TreenodeQstdItem("/c/rowrow3/child") # item_r_3.appendRow(self.item_r_3_1) # item_r_4 = TreenodeQstdItem("/d/row4") self._rootitem.appendRow(item_r_1) # self._rootitem.appendRow(item_r_2) # self._rootitem.appendRow(item_r_3) # self._rootitem.appendRow(item_r_4) # self._rootitem.appendRow(item_r_5) print('_rootitem index={}'.format(self._rootitem.index())) self.uiw._treeview.setModel(self._std_model) self.selectionModel = self.uiw._treeview.selectionModel() self.selectionModel.selectionChanged.connect( self._selection_changed_slot) # print('del/sel?\tde/sel index\tde/sel.row\tde/sel.dat\tsel.item\tsel.item.name\tparent.de/sel\tparent.sel.dat\tinternal id') print('del/sel?\tde/sel index\tde/sel.row\tde/sel.dat\tparent\tinternal id') self.uiw.show() def _selection_changed_slot(self, selected, deselected): """ Receives args from signal QItemSelectionModel.selectionChanged. :type selected: QItemSelection :type deselected: QItemSelection """ self._test_sel_index(selected, deselected) def _test_sel_index(self, selected, deselected): src_model = self._std_model index_current = None index_deselected = None index_parent_sel = None index_parent_desel = None curr_qstd_item = None indexes = selected.indexes() del_or_sel = 'Sel' index_internalid = -1 if len(indexes) > 0: index_internalid = selected.indexes()[0].internalId() # # Trying many approaches to get the right qindex # # Approach-1 index_current = selected.indexes()[0] # # Approach-2 # index_current_from_indexes = selected.indexes()[0] # index_current = src_model.index(index_current_from_indexes.row(), # 0, QModelIndex()) # 0, index_current_from_indexes) # index_current = self.selectionModel.currentIndex() index_parent_sel = index_current.parent() curr_qstd_item = src_model.itemFromIndex(# index_parent) index_current) elif len(deselected.indexes()) > 0: index_internalid = deselected.indexes()[0].internalId() del_or_sel = 'Desel' index_deselected = self.selectionModel.currentIndex() index_parent_desel = index_deselected.parent() curr_qstd_item = src_model.itemFromIndex(index_deselected) tabular_format = '{}\t{}\t{}\t{}\t{}\t{}' if len(indexes) > 0: print(tabular_format.format( del_or_sel, index_current, index_current.row(), index_current.data(Qt.DisplayRole).toString(), # curr_qstd_item, # curr_qstd_item.data(Qt.DisplayRole), index_parent_sel, # index_parent_sel.data(Qt.DisplayRole), index_internalid)) elif len(deselected.indexes()) > 0: print(tabular_format.format( del_or_sel, index_deselected, index_deselected.row(), index_deselected.data(Qt.DisplayRole).toString(), # curr_qstd_item, # curr_qstd_item.data(), index_parent_desel, # index_parent_desel.data(Qt.DisplayRole), index_internalid)) self.selectionModel.select(index_deselected, QItemSelectionModel.Deselect)
class ConfigManagerDialog(ui_configmanager.Ui_ProjectInstallerDialog, QDialog): def __init__(self, roamapp, parent=None): super(ConfigManagerDialog, self).__init__(parent) self.setupUi(self) self.bar = roam.messagebaritems.MessageBar(self) self.roamapp = roamapp self.reloadingProject = False self.loadedProject = None # Nope! self.projectwidget.roamapp = roamapp self.projectwidget.bar = self.bar self.treemodel = QStandardItemModel() self.projectList.setModel(self.treemodel) self.projectList.setHeaderHidden(True) self.projectList.selectionModel().currentChanged.connect(self.nodeselected) self.projectwidget.adjustSize() self.setWindowFlags(Qt.Window) self.projectwidget.projectupdated.connect(self.projectupdated) self.projectwidget.projectloaded.connect(self.projectLoaded) self.projectwidget.setaboutinfo() self.projectwidget.projects_page.projectlocationchanged.connect(self.loadprojects) self.setuprootitems() ConfigEvents.deleteForm.connect(self.delete_form) # ## If all the layers are gone we need to reset back to the top state to get the widgets # ## back into sync. # QgsMapLayerRegistry.instance().removeAll.connect(self.reset_project) # def reset_project(self): # print(QgsProject.instance().fileName()) # print("ALL REMOVED") # node = self.projectsnode.find_by_filename(QgsProject.instance().fileName()) def raiseerror(self, *exinfo): self.bar.pushError(*exinfo) import roam.errors roam.errors.send_exception(exinfo) def setuprootitems(self): rootitem = self.treemodel.invisibleRootItem() self.roamnode = RoamNode() rootitem.appendRow(self.roamnode) self.projectsnode = ProjectsNode(folder=None) rootitem.appendRow(self.projectsnode) self.pluginsnode = PluginsNode() pluginpath = os.path.join(self.roamapp.apppath, "plugins") rootitem.appendRow(self.pluginsnode) self.pluginsnode.add_plugin_paths([pluginpath]) def delete_form(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if not node.type() == Treenode.FormNode: return title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes print "Delete" if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) print parentindex self.projectList.setCurrentIndex(parentindex) def delete_project(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.type() == Treenode.ProjectNode: self.projectwidget._closeqgisproject() title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) self.projectList.setCurrentIndex(newindex) def addprojectfolders(self, folders): self.projectwidget.projects_page.setprojectfolders(folders) def loadprojects(self, projectpath): projects = roam.project.getProjects([projectpath]) self.projectsnode.loadprojects(projects, projectsbase=projectpath) index = self.treemodel.indexFromItem(self.projectsnode) self.projectList.setCurrentIndex(index) self.projectList.expand(index) def projectLoaded(self, project): roam.utils.info("Project loaded: {}".format(project.name)) node = self.projectsnode.find_by_name(project.name) node.create_children() self.projectwidget.setpage(node.page, node, refreshingProject=True) self.reloadingProject = False self.loadedProject = project self.projectList.setExpanded(node.index(), True ) def nodeselected(self, index, last, reloadProject=False): node = index.data(Qt.UserRole) if node is None: return project = node.project if project: validateresults = list(project.validate()) if validateresults: text = "Here are some reasons we found: \n\n" for message in validateresults: text += "- {} \n".format(message) self.projectwidget.reasons_label.setText(text) return if node.nodetype == Treenode.ProjectNode and reloadProject: self.reloadingProject = True self.projectwidget.setproject(project) return if project and self.loadedProject != project: # Only load the project if it's different the current one. roam.utils.info("Swapping to project: {}".format(project.name)) if self.loadedProject: lastnode = self.projectsnode.find_by_name(self.loadedProject.name) self.projectList.setExpanded(lastnode.index(), False ) ## We are closing the open project at this point. Watch for null ref after this. self.projectwidget.setproject(project) return else: roam.utils.debug("Setting page") self.projectwidget.setpage(node.page, node) if node.nodetype == Treenode.RoamNode: self.projectwidget.projectlabel.setText("IntraMaps Roam Config Manager") if node.nodetype == Treenode.AddNew: try: item = node.additem() except ValueError: return newindex = self.treemodel.indexFromItem(item) self.projectList.setCurrentIndex(newindex) return self.projectwidget.projectbuttonframe.setVisible(not project is None) def projectupdated(self, project): # index = self.projectList.currentIndex() # node = find_node(index) # node.refresh() print "PROJECT UPDATED" node = self.projectsnode.find_by_name(project.name) self.projectList.selectionModel().select(node.index(), QItemSelectionModel.ClearAndSelect) self.nodeselected(node.index(), None, reloadProject=True)
class PersistendIndexProve(QMainWindow): def __init__(self): super(PersistendIndexProve, self).__init__() self.uiw = loadUi("/u/isaito/data/Dropbox/ROS/groovy_quantal/catkin_ws/src/rqt_prove/resource/treeview.ui") self._std_model = QStandardItemModel() self._rootitem = self._std_model.invisibleRootItem() item_r_1 = QStandardItem("r1") item_r_2 = QStandardItem("r2") print 'index before {}'.format(item_r_1.index()) qindex_persistent = QPersistentModelIndex(item_r_1.index()) self._std_model.beginInsertRows(self._rootitem.index(), 0, 0) self._rootitem.appendRow(item_r_1) self._rootitem.appendRow(item_r_2) self._std_model.endInsertRows() print 'index after {}'.format(item_r_1.index()) print 'index after 2 {}'.format(self._std_model.index(0, 0, QModelIndex())) print '_rootitem index={} persistent list={}'.format( self._rootitem.index(), self._std_model.persistentIndexList()) self.uiw._treeview.setModel(self._std_model) self.selectionModel = self.uiw._treeview.selectionModel() self.selectionModel.selectionChanged.connect( self._selection_changed_slot) self.selectionModel.currentChanged.connect( self._current_changed_slot) print('del/sel?\tde/sel index\tde/sel.row\tde/sel.dat\tparent\tinternal id') self.uiw.show() def _current_changed_slot(self, current, previous): print 'changed slot current={} prev={}'.format( current.data(Qt.DisplayRole).toString(), previous.data(Qt.DisplayRole).toString()) def _selection_changed_slot(self, selected, deselected): """ Receives args from signal QItemSelectionModel.selectionChanged. :type selected: QItemSelection :type deselected: QItemSelection """ # self._test_sel_index(selected, deselected) self._sel_index_2(selected, deselected) def _sel_index_2(self, selected, deselected): # index_list = self.selectionModel.selectedIndexes() for index in self.selectionModel.selectedIndexes(): print 'indices selected={} len selected={} deseled={}'.format( str(index.data(Qt.DisplayRole)), len(selected), len(deselected)) def _test_sel_index(self, selected, deselected): src_model = self._std_model index_current = None index_deselected = None index_parent_sel = None index_parent_desel = None curr_qstd_item = None indexes = selected.indexes() del_or_sel = 'Sel' index_internalid = -1 if len(indexes) > 0: index_internalid = selected.indexes()[0].internalId() # # Trying many approaches to get the right qindex # # Approach-1 index_current = selected.indexes()[0] # # Approach-2 # index_current_from_indexes = selected.indexes()[0] # index_current = src_model.index(index_current_from_indexes.row(), # 0, QModelIndex()) # 0, index_current_from_indexes) # index_current = self.selectionModel.currentIndex() index_parent_sel = index_current.parent() curr_qstd_item = src_model.itemFromIndex(# index_parent) index_current) elif len(deselected.indexes()) > 0: index_internalid = deselected.indexes()[0].internalId() del_or_sel = 'Desel' index_deselected = self.selectionModel.currentIndex() index_parent_desel = index_deselected.parent() curr_qstd_item = src_model.itemFromIndex(index_deselected) tabular_format = '{}\t{}\t{}\t{}\t{}\t{}' if len(indexes) > 0: print(tabular_format.format( del_or_sel, index_current, index_current.row(), index_current.data(Qt.DisplayRole).toString(), # curr_qstd_item, # curr_qstd_item.data(Qt.DisplayRole), index_parent_sel, # index_parent_sel.data(Qt.DisplayRole), index_internalid)) elif len(deselected.indexes()) > 0: print(tabular_format.format( del_or_sel, index_deselected, index_deselected.row(), index_deselected.data(Qt.DisplayRole).toString(), # curr_qstd_item, # curr_qstd_item.data(), index_parent_desel, # index_parent_desel.data(Qt.DisplayRole), index_internalid)) self.selectionModel.select(index_deselected, QItemSelectionModel.Deselect)
class OWConfusionMatrix(widget.OWWidget): """Confusion matrix widget""" name = "Confusion Matrix" description = "Display a confusion matrix constructed from " \ "the results of classifier evaluations." icon = "icons/ConfusionMatrix.svg" priority = 1001 inputs = [("Evaluation Results", Orange.evaluation.Results, "set_results")] outputs = [("Selected Data", Orange.data.Table)] quantities = [ "Number of instances", "Proportion of predicted", "Proportion of actual" ] settingsHandler = settings.ClassValuesContextHandler() selected_learner = settings.Setting([0], schema_only=True) selection = settings.ContextSetting(set()) selected_quantity = settings.Setting(0) append_predictions = settings.Setting(True) append_probabilities = settings.Setting(False) autocommit = settings.Setting(True) UserAdviceMessages = [ widget.Message( "Clicking on cells or in headers outputs the corresponding " "data instances", "click_cell") ] def __init__(self): super().__init__() self.data = None self.results = None self.learners = [] self.headers = [] box = gui.vBox(self.controlArea, "Learners") self.learners_box = gui.listBox(box, self, "selected_learner", "learners", callback=self._learner_changed) box = gui.vBox(self.controlArea, "Show") gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.vBox(self.controlArea, "Select") gui.button(box, self, "Select Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Select Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "Clear Selection", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.vBox(self.controlArea, "Output") gui.checkBox(box, self, "append_predictions", "Predictions", callback=self._invalidate) gui.checkBox(box, self, "append_probabilities", "Probabilities", callback=self._invalidate) gui.auto_commit(self.controlArea, self, "autocommit", "Send Selected", "Send Automatically") grid = QGridLayout() self.tablemodel = QStandardItemModel(self) view = self.tableview = QTableView( editTriggers=QTableView.NoEditTriggers) view.setModel(self.tablemodel) view.horizontalHeader().hide() view.verticalHeader().hide() view.horizontalHeader().setMinimumSectionSize(60) view.selectionModel().selectionChanged.connect(self._invalidate) view.setShowGrid(False) view.setItemDelegate(BorderedItemDelegate(Qt.white)) view.clicked.connect(self.cell_clicked) grid.addWidget(view, 0, 0) self.mainArea.layout().addLayout(grid) def sizeHint(self): """Initial size""" return QSize(750, 490) def _item(self, i, j): return self.tablemodel.item(i, j) or QStandardItem() def _set_item(self, i, j, item): self.tablemodel.setItem(i, j, item) def _init_table(self, nclasses): item = self._item(0, 2) item.setData("Predicted", Qt.DisplayRole) item.setTextAlignment(Qt.AlignCenter) item.setFlags(Qt.NoItemFlags) self._set_item(0, 2, item) item = self._item(2, 0) item.setData("Actual", Qt.DisplayRole) item.setTextAlignment(Qt.AlignHCenter | Qt.AlignBottom) item.setFlags(Qt.NoItemFlags) self.tableview.setItemDelegateForColumn(0, gui.VerticalItemDelegate()) self._set_item(2, 0, item) self.tableview.setSpan(0, 2, 1, nclasses) self.tableview.setSpan(2, 0, nclasses, 1) font = self.tablemodel.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) for i in (0, 1): for j in (0, 1): item = self._item(i, j) item.setFlags(Qt.NoItemFlags) self._set_item(i, j, item) for p, label in enumerate(self.headers): for i, j in ((1, p + 2), (p + 2, 1)): item = self._item(i, j) item.setData(label, Qt.DisplayRole) item.setFont(bold_font) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) if p < len(self.headers) - 1: item.setData("br"[j == 1], BorderRole) item.setData(QColor(192, 192, 192), BorderColorRole) self._set_item(i, j, item) hor_header = self.tableview.horizontalHeader() if len(' '.join(self.headers)) < 120: hor_header.setResizeMode(QHeaderView.ResizeToContents) else: hor_header.setDefaultSectionSize(60) self.tablemodel.setRowCount(nclasses + 3) self.tablemodel.setColumnCount(nclasses + 3) def set_results(self, results): """Set the input results.""" prev_sel_learner = self.selected_learner.copy() self.clear() self.warning() self.closeContext() data = None if results is not None and results.data is not None: data = results.data if data is not None and not data.domain.has_discrete_class: self.warning("Confusion Matrix cannot show regression results.") self.results = results self.data = data if data is not None: class_values = data.domain.class_var.values elif results is not None: raise NotImplementedError if results is None: self.report_button.setDisabled(True) else: self.report_button.setDisabled(False) nmodels = results.predicted.shape[0] self.headers = class_values + \ [unicodedata.lookup("N-ARY SUMMATION")] # NOTE: The 'learner_names' is set in 'Test Learners' widget. if hasattr(results, "learner_names"): self.learners = results.learner_names else: self.learners = [ "Learner #{}".format(i + 1) for i in range(nmodels) ] self._init_table(len(class_values)) self.openContext(data.domain.class_var) if not prev_sel_learner or prev_sel_learner[0] >= len( self.learners): self.selected_learner[:] = [0] else: self.selected_learner[:] = prev_sel_learner self._update() self._set_selection() self.unconditional_commit() def clear(self): """Reset the widget, clear controls""" self.results = None self.data = None self.tablemodel.clear() self.headers = [] # Clear learners last. This action will invoke `_learner_changed` self.learners = [] def select_correct(self): """Select the diagonal elements of the matrix""" selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(2, n): index = self.tablemodel.index(i, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def select_wrong(self): """Select the off-diagonal elements of the matrix""" selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(2, n): for j in range(i + 1, n): index = self.tablemodel.index(i, j) selection.select(index, index) index = self.tablemodel.index(j, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def select_none(self): """Reset selection""" self.tableview.selectionModel().clear() def cell_clicked(self, model_index): """Handle cell click event""" i, j = model_index.row(), model_index.column() if not i or not j: return n = self.tablemodel.rowCount() index = self.tablemodel.index selection = None if i == j == 1 or i == j == n - 1: selection = QItemSelection(index(2, 2), index(n - 1, n - 1)) elif i in (1, n - 1): selection = QItemSelection(index(2, j), index(n - 1, j)) elif j in (1, n - 1): selection = QItemSelection(index(i, 2), index(i, n - 1)) if selection is not None: self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def commit(self): """Output data instances corresponding to selected cells""" if self.results is not None and self.data is not None \ and self.selected_learner: indices = self.tableview.selectedIndexes() indices = {(ind.row() - 2, ind.column() - 2) for ind in indices} actual = self.results.actual learner_name = self.learners[self.selected_learner[0]] predicted = self.results.predicted[self.selected_learner[0]] selected = [ i for i, t in enumerate(zip(actual, predicted)) if t in indices ] row_indices = self.results.row_indices[selected] extra = [] class_var = self.data.domain.class_var metas = self.data.domain.metas if self.append_predictions: predicted = numpy.array(predicted[selected], dtype=object) extra.append(predicted.reshape(-1, 1)) var = Orange.data.DiscreteVariable( "{}({})".format(class_var.name, learner_name), class_var.values) metas = metas + (var, ) if self.append_probabilities and \ self.results.probabilities is not None: probs = self.results.probabilities[self.selected_learner[0], selected] extra.append(numpy.array(probs, dtype=object)) pvars = [ Orange.data.ContinuousVariable("p({})".format(value)) for value in class_var.values ] metas = metas + tuple(pvars) X = self.data.X[row_indices] Y = self.data.Y[row_indices] M = self.data.metas[row_indices] row_ids = self.data.ids[row_indices] M = numpy.hstack((M, ) + tuple(extra)) domain = Orange.data.Domain(self.data.domain.attributes, self.data.domain.class_vars, metas) data = Orange.data.Table.from_numpy(domain, X, Y, M) data.ids = row_ids data.name = learner_name else: data = None self.send("Selected Data", data) def _invalidate(self): indices = self.tableview.selectedIndexes() self.selection = {(ind.row() - 2, ind.column() - 2) for ind in indices} self.commit() def _set_selection(self): selection = QItemSelection() index = self.tableview.model().index for row, col in self.selection: sel = index(row + 2, col + 2) selection.select(sel, sel) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def _learner_changed(self): self._update() self._set_selection() self.commit() def _update(self): def _isinvalid(x): return isnan(x) or isinf(x) # Update the displayed confusion matrix if self.results is not None and self.selected_learner: cmatrix = confusion_matrix(self.results, self.selected_learner[0]) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) n = len(cmatrix) diag = numpy.diag_indices(n) colors = cmatrix.astype(numpy.double) colors[diag] = 0 if self.selected_quantity == 0: normalized = cmatrix.astype(numpy.int) formatstr = "{}" div = numpy.array([colors.max()]) else: if self.selected_quantity == 1: normalized = 100 * cmatrix / colsum div = colors.max(axis=0) else: normalized = 100 * cmatrix / rowsum[:, numpy.newaxis] div = colors.max(axis=1)[:, numpy.newaxis] formatstr = "{:2.1f} %" div[div == 0] = 1 colors /= div colors[diag] = normalized[diag] / normalized[diag].max() for i in range(n): for j in range(n): val = normalized[i, j] col_val = colors[i, j] item = self._item(i + 2, j + 2) item.setData( "NA" if _isinvalid(val) else formatstr.format(val), Qt.DisplayRole) bkcolor = QColor.fromHsl( [0, 240][i == j], 160, 255 if _isinvalid(col_val) else int(255 - 30 * col_val)) item.setData(QBrush(bkcolor), Qt.BackgroundRole) item.setData("trbl", BorderRole) item.setToolTip("actual: {}\npredicted: {}".format( self.headers[i], self.headers[j])) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self._set_item(i + 2, j + 2, item) bold_font = self.tablemodel.invisibleRootItem().font() bold_font.setBold(True) def _sum_item(value, border=""): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) item.setData(border, BorderRole) item.setData(QColor(192, 192, 192), BorderColorRole) return item for i in range(n): self._set_item(n + 2, i + 2, _sum_item(int(colsum[i]), "t")) self._set_item(i + 2, n + 2, _sum_item(int(rowsum[i]), "l")) self._set_item(n + 2, n + 2, _sum_item(int(rowsum.sum()))) def send_report(self): """Send report""" if self.results is not None and self.selected_learner: self.report_table( "Confusion matrix for {} (showing {})".format( self.learners[self.selected_learner[0]], self.quantities[self.selected_quantity].lower()), self.tableview)
if __name__ == "__main__": app = QApplication(sys.argv) view = QTreeView() # 1. 模型 ''' PyQt使用Model时,如果Model创建时未设置parent,则运行完退出时会报错: QObject::startTimer: QTimer can only be used with threads started with QThread ''' # model = QStandardItemModel() # 创建标准项模型 model = QStandardItemModel(view) # 创建标准项模型 # 获取模型的根项(Root Item),根项是不可见的 parentItem = model.invisibleRootItem() # 创建标准项item0,并设置显示文本,图标和工具提示 item0 = QStandardItem() item0.setText("A") pixmap0 = QPixmap(50, 50) pixmap0.fill(QColor("red")) # pixmap0.fill(Qt.red) item0.setIcon(QIcon(pixmap0)) item0.setToolTip("indexA") parentItem.appendRow(item0) # 将item0 作为根项的子项 # 将创建的标准项作为新的父项 parentItem = item0 # 创建新的标准项,它将作为item0的子项
class SubPowerWidget(QWidget): """ @brief Zeigt alle Unterkräfte in einer Baumstruktur an. """ def __init__(self, template, character, parent=None): super(SubPowerWidget, self).__init__(parent) self.__storage = template self.__character = character self.__model = QStandardItemModel() # Das ungenutzte Model dient dazu, alle Unterkräfte aufzunehmen, die ich nicht darstellen möchte. Ist einfacher, als diese im View zu verstecken. self.__modelUnused = QStandardItemModel() self._layout = QVBoxLayout() self.setLayout( self._layout ) self.__view = QTreeView() self.__view.setHeaderHidden(True) self.__view.setModel( self.__model) self._layout.addWidget(self.__view) self._typ = "Subpower" categories = self.__storage.categories(self._typ) self.__items = {} self.__rootItem = QStandardItem() self.__rootItem = self.__model.invisibleRootItem() self.__rootItemUnused = QStandardItem() self.__rootItemUnused = self.__modelUnused.invisibleRootItem() for item in categories: categoryItem = QStandardItem(item) self.__rootItem.appendRow(categoryItem) ## Ich benötige diese Items auch im ungenutzten Model. categoryItemUnused = QStandardItem(item) self.__rootItemUnused.appendRow(categoryItemUnused) traitList = list( self.__character.traits[self._typ][item].items() ) traitList.sort() for trait in traitList: traitItem = QStandardItem(trait[1].name) traitItem.setCheckable(True) ## Unhashable Type self.__items[trait[1]] = traitItem categoryItem.appendRow(traitItem) ## Funktioniert mit PySide nicht: #trait[1].availableChanged.connect(traitItem.setEnabled) ## Funktioniert auch mit PySide: trait[1].availableChanged.connect( lambda enable, item=traitItem: item.setEnabled(enable) ) trait[1].valueChanged.connect( lambda val, trait=trait[1], item=traitItem: self.__setItemValue(trait, item) ) self.__model.itemChanged.connect(self.__getItemValue) self.__character.speciesChanged.connect(self.hideOrShowToolPage) self.__character.breedChanged.connect(self.hideOrShowToolPage) self.__character.factionChanged.connect(self.hideOrShowToolPage) def __setItemValue(self, trait, item): """ Setzt den Wert der Angezeigten Items. """ if trait.value == 0: item.setCheckState(Qt.Unchecked) elif trait.value == 1: item.setCheckState(Qt.PartiallyChecked) else: item.setCheckState(Qt.Checked) def __getItemValue(self, item): """ Setzt den Wert der Eigenschaft im Speicher. """ for trait in self.__items.items(): if id(trait[1]) == id(item): trait[0].value = item.checkState() break def hideOrShowToolPage(self, res): """ Alle Eigenschaften, die nicht zur Verfügung stehen, werden verborgen, indem sie in ein anderes Model verschoben werden. \bug Möglicher Fehler in PySide: Der Aufruf von QStandardItem.model() führt beim Beenden des Programms zu einem Segmentation Fault. """ # Versteckt alle Unterkräfte, die zu gewähltem Charakter nicht passen. for item in self.__items.items(): if ( ( item[0].species and item[0].species != self.__character.species ) or ( item[0].only and self.__character.breed not in item[0].only and self.__character.faction not in item[0].only ) ): #self.__view.setRowHidden(item[1].index().row(), item[1].parent().index(), True) #Debug.debug(item[1].model()) ## Hier wird beispielsweise besagter Aufruf getätigt, der zu einem segfault führt. if item[1].model() == self.__model: parent = item[1].parent() itemUnused = parent.takeRow(item[1].index().row()) parentUnused = self.__modelUnused.findItems(parent.text())[0] parentUnused.appendRow(itemUnused) else: #self.__view.setRowHidden(item[1].index().row(), item[1].parent().index(), False) if item[1].model() == self.__modelUnused: parent = item[1].parent() itemUsed = parent.takeRow(item[1].index().row()) parentUsed = self.__model.findItems(parent.text())[0] parentUsed.appendRow(itemUsed) ## Versteckt alle Elternzeilen, wenn sie keine Kinder enthalten. for i in range(self.__model.rowCount()): categoryItem = self.__model.item(i) if categoryItem.hasChildren(): self.__view.setRowHidden(categoryItem.index().row(), self.__rootItem.index(), False) else: self.__view.setRowHidden(categoryItem.index().row(), self.__rootItem.index(), True)
class ConfigManagerDialog(ui_configmanager.Ui_ProjectInstallerDialog, QDialog): def __init__(self, roamapp, parent=None): super(ConfigManagerDialog, self).__init__(parent) self.setupUi(self) self.bar = roam.messagebaritems.MessageBar(self) self.roamapp = roamapp # Nope! self.projectwidget.roamapp = roamapp self.projectwidget.bar = self.bar self.treemodel = QStandardItemModel() self.projectList.setModel(self.treemodel) self.projectList.setHeaderHidden(True) self.projectList.selectionModel().currentChanged.connect(self.nodeselected) self.projectwidget.adjustSize() self.setWindowFlags(Qt.Window) self.projectwidget.projectupdated.connect(self.projectupdated) self.projectwidget.setaboutinfo() self.projectwidget.projects_page.projectlocationchanged.connect(self.loadprojects) self.setuprootitems() def raiseerror(self, *exinfo): self.bar.pushError(*exinfo) import roam.errors roam.errors.send_exception(exinfo) def setuprootitems(self): rootitem = self.treemodel.invisibleRootItem() self.roamnode = RoamNode() rootitem.appendRow(self.roamnode) self.projectsnode = ProjectsNode(folder=None) rootitem.appendRow(self.projectsnode) self.pluginsnode = PluginsNode() pluginpath = os.path.join(self.roamapp.apppath, "plugins") rootitem.appendRow(self.pluginsnode) self.pluginsnode.add_plugin_paths([pluginpath]) def delete_project(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.type() == Treenode.ProjectNode: self.projectwidget._closeqgisproject() title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) self.projectList.setCurrentIndex(newindex) def addprojectfolders(self, folders): self.projectwidget.projects_page.setprojectfolders(folders) def loadprojects(self, projectpath): projects = roam.project.getProjects([projectpath]) self.projectsnode.loadprojects(projects, projectsbase=projectpath) index = self.treemodel.indexFromItem(self.projectsnode) self.projectList.setCurrentIndex(index) self.projectList.expand(index) def nodeselected(self, index, _): node = index.data(Qt.UserRole) if node is None: return project = node.project if project and not self.projectwidget.project == project: # Only load the project if it's different the current one. self.projectwidget.setproject(project) node.create_children() validateresults = list(project.validate()) if validateresults: text = "Here are some reasons we found: \n\n" for message in validateresults: text += "- {} \n".format(message) self.projectwidget.reasons_label.setText(text) if node.nodetype == Treenode.RoamNode: self.projectwidget.projectlabel.setText("IntraMaps Roam Config Manager") if node.nodetype == Treenode.AddNew: try: item = node.additem() except ValueError: return newindex = self.treemodel.indexFromItem(item) self.projectList.setCurrentIndex(newindex) return self.projectwidget.projectbuttonframe.setVisible(not project is None) self.projectwidget.setpage(node.page, node) def projectupdated(self): index = self.projectList.currentIndex() node = find_node(index) node.refresh()
class AddLayerDialog(QDialog): def __init__(self, plugin): QDialog.__init__(self, plugin.iface.mainWindow()) self.plugin = plugin # set up the user interface self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.pushButton_Add.clicked.connect(self.accept) self.ui.pushButton_Close.clicked.connect(self.reject) self.ui.pushButton_Settings.clicked.connect(self.settingsClicked) self.ui.treeView.doubleClicked.connect(self.treeItemDoubleClicked) self.setupTreeView() def setupTreeView(self): # tree view header labels headers = [self.tr("Title"), self.tr("Attribution"), self.tr("Url"), self.tr("Zoom"), self.tr("Extent"), self.tr("yOrigin")] + ["index"] self.indexColumn = len(headers) - 1 self.model = QStandardItemModel(0, len(headers)) self.model.setHorizontalHeaderLabels(headers) self.serviceInfoList = [] # import layer definitions from external layer definition directory, and append it into the tree extDir = QSettings().value("/TileLayerPlugin/extDir", "", type=unicode) if extDir: self.importFromDirectory(extDir) # import layer definitions from TileLayerPlugin/layers directory, and append it into the tree pluginDir = os.path.dirname(QFile.decodeName(__file__)) self.importFromDirectory(os.path.join(pluginDir, "layers")) # model and style settings self.ui.treeView.setModel(self.model) self.ui.treeView.header().setResizeMode(QHeaderView.ResizeToContents) self.ui.treeView.expandAll() def importFromDirectory(self, path): d = QDir(path) d.setFilter(QDir.Files | QDir.Hidden) #d.setSorting(QDir.Size | QDir.Reversed) for fileInfo in d.entryInfoList(): if debug_mode == 0 and fileInfo.fileName() == "debug.tsv": continue if fileInfo.suffix().lower() == "tsv": self.importFromTsv(fileInfo.filePath()) # Line Format is: # title attribution url [yOriginTop [zmin zmax [xmin ymin xmax ymax ]]] def importFromTsv(self, filename): # append file item rootItem = self.model.invisibleRootItem() basename = os.path.basename(filename) parent = QStandardItem(os.path.splitext(basename)[0]) rootItem.appendRow([parent]) # load service info from tsv file try: with codecs.open(filename, "r", "utf-8") as f: lines = f.readlines() except Exception as e: QgsMessageLog.logMessage(self.tr("Fail to read {0}: {1}").format(basename, unicode(e)), self.tr("TileLayerPlugin")) return False for i, line in enumerate(lines): if line.startswith("#"): continue vals = line.rstrip().split("\t") nvals = len(vals) try: if nvals < 3: raise title, attribution, url = vals[0:3] if not url: raise if nvals < 4: serviceInfo = TileLayerDefinition(title, attribution, url) else: yOriginTop = int(vals[3]) if nvals < 6: serviceInfo = TileLayerDefinition(title, attribution, url, yOriginTop) else: zmin, zmax = map(int, vals[4:6]) if nvals < 10: serviceInfo = TileLayerDefinition(title, attribution, url, yOriginTop, zmin, zmax) else: bbox = BoundingBox.fromString(",".join(vals[6:10])) serviceInfo = TileLayerDefinition(title, attribution, url, yOriginTop, zmin, zmax, bbox) except: QgsMessageLog.logMessage(self.tr("Invalid line format: {} line {}").format(basename, i + 1), self.tr("TileLayerPlugin")) continue # append the service info into the tree vals = serviceInfo.toArrayForTreeView() + [len(self.serviceInfoList)] rowItems = map(QStandardItem, map(unicode, vals)) parent.appendRow(rowItems) self.serviceInfoList.append(serviceInfo) return True def selectedLayerDefinitions(self): list = [] for idx in self.ui.treeView.selectionModel().selection().indexes(): if idx.column() == self.indexColumn and idx.data() is not None: list.append(self.serviceInfoList[int(idx.data())]) return list def settingsClicked(self): if self.plugin.settings(): self.setupTreeView() def treeItemDoubleClicked(self, index): if len(self.selectedLayerDefinitions()) > 0: self.accept()
class NodeLibrary ( QtCore.QObject ) : # QtCore.QObject # # __init__ # def __init__ ( self, dirName ) : # self.dirName = dirName self.libdir = QDir ( dirName ); self.model = QStandardItemModel () self.parentItem = self.model.invisibleRootItem () print '>> NodeLibrary: libdir = %s' % dirName self.liblevel = '' self.scanLibDir () # # scanLibDir # def scanLibDir ( self ) : # process directories sortFlags = QDir.Name filterFlags = ( QDir.AllDirs | QDir.NoDotAndDotDot ) fileList = self.libdir.entryInfoList ( filterFlags, sortFlags ) for f in fileList : item = QStandardItem ( f.fileName () ) item.setEditable ( False ) item.setDragEnabled ( False ) # set bold font for folders font = item.font() font.setBold ( True ) item.setFont ( font ) item.setWhatsThis ( 'folder' ) currparent = self.parentItem self.parentItem.appendRow ( item ) self.parentItem = item currlevel = self.liblevel # store current level self.liblevel = self.liblevel + f.fileName () + '/' self.libdir.cd ( f.fileName () ) self.scanLibDir () # recurcive call itself self.liblevel = currlevel # restore current level self.libdir.cdUp () self.parentItem = currparent # process XML files filterFlags = QDir.Files fileList = self.libdir.entryInfoList ( [ '*.xml' ], filterFlags, sortFlags ) for f in fileList : self.scanXmlNodes ( f.fileName () ) # # scanXmlNodes # def scanXmlNodes ( self, filename ) : # dom = QtXml.QDomDocument ( '' ) nodeFilename = self.dirName + '/' + self.liblevel + filename file = QFile ( self.libdir.filePath ( filename ) ) if file.open ( QtCore.QIODevice.ReadOnly ) : if dom.setContent ( file ) : node = dom.documentElement () if node.nodeName () == 'nodenet' or node.nodeName () == 'node' : nodeName = node.attributes ().namedItem ( 'name' ).nodeValue () nodeType = node.attributes ().namedItem ( 'type' ).nodeValue () nodeAuthor = node.attributes ().namedItem ( 'author' ).nodeValue () nodeIcon = node.attributes ().namedItem ( 'icon' ).nodeValue () nodeHelp = '' help_tag = node.namedItem ('help') if not help_tag.isNull() : nodeHelp = help_tag.toElement ().text () item = QStandardItem ( nodeName ) item.setEditable ( False ) item.setData ( QVariant ( nodeAuthor ), QtCore.Qt.UserRole + 1 ) item.setData ( QVariant ( nodeType ), QtCore.Qt.UserRole + 2 ) item.setData ( QVariant ( nodeHelp ), QtCore.Qt.UserRole + 3 ) item.setData ( QVariant ( nodeFilename ), QtCore.Qt.UserRole + 4 ) item.setData ( QVariant ( nodeIcon ), QtCore.Qt.UserRole + 5 ) if node.nodeName () == 'nodenet' : # set Blue color for nodenet items brush = QtGui.QBrush () brush.setColor ( QtCore.Qt.blue ) item.setForeground ( brush ) item.setWhatsThis ( 'nodenet' ) else: item.setWhatsThis ( 'node' ) self.parentItem.appendRow ( item ) file.close ()
class PatternEditorWindow(QtGui.QMainWindow): # My custom signals changedPattern = QtCore.pyqtSignal(str) def __init__(self, databaseFile, lastMathML, parent=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_PatternEditorWindow() self.ui.setupUi(self) # Make the fonts bigger font = QFont() font.setPointSize(12) font.setFamily('Consolas') font.setFixedPitch(True) self.ui.databaseEditor.setFont(font) self.ui.mathmlEditor.setFont(font) self.currentFile = databaseFile.strip() # If I actually got something, then let's load the file in if len(self.currentFile) > 0: try: f = open(self.currentFile, 'r') contents = f.read() f.close() self.ui.databaseEditor.setText(contents) except IOError: print 'Database file doesn\'t exist! Resetting to nothing...' self.currentFile = '' try: self.mathTTS = MathTTS(databaseFile) except Exception: self.mathTTS = None self.stagesModel = QStandardItemModel() self.stageTrees = [] self.updateStagesModel() self.ui.mathmlEditor.setText(unicode(lastMathML)) self.connect_signals() def connect_signals(self): self.ui.speakButton.clicked.connect(self.speakButton_clicked) self.ui.expandAllButton.clicked.connect(self.expandButton_clicked) self.ui.collapseAllButton.clicked.connect(self.collapseButton_clicked) self.ui.actionNew.triggered.connect(self.actionNew_triggered) self.ui.actionOpen.triggered.connect(self.actionOpen_triggered) self.ui.actionOpen_MathML.triggered.connect(self.actionOpen_MathML_triggered) self.ui.actionSave.triggered.connect(self.actionSave_triggered) self.ui.actionSave_As.triggered.connect(self.actionSaveAs_triggered) self.ui.actionQuit.triggered.connect(self.actionQuit_triggered) def speakButton_clicked(self): print 'Speak button pressed!' self.stageTrees = [] stuff = self.mathTTS.parse(unicode(self.ui.mathmlEditor.text()), stageSink=self.stageTrees) # Output what the text was self.ui.outputText.setPlainText(stuff) # Turn my stages into a tree model with extra happy! self.updateStagesModel() def expandButton_clicked(self): self.ui.stagesTreeView.expandAll() def collapseButton_clicked(self): self.ui.stagesTreeView.collapseAll() def updateStagesModel(self): ''' Used to update the tree model for the Stages tree ''' self.stagesModel.clear() parent = self.stagesModel.invisibleRootItem(); i = 0 for stage in self.stageTrees: i += 1 stageItem = QStandardItem(stage.replaceVariable) stageItem.setEditable(False) item = QStandardItem(self._buildTreeStringLabel(stage)) item.setEditable(False) self._addChildrenToParent(stage, item) stageItem.appendRow(item) parent.appendRow(stageItem) self.ui.stagesTreeView.setModel(self.stagesModel) def _addChildrenToParent(self, replaceParentNode, standardItemParent): if len(replaceParentNode.expressions) > 0: for e in replaceParentNode.expressions: if isinstance(e, list): listItem = QStandardItem('+') listItem.setEditable(False) for e2 in e: item = QStandardItem(self._buildTreeStringLabel(e2)) item.setEditable(False) self._addChildrenToParent(e2, item) listItem.appendRow(item) standardItemParent.appendRow(listItem) else: item = QStandardItem(self._buildTreeStringLabel(e)) item.setEditable(False) self._addChildrenToParent(e, item) standardItemParent.appendRow(item) if len(replaceParentNode.children) > 0: for c in replaceParentNode.children: item = QStandardItem(self._buildTreeStringLabel(c)) item.setEditable(False) self._addChildrenToParent(c, item) standardItemParent.appendRow(item) def _buildTreeStringLabel(self, replaceTree): ''' Builds the label for the stages tree based on the replace tree given ''' myString = replaceTree.value + ' (' + replaceTree._getTypeString() + ')' if replaceTree.parent != None: myString += ' -> Parent: ' myString += replaceTree.parent.value + ' (' + replaceTree.parent._getTypeString() + ')' return myString def actionNew_triggered(self): print 'New was triggered!' self.ui.databaseEditor.clear() self.currentFile = '' self.changedPattern.emit(self.currentFile) self.mathTTS.setPatternDatabase(self.currentFile) def actionOpen_triggered(self): print 'Open was triggered!' newFile = QtGui.QFileDialog.getOpenFileName(self, 'Open pattern database file...') if len(newFile) > 0: self.currentFile = newFile f = open(self.currentFile, 'r') contents = f.read() f.close() self.ui.databaseEditor.setText(contents) self.changedPattern.emit(self.currentFile) self.mathTTS.setPatternDatabase(self.currentFile) def actionOpen_MathML_triggered(self): print 'Open MathML was triggered!' newFile = QtGui.QFileDialog.getOpenFileName(self, 'Open MathML file...') if len(newFile) > 0: f = open(newFile, 'r') contents = f.read() f.close() self.ui.mathmlEditor.setText(contents) def actionSave_triggered(self): print 'Save was triggered!' if len(self.currentFile) == 0: # Perform a Save As instead self.actionSaveAs_triggered() else: f = open(self.currentFile, 'w') f.write(unicode(self.ui.databaseEditor.text())) f.close() self.changedPattern.emit(self.currentFile) if self.mathTTS == None: try: self.mathTTS = MathTTS(self.currentFile) except Exception: pass else: self.mathTTS.setPatternDatabase(self.currentFile) def actionSaveAs_triggered(self): print 'Save As was triggered!' newFileName = QtGui.QFileDialog.getSaveFileName(self, 'Save pattern database file...') if len(newFileName) > 0: self.currentFile = newFileName f = open(self.currentFile, 'w') f.write(unicode(self.ui.databaseEditor.text())) f.close() self.changedPattern.emit(self.currentFile) self.mathTTS.setPatternDatabase(self.currentFile) def actionQuit_triggered(self): print 'Quit was triggered!'
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> ' + Qt.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(buffer(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', u'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', u'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 = set(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', u'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 ConfigManagerDialog(ui_configmanager.Ui_ProjectInstallerDialog, QDialog): def __init__(self, roamapp, parent=None): super(ConfigManagerDialog, self).__init__(parent) self.setupUi(self) self.bar = roam.messagebaritems.MessageBar(self) self.roamapp = roamapp self.reloadingProject = False self.loadedProject = None self.projectpath = None # Nope! self.projectwidget.roamapp = roamapp self.projectwidget.bar = self.bar self.treemodel = QStandardItemModel() self.projectList.setModel(self.treemodel) self.projectList.setHeaderHidden(True) self.projectList.selectionModel().currentChanged.connect( self.nodeselected) self.projectwidget.adjustSize() self.setWindowFlags(Qt.Window) self.projectwidget.projectupdated.connect(self.projectupdated) self.projectwidget.projectloaded.connect(self.projectLoaded) self.projectwidget.setaboutinfo() self.projectwidget.projects_page.projectlocationchanged.connect( self.loadprojects) self.setuprootitems() ConfigEvents.deleteForm.connect(self.delete_form) def closeEvent(self, closeevent): self.save_page_config() closeevent.accept() def raiseerror(self, *exinfo): self.bar.pushError(*exinfo) import roam.errors roam.errors.send_exception(exinfo) def setuprootitems(self): rootitem = self.treemodel.invisibleRootItem() self.roamnode = RoamNode() rootitem.appendRow(self.roamnode) self.datanode = DataNode(folder=None) rootitem.appendRow(self.datanode) self.projectsnode = ProjectsNode(folder=None) rootitem.appendRow(self.projectsnode) self.publishnode = PublishNode(folder=None) rootitem.appendRow(self.publishnode) self.pluginsnode = PluginsNode() pluginpath = os.path.join(self.roamapp.apppath, "plugins") rootitem.appendRow(self.pluginsnode) self.pluginsnode.add_plugin_paths([pluginpath]) def delete_form(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if not node.type() == Treenode.FormNode: return title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes print "Delete" if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) print parentindex self.projectList.setCurrentIndex(parentindex) def delete_project(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.type() == Treenode.ProjectNode: self.projectwidget._closeqgisproject() title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) self.projectList.setCurrentIndex(newindex) def addprojectfolders(self, folders): self.projectwidget.projects_page.setprojectfolders(folders) @property def active_project_folder(self): return self.projectpath @active_project_folder.setter def active_project_folder(self, value): self.projectpath = value pass def loadprojects(self, projectpath): self.active_project_folder = projectpath projects = roam.project.getProjects([projectpath]) self.projectsnode.loadprojects(projects, projectsbase=projectpath) index = self.treemodel.indexFromItem(self.projectsnode) self.projectList.setCurrentIndex(index) self.projectList.expand(index) def projectLoaded(self, project): roam.utils.info("Project loaded: {}".format(project.name)) node = self.projectsnode.find_by_name(project.name) node.create_children() self.projectwidget.setpage(node.page, node, refreshingProject=True) self.reloadingProject = False self.loadedProject = project self.projectList.setExpanded(node.index(), True) def nodeselected(self, index, last, reloadProject=False): node = index.data(Qt.UserRole) if node is None: return project = node.project if project: validateresults = list(project.validate()) if validateresults: text = "Here are some reasons we found: \n\n" for message in validateresults: text += "- {} \n".format(message) self.projectwidget.reasons_label.setText(text) return if node.nodetype == Treenode.ProjectNode and reloadProject: self.reloadingProject = True self.projectwidget.setproject(project) return if project and self.loadedProject != project: # Only load the project if it's different the current one. if self.loadedProject: lastnode = self.projectsnode.find_by_name( self.loadedProject.name) self.projectList.setExpanded(lastnode.index(), False) ## We are closing the open project at this point. Watch for null ref after this. self.projectwidget.setproject(project) self.projectwidget.setpage(node.page, node) return else: self.projectwidget.setpage(node.page, node) if node.nodetype == Treenode.AddNew: try: item = node.additem() except ValueError: return newindex = self.treemodel.indexFromItem(item) self.projectList.setCurrentIndex(newindex) return def save_page_config(self): """ Save the current page config """ self.projectwidget.savePage(closing=True) def projectupdated(self, project): print "PROJECT UPDATED" node = self.projectsnode.find_by_name(project.name) self.projectList.selectionModel().select( node.index(), QItemSelectionModel.ClearAndSelect) self.nodeselected(node.index(), None, reloadProject=True)
class SetupDialog(QDialog, Ui_SetupDialog): """ Function and Event handling class for the Ui_SetupDialog. """ def __init__(self, parent): QDialog.__init__(self, parent) self._gui_logger = GUILogger("GUILogger", logging.INFO) self._gui_job = None EventLogger.add_logger(self._gui_logger) # FIXME better way to find interval and uids in tree_widget?! self.__tree_interval_tooltip = "Update interval in seconds" self.__tree_uid_tooltip = "UID cannot be empty" self.data_logger_thread = None self.tab_debug_warning = False self.device_dialog = None self.host_infos = None self.last_host = None self.host_index_changing = None 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.widget_initialization() self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/start-icon.png'))) timestamp = int(time.time()) self.edit_csv_file_name.setText(os.path.join(get_home_path(), 'logger_data_{0}.csv'.format(timestamp))) self.edit_log_file_name.setText(os.path.join(get_home_path(), 'logger_debug_{0}.log'.format(timestamp))) self.combo_data_time_format.addItem(utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_data_time_format.addItem(utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_data_time_format.addItem(utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso') self.combo_data_time_format.addItem(utils.timestamp_to_unix(timestamp) + ' (Unix)', 'unix') self.combo_debug_time_format.addItem(utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_debug_time_format.addItem(utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_debug_time_format.addItem(utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso') self.combo_debug_time_format.addItem(utils.timestamp_to_unix(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 self.update_ui_state() def update_ui_state(self): data_to_csv_file = self.check_data_to_csv_file.isChecked() debug_to_log_file = self.check_debug_to_log_file.isChecked() 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 widget_initialization(self): """ Sets default values for some widgets """ # Login data self.host_info_initialization() self.signal_initialization() 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.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.connect(self._gui_logger, QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE), self.add_debug_message) self.connect(self._gui_logger, QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE_TAB_HIGHLIGHT), self.highlight_debug_tab) self.combo_host.currentIndexChanged.connect(self._host_index_changed) self.spin_port.valueChanged.connect(self._port_changed) def host_info_initialization(self): """ initialize host by getting information out of brickv.config """ self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT) self.host_index_changing = True for host_info in self.host_infos: self.combo_host.addItem(host_info.host) self.last_host = None self.combo_host.setCurrentIndex(0) self.spin_port.setValue(self.host_infos[0].port) self.host_index_changing = False 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.connect(self._gui_job, QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA), self.table_add_row) self.data_logger_thread = main.main(None, GuiConfigHandler.create_config(self), self._gui_job) 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.disconnect(self._gui_job, QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA), 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 btn_save_config_clicked(self): filename = get_save_file_name(get_main_window(), '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(get_main_window(), '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(get_main_window(), 'Load Config', get_home_path(), 'JSON Files (*.json)') if len(filename) == 0: return config = load_and_validate_config(filename) if config == None: QMessageBox.warning(get_main_window(), '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(get_main_window(), '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(get_main_window(), '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.currentWidget().objectName() != self.tab_debug.objectName(): 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. """ from PyQt4.QtGui import QIcon 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): """ Persists host information changes like in brickv.mainwindow Changes port if the host was changed """ if i < 0: return self.host_index_changing = True self.spin_port.setValue(self.host_infos[i].port) self.host_index_changing = False def _port_changed(self, value): """ Persists host information changes like in brickv.mainwindow """ if self.host_index_changing: return i = self.combo_host.currentIndex() if i < 0: return self.host_infos[i].port = self.spin_port.value() def update_setup_tab(self, config): EventLogger.debug('Updating setup tab from config') self.combo_host.setEditText(config['hosts']['default']['name']) self.spin_port.setValue(config['hosts']['default']['port']) self.combo_data_time_format.setCurrentIndex(max(self.combo_data_time_format.findData(config['data']['time_format']), 0)) self.check_data_to_csv_file.setChecked(config['data']['csv']['enabled']) self.edit_csv_file_name.setText(config['data']['csv']['file_name'].decode('utf-8')) 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'].decode('utf-8')) 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 = QSpinBox() spinbox_interval.setRange(0, (1 << 31) - 1) spinbox_interval.setSingleStep(1) spinbox_interval.setValue(device['values'][value_spec['name']]['interval']) spinbox_interval.setSuffix(' seconds') 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].decode('utf-8'), option_value_spec[1]) widget_option_value.setCurrentIndex(widget_option_value.findText(device['options'][option_spec['name']]['value'].decode('utf-8'))) 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.currentWidget().objectName() != self.tab_debug.objectName(): self.tab_debug_warning = True self.tab_set(self.tab_widget.indexOf(self.tab_debug), QColor(255, 0, 0), os.path.join(get_resources_path(), "warning-icon.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.decode('utf-8'))]) 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()
class Model: """ class model """ def __init__(self, view, config, parent=None): """ Constructor for class model @param view: @param config: """ self.parent = parent self.view = view self.config = config self.pageModel = QStandardItemModel() self.view.listView.setModel(self.pageModel) def createConnector(self): self.view.statusBar().showMessage('connecting...') self.c = Connector(self.view.serverLineEdit.text(), self.view.userLineEdit.text(), self.view.passwdLineEdit.text(), '') print (self.c.getWikiVersion()) self.allPages = self.c.getAllPages() if (self.allPages != None): self.view.statusBar().showMessage('connected.') parentItem = self.pageModel.invisibleRootItem() for i in self.allPages: parentItem.appendRow(QStandardItem(i['id'])) self.connected = True else: self.view.statusBar().showMessage("Couldn't get pages.") print ("Couldn't get pages.") def copySettings(self): self.config.settings['app_x'] = self.view.pos().x() self.config.settings['app_y'] = self.view.pos().y() self.config.settings['app_w'] = self.view.size().width() self.config.settings['app_h'] = self.view.size().height() self.config.settings['user'] = str(self.view.userLineEdit.text()) self.config.settings['serverAddress'] = str(self.view.serverLineEdit.text()) self.config.writeConfig() def readyToSave(self): if (self.connected): self.view.save.setDisabled(False) def displayPage(self, newSelection, oldSelection): self.pageIndex = self.view.listView.selectionModel().selectedIndexes() if (self.pageIndex != None): self.pageName = self.pageIndex[0].data().toString() if (self.pageName != None): print ('Selected item: ' + self.pageName) self.view.statusBar().showMessage('Loading page ' + str(self.pageName)) self.view.textEdit.setText(self.c.getPageText(self.pageName)) def saveCurrentPage(self): attr = QVariant() if (self.pageName != None): self.c.setPageText(self.pageName, self.view.textEdit.document().toPlainText(), attr) self.view.statusBar().showMessage('Page ' + str(self.pageName) + ' saved.') def insertBoldText(self): print ('insert bold text or change text to bold') self.textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('**' + str(self.textCursor.selectedText()) + '**') # self.textCursor.setPosition(self.textCursor.position() - 2) # print self.textCursor.movePosition(QTextCursor.Left, 2) def insertItalicText(self): print ('insert italic text or change text to bold') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('//' + str(textCursor.selectedText()) + '//') def insertH1Text(self): print ('insert H1 text or change text to H1') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('======' + str(textCursor.selectedText()) + '======') def insertH2Text(self): print ('insert H2 text or change text to H2') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('=====' + str(textCursor.selectedText()) + '=====') def insertH3Text(self): print ('insert H3 text or change text to H3') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('====' + str(textCursor.selectedText()) + '====') def insertH4Text(self): print ('insert H4 text or change text to H4') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('===' + str(textCursor.selectedText()) + '===') def insertH5Text(self): print ('insert H5 text or change text to H5') textCursor = self.view.textEdit.textCursor() self.view.textEdit.insertPlainText('==' + str(textCursor.selectedText()) + '==') def searchFor(self): print ('TODO: search for pages')
class OWConfusionMatrix(widget.OWWidget): """Confusion matrix widget""" name = "Confusion Matrix" description = "Display a confusion matrix constructed from " \ "the results of classifier evaluations." icon = "icons/ConfusionMatrix.svg" priority = 1001 inputs = [("Evaluation Results", Orange.evaluation.Results, "set_results")] outputs = [("Selected Data", Orange.data.Table)] quantities = ["Number of instances", "Proportion of predicted", "Proportion of actual"] settingsHandler = settings.ClassValuesContextHandler() selected_learner = settings.Setting([0], schema_only=True) selection = settings.ContextSetting(set()) selected_quantity = settings.Setting(0) append_predictions = settings.Setting(True) append_probabilities = settings.Setting(False) autocommit = settings.Setting(True) UserAdviceMessages = [ widget.Message( "Clicking on cells or in headers outputs the corresponding " "data instances", "click_cell")] def __init__(self): super().__init__() self.data = None self.results = None self.learners = [] self.headers = [] box = gui.vBox(self.controlArea, "Learners") self.learners_box = gui.listBox( box, self, "selected_learner", "learners", callback=self._learner_changed ) box = gui.vBox(self.controlArea, "Show") gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.vBox(self.controlArea, "Select") gui.button(box, self, "Select Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Select Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "Clear Selection", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.vBox(self.controlArea, "Output") gui.checkBox(box, self, "append_predictions", "Predictions", callback=self._invalidate) gui.checkBox(box, self, "append_probabilities", "Probabilities", callback=self._invalidate) gui.auto_commit(self.controlArea, self, "autocommit", "Send Selected", "Send Automatically") grid = QGridLayout() self.tablemodel = QStandardItemModel(self) view = self.tableview = QTableView( editTriggers=QTableView.NoEditTriggers) view.setModel(self.tablemodel) view.horizontalHeader().hide() view.verticalHeader().hide() view.horizontalHeader().setMinimumSectionSize(60) view.selectionModel().selectionChanged.connect(self._invalidate) view.setShowGrid(False) view.setItemDelegate(BorderedItemDelegate(Qt.white)) view.clicked.connect(self.cell_clicked) grid.addWidget(view, 0, 0) self.mainArea.layout().addLayout(grid) def sizeHint(self): """Initial size""" return QSize(750, 490) def _item(self, i, j): return self.tablemodel.item(i, j) or QStandardItem() def _set_item(self, i, j, item): self.tablemodel.setItem(i, j, item) def _init_table(self, nclasses): item = self._item(0, 2) item.setData("Predicted", Qt.DisplayRole) item.setTextAlignment(Qt.AlignCenter) item.setFlags(Qt.NoItemFlags) self._set_item(0, 2, item) item = self._item(2, 0) item.setData("Actual", Qt.DisplayRole) item.setTextAlignment(Qt.AlignHCenter | Qt.AlignBottom) item.setFlags(Qt.NoItemFlags) self.tableview.setItemDelegateForColumn(0, gui.VerticalItemDelegate()) self._set_item(2, 0, item) self.tableview.setSpan(0, 2, 1, nclasses) self.tableview.setSpan(2, 0, nclasses, 1) font = self.tablemodel.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) for i in (0, 1): for j in (0, 1): item = self._item(i, j) item.setFlags(Qt.NoItemFlags) self._set_item(i, j, item) for p, label in enumerate(self.headers): for i, j in ((1, p + 2), (p + 2, 1)): item = self._item(i, j) item.setData(label, Qt.DisplayRole) item.setFont(bold_font) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) if p < len(self.headers) - 1: item.setData("br"[j == 1], BorderRole) item.setData(QColor(192, 192, 192), BorderColorRole) self._set_item(i, j, item) hor_header = self.tableview.horizontalHeader() if len(' '.join(self.headers)) < 120: hor_header.setResizeMode(QHeaderView.ResizeToContents) else: hor_header.setDefaultSectionSize(60) self.tablemodel.setRowCount(nclasses + 3) self.tablemodel.setColumnCount(nclasses + 3) def set_results(self, results): """Set the input results.""" prev_sel_learner = self.selected_learner.copy() self.clear() self.warning() self.closeContext() data = None if results is not None and results.data is not None: data = results.data if data is not None and not data.domain.has_discrete_class: self.warning("Confusion Matrix cannot show regression results.") self.results = results self.data = data if data is not None: class_values = data.domain.class_var.values elif results is not None: raise NotImplementedError if results is None: self.report_button.setDisabled(True) else: self.report_button.setDisabled(False) nmodels = results.predicted.shape[0] self.headers = class_values + \ [unicodedata.lookup("N-ARY SUMMATION")] # NOTE: The 'learner_names' is set in 'Test Learners' widget. if hasattr(results, "learner_names"): self.learners = results.learner_names else: self.learners = ["Learner #{}".format(i + 1) for i in range(nmodels)] self._init_table(len(class_values)) self.openContext(data.domain.class_var) if not prev_sel_learner or prev_sel_learner[0] >= len(self.learners): self.selected_learner[:] = [0] else: self.selected_learner[:] = prev_sel_learner self._update() self._set_selection() self.unconditional_commit() def clear(self): """Reset the widget, clear controls""" self.results = None self.data = None self.tablemodel.clear() self.headers = [] # Clear learners last. This action will invoke `_learner_changed` self.learners = [] def select_correct(self): """Select the diagonal elements of the matrix""" selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(2, n): index = self.tablemodel.index(i, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def select_wrong(self): """Select the off-diagonal elements of the matrix""" selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(2, n): for j in range(i + 1, n): index = self.tablemodel.index(i, j) selection.select(index, index) index = self.tablemodel.index(j, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def select_none(self): """Reset selection""" self.tableview.selectionModel().clear() def cell_clicked(self, model_index): """Handle cell click event""" i, j = model_index.row(), model_index.column() if not i or not j: return n = self.tablemodel.rowCount() index = self.tablemodel.index selection = None if i == j == 1 or i == j == n - 1: selection = QItemSelection(index(2, 2), index(n - 1, n - 1)) elif i in (1, n - 1): selection = QItemSelection(index(2, j), index(n - 1, j)) elif j in (1, n - 1): selection = QItemSelection(index(i, 2), index(i, n - 1)) if selection is not None: self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def commit(self): """Output data instances corresponding to selected cells""" if self.results is not None and self.data is not None \ and self.selected_learner: indices = self.tableview.selectedIndexes() indices = {(ind.row() - 2, ind.column() - 2) for ind in indices} actual = self.results.actual learner_name = self.learners[self.selected_learner[0]] predicted = self.results.predicted[self.selected_learner[0]] selected = [i for i, t in enumerate(zip(actual, predicted)) if t in indices] row_indices = self.results.row_indices[selected] extra = [] class_var = self.data.domain.class_var metas = self.data.domain.metas if self.append_predictions: predicted = numpy.array(predicted[selected], dtype=object) extra.append(predicted.reshape(-1, 1)) var = Orange.data.DiscreteVariable( "{}({})".format(class_var.name, learner_name), class_var.values ) metas = metas + (var,) if self.append_probabilities and \ self.results.probabilities is not None: probs = self.results.probabilities[self.selected_learner[0], selected] extra.append(numpy.array(probs, dtype=object)) pvars = [Orange.data.ContinuousVariable("p({})".format(value)) for value in class_var.values] metas = metas + tuple(pvars) X = self.data.X[row_indices] Y = self.data.Y[row_indices] M = self.data.metas[row_indices] row_ids = self.data.ids[row_indices] M = numpy.hstack((M,) + tuple(extra)) domain = Orange.data.Domain( self.data.domain.attributes, self.data.domain.class_vars, metas ) data = Orange.data.Table.from_numpy(domain, X, Y, M) data.ids = row_ids data.name = learner_name else: data = None self.send("Selected Data", data) def _invalidate(self): indices = self.tableview.selectedIndexes() self.selection = {(ind.row() - 2, ind.column() - 2) for ind in indices} self.commit() def _set_selection(self): selection = QItemSelection() index = self.tableview.model().index for row, col in self.selection: sel = index(row + 2, col + 2) selection.select(sel, sel) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def _learner_changed(self): self._update() self._set_selection() self.commit() def _update(self): def _isinvalid(x): return isnan(x) or isinf(x) # Update the displayed confusion matrix if self.results is not None and self.selected_learner: cmatrix = confusion_matrix(self.results, self.selected_learner[0]) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) n = len(cmatrix) diag = numpy.diag_indices(n) colors = cmatrix.astype(numpy.double) colors[diag] = 0 if self.selected_quantity == 0: normalized = cmatrix.astype(numpy.int) formatstr = "{}" div = numpy.array([colors.max()]) else: if self.selected_quantity == 1: normalized = 100 * cmatrix / colsum div = colors.max(axis=0) else: normalized = 100 * cmatrix / rowsum[:, numpy.newaxis] div = colors.max(axis=1)[:, numpy.newaxis] formatstr = "{:2.1f} %" div[div == 0] = 1 colors /= div colors[diag] = normalized[diag] / normalized[diag].max() for i in range(n): for j in range(n): val = normalized[i, j] col_val = colors[i, j] item = self._item(i + 2, j + 2) item.setData( "NA" if _isinvalid(val) else formatstr.format(val), Qt.DisplayRole) bkcolor = QColor.fromHsl( [0, 240][i == j], 160, 255 if _isinvalid(col_val) else int(255 - 30 * col_val)) item.setData(QBrush(bkcolor), Qt.BackgroundRole) item.setData("trbl", BorderRole) item.setToolTip("actual: {}\npredicted: {}".format( self.headers[i], self.headers[j])) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self._set_item(i + 2, j + 2, item) bold_font = self.tablemodel.invisibleRootItem().font() bold_font.setBold(True) def _sum_item(value, border=""): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) item.setData(border, BorderRole) item.setData(QColor(192, 192, 192), BorderColorRole) return item for i in range(n): self._set_item(n + 2, i + 2, _sum_item(int(colsum[i]), "t")) self._set_item(i + 2, n + 2, _sum_item(int(rowsum[i]), "l")) self._set_item(n + 2, n + 2, _sum_item(int(rowsum.sum()))) def send_report(self): """Send report""" if self.results is not None and self.selected_learner: self.report_table( "Confusion matrix for {} (showing {})". format(self.learners[self.selected_learner[0]], self.quantities[self.selected_quantity].lower()), self.tableview)
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_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_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> ' + Qt.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(buffer(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', u'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 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 = set(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', u'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 ConfigManagerDialog(ui_configmanager.Ui_ProjectInstallerDialog, QDialog): def __init__(self, parent=None): super(ConfigManagerDialog, self).__init__(parent) self.setupUi(self) self.bar = roam.messagebaritems.MessageBar(self) self.projectwidget.bar = self.bar self.treemodel = QStandardItemModel() self.projectList.setModel(self.treemodel) self.projectList.setHeaderHidden(True) self.projectList.selectionModel().currentChanged.connect(self.nodeselected) self.projectwidget.adjustSize() self.setWindowFlags(Qt.Window) self.newProjectButton.pressed.connect(self.newproject) self.removeProjectButton.pressed.connect(self.deletebuttonpressed) self.projectwidget.projectupdated.connect(self.projectupdated) self.projectwidget.projectsaved.connect(self.projectupdated) self.projectwidget.projectloaded.connect(self.updateformsnode) self.projectwidget.selectlayersupdated.connect(self.updateformsnode) self.projectwidget.setaboutinfo() self.projectwidget.projects_page.newproject.connect(self.newproject) self.projectwidget.projects_page.projectlocationchanged.connect(self.loadprojects) self.setuprootitems() def updateformsnode(self, *args): haslayers = self.projectwidget.checkcapturelayers() index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.nodetype == Treenode.FormsNode: self.newProjectButton.setEnabled(haslayers) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) self.bar.pushError('Seems something has gone wrong. Press for more details', info) def setuprootitems(self): rootitem = self.treemodel.invisibleRootItem() self.roamnode = RoamNode() rootitem.appendRow(self.roamnode) self.projectsnode = ProjectsNode(folder=None) rootitem.appendRow(self.projectsnode) def newproject(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node and node.canadd: try: item = node.additem() except ValueError: return newindex = self.treemodel.indexFromItem(item) self.projectList.setCurrentIndex(newindex) def deletebuttonpressed(self): index = self.projectList.currentIndex() node = index.data(Qt.UserRole) if node.type() == Treenode.ProjectNode: self.projectwidget._closeqgisproject() title, removemessage = node.removemessage delete = node.canremove if node.canremove and removemessage: button = QMessageBox.warning(self, title, removemessage, QMessageBox.Yes | QMessageBox.No) delete = button == QMessageBox.Yes if delete: parentindex = index.parent() newindex = self.treemodel.index(index.row(), 0, parentindex) if parentindex.isValid(): parent = parentindex.data(Qt.UserRole) parent.delete(index.row()) self.projectList.setCurrentIndex(newindex) def addprojectfolders(self, folders): self.projectwidget.projects_page.setprojectfolders(folders) def loadprojects(self, projectpath): projects = roam.project.getProjects([projectpath]) self.projectsnode.loadprojects(projects, projectsbase=projectpath) index = self.treemodel.indexFromItem(self.projectsnode) self.projectList.setCurrentIndex(index) self.projectList.expand(index) def nodeselected(self, index, _): node = index.data(Qt.UserRole) if node is None: return self.projectwidget.setpage(node.page) self.removeProjectButton.setEnabled(node.canremove) self.newProjectButton.setEnabled(node.canadd) #self.newProjectButton.setText(node.addtext) #self.removeProjectButton.setText(node.removetext) project = node.project if project and not self.projectwidget.project == project: # Only load the project if it's different the current one. self.projectwidget.setproject(project) validateresults = list(project.validate()) if validateresults: text = "Here are some reasons we found: \n\n" for message in validateresults: text += "- {} \n".format(message) self.projectwidget.reasons_label.setText(text) if node.nodetype == Treenode.FormNode: self.projectwidget.setform(node.form) elif node.nodetype == Treenode.RoamNode: self.projectwidget.projectlabel.setText("IntraMaps Roam Config Manager") elif node.nodetype == Treenode.MapNode: self.projectwidget.loadmap() elif node.nodetype == Treenode.FormsNode: haslayers = self.projectwidget.checkcapturelayers() self.newProjectButton.setEnabled(haslayers) self.projectwidget.projectbuttonframe.setVisible(not project is None) def projectupdated(self): index = self.projectList.currentIndex() self.treemodel.dataChanged.emit(index, index)
class SetupDialog(QDialog, Ui_SetupDialog): """ Function and Event handling class for the Ui_SetupDialog. """ def __init__(self, parent): QDialog.__init__(self, parent) self._gui_logger = GUILogger("GUILogger", logging.INFO) self._gui_job = None EventLogger.add_logger(self._gui_logger) # FIXME better way to find interval and uids in tree_widget?! self.__tree_interval_tooltip = "Update interval in seconds" self.__tree_uid_tooltip = "UID cannot be empty" self.data_logger_thread = None self.tab_debug_warning = False self.device_dialog = None self.host_infos = None self.last_host = None self.host_index_changing = None 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.widget_initialization() self.btn_start_logging.setIcon( QIcon(load_pixmap('data_logger/start-icon.png'))) timestamp = int(time.time()) self.edit_csv_file_name.setText( os.path.join(get_home_path(), 'logger_data_{0}.csv'.format(timestamp))) self.edit_log_file_name.setText( os.path.join(get_home_path(), 'logger_debug_{0}.log'.format(timestamp))) self.combo_data_time_format.addItem( utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_data_time_format.addItem( utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_data_time_format.addItem( utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso') self.combo_data_time_format.addItem( utils.timestamp_to_unix(timestamp) + ' (Unix)', 'unix') self.combo_debug_time_format.addItem( utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de') self.combo_debug_time_format.addItem( utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us') self.combo_debug_time_format.addItem( utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso') self.combo_debug_time_format.addItem( utils.timestamp_to_unix(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 self.update_ui_state() def update_ui_state(self): data_to_csv_file = self.check_data_to_csv_file.isChecked() debug_to_log_file = self.check_debug_to_log_file.isChecked() 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 widget_initialization(self): """ Sets default values for some widgets """ # Login data self.host_info_initialization() self.signal_initialization() 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.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.connect(self._gui_logger, QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE), self.add_debug_message) self.connect(self._gui_logger, QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE_TAB_HIGHLIGHT), self.highlight_debug_tab) self.combo_host.currentIndexChanged.connect(self._host_index_changed) self.spin_port.valueChanged.connect(self._port_changed) def host_info_initialization(self): """ initialize host by getting information out of brickv.config """ self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT) self.host_index_changing = True for host_info in self.host_infos: self.combo_host.addItem(host_info.host) self.last_host = None self.combo_host.setCurrentIndex(0) self.spin_port.setValue(self.host_infos[0].port) self.host_index_changing = False 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.connect(self._gui_job, QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA), self.table_add_row) self.data_logger_thread = main.main( None, GuiConfigHandler.create_config(self), self._gui_job) 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.disconnect(self._gui_job, QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA), 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 btn_save_config_clicked(self): filename = get_save_file_name(get_main_window(), '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( get_main_window(), '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(get_main_window(), 'Load Config', get_home_path(), 'JSON Files (*.json)') if len(filename) == 0: return config = load_and_validate_config(filename) if config == None: QMessageBox.warning( get_main_window(), '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(get_main_window(), '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(get_main_window(), '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.currentWidget( ).objectName() != self.tab_debug.objectName(): 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. """ from PyQt4.QtGui import QIcon 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): """ Persists host information changes like in brickv.mainwindow Changes port if the host was changed """ if i < 0: return self.host_index_changing = True self.spin_port.setValue(self.host_infos[i].port) self.host_index_changing = False def _port_changed(self, value): """ Persists host information changes like in brickv.mainwindow """ if self.host_index_changing: return i = self.combo_host.currentIndex() if i < 0: return self.host_infos[i].port = self.spin_port.value() def update_setup_tab(self, config): EventLogger.debug('Updating setup tab from config') self.combo_host.setEditText(config['hosts']['default']['name']) self.spin_port.setValue(config['hosts']['default']['port']) self.combo_data_time_format.setCurrentIndex( max( self.combo_data_time_format.findData( config['data']['time_format']), 0)) self.check_data_to_csv_file.setChecked( config['data']['csv']['enabled']) self.edit_csv_file_name.setText( config['data']['csv']['file_name'].decode('utf-8')) 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'].decode('utf-8')) 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 = QSpinBox() spinbox_interval.setRange(0, (1 << 31) - 1) spinbox_interval.setSingleStep(1) spinbox_interval.setValue( device['values'][value_spec['name']]['interval']) spinbox_interval.setSuffix(' seconds') 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].decode('utf-8'), option_value_spec[1]) widget_option_value.setCurrentIndex( widget_option_value.findText(device['options'][ option_spec['name']]['value'].decode('utf-8'))) 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.currentWidget( ).objectName() != self.tab_debug.objectName(): self.tab_debug_warning = True self.tab_set( self.tab_widget.indexOf(self.tab_debug), QColor(255, 0, 0), os.path.join(get_resources_path(), "warning-icon.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.decode('utf-8')) ]) 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()
class ConfigDialog(BASE, WIDGET): def __init__(self, toolbox): super(ConfigDialog, self).__init__(None) self.setupUi(self) self.toolbox = toolbox self.groupIcon = QIcon() self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off) self.groupIcon.addPixmap(self.style().standardPixmap( QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(self.tr('Search...')) self.model = QStandardItemModel() self.tree.setModel(self.model) self.delegate = SettingDelegate() self.tree.setItemDelegateForColumn(1, self.delegate) self.searchBox.textChanged.connect(self.fillTree) self.fillTree() self.tree.expanded.connect(self.adjustColumns) def fillTree(self): self.items = {} self.model.clear() self.model.setHorizontalHeaderLabels([self.tr('Setting'), self.tr('Value')]) text = unicode(self.searchBox.text()) settings = ProcessingConfig.getSettings() rootItem = self.model.invisibleRootItem() priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [groupItem, emptyItem]) for setting in settings[group]: if setting.hidden: continue if text == '' or text.lower() in setting.description.lower(): labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) if text != '': self.tree.expand(groupItem.index()) providersItem = QStandardItem(self.tr('Providers')) icon = QIcon(os.path.join(pluginPath, 'images', 'alg.png')) providersItem.setIcon(icon) providersItem.setEditable(False) emptyItem = QStandardItem() emptyItem.setEditable(False) rootItem.insertRow(0, [providersItem, emptyItem]) for group in settings.keys(): if group in priorityKeys: continue groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) groupItem.setIcon(icon) groupItem.setEditable(False) for setting in settings[group]: if setting.hidden: continue if text == '' or text.lower() in setting.description.lower(): labelItem = QStandardItem(setting.description) labelItem.setIcon(icon) labelItem.setEditable(False) self.items[setting] = SettingItem(setting) groupItem.insertRow(0, [labelItem, self.items[setting]]) emptyItem = QStandardItem() emptyItem.setEditable(False) providersItem.appendRow([groupItem, emptyItem]) self.tree.sortByColumn(0, Qt.AscendingOrder) self.adjustColumns() def accept(self): for setting in self.items.keys(): if isinstance(setting.value, bool): setting.value = self.items[setting].checkState() == Qt.Checked elif isinstance(setting.value, (float, int, long)): value = unicode(self.items[setting].text()) try: value = float(value) setting.value = value except ValueError: QMessageBox.critical(self, self.tr('Wrong value'), self.tr('Wrong parameter value:\n%1') % value) return else: setting.value = unicode(self.items[setting].text()) setting.save() Processing.updateAlgsList() QDialog.accept(self) def adjustColumns(self): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(1)
class FrameInfoViewer(QTreeView): """ Main tree for frame info """ frame_changed = pyqtSignal(SBFrame) def __init__(self, parent): super(QTreeView, self).__init__(parent) self.setAutoScroll(True) self.source_files = {} self.focus_signal = None self.header().setResizeMode(QHeaderView.ResizeToContents) self._show_args = None self.frame_data = QStandardItemModel() self.setModel(self.frame_data) self.setAlternatingRowColors(True) self.top_frame = None self.frames = {} def set_focus_signal(self, signal): """ set callback to focus source file line""" self.focus_signal = signal def clear(self): """ clear the widget""" self.frame_data.clear() self.frame_data.setColumnCount(2) self.frame_data.setHorizontalHeaderLabels(['', '']) def show_frame_info(self, process): """ show the frame info """ if not self.isVisible: return #TODO: no update if top frame is the same self.clear() root = self.frame_data.invisibleRootItem() self.source_files.clear() self.frames.clear() if process is None or not process.is_alive: return #if process.num_of_threads == 1: for thread in process: thread_name = thread.GetName() if not thread_name: thread_name = '[No Thread]' thread_row = QStandardItem(thread_name) thread_row.setEditable(False) thread_row.setSelectable(False) dummy = QStandardItem('') dummy.setEditable(False) dummy.setSelectable(False) root.appendRow([thread_row, dummy]) if len(thread.frames): self.top_frame = thread.frames[0] self.frame_changed.emit(self.top_frame) for frame in thread.frames: # first show the frame on the top of call stack. frame_idx = '#%d: ' % frame.idx frame_info = '' selectable = False if frame.name: frame_idx += frame.name if self._show_args.isChecked(): args = ','.join([str(x) for x in frame.args]) frame_info += ' (%s)' % args line = frame.line_entry if line: file_info = ' at %s:%d' % (str(line.GetFileSpec()), line.GetLine()) frame_info += file_info selectable = True else: frame_info += str(frame.module.GetFileSpec()) if frame.is_inlined: frame_info += ' (inlined)' col_idx = QStandardItem(frame_idx) self.source_files[col_idx] = line self.frames[col_idx] = frame col_idx.setEditable(False) col_idx.setSelectable(selectable) col_info = QStandardItem(frame_info) col_info.setEditable(False) col_info.setSelectable(selectable) thread_row.appendRow([col_idx, col_info]) self.expandToDepth(1) def frame_up(self): """ set frame to one level up """ pass def frame_down(self): """ set frame to one level down """ pass def set_show_args(self, widget): """ set the checkbox of showing func args""" self._show_args = widget def mousePressEvent(self, event): """ overrided """ idx = self.indexAt(event.pos()) if idx.isValid() and self.focus_signal: model = idx.model() idx = idx.sibling(idx.row(), 0) if idx.isValid(): item = model.itemFromIndex(idx) if item and item.isSelectable(): if item in self.source_files: file_info = self.source_files[item] if self.focus_signal: self.focus_signal.emit(file_info.GetFileSpec().fullpath, file_info.GetLine()) self.frame_changed.emit(self.frames[item]) else: logging.error('frame cannot find associated source file') QTreeView.mousePressEvent(self, event)