class PrvTreeviewNest(QTreeView): def __init__(self): super(PrvTreeviewNest, self).__init__() loadUi('treeview_nest.ui') # row can be 0 even when it's more than 0. self._datamodel = QStandardItemModel(0, 2) self.setModel(self._datamodel) for i in range(4): self.add_widget(i + 1) self.show() def add_widget(self, n): std_item = QStandardItem('{}th item'.format(n)) self._datamodel.setItem(n, 0, std_item) node_widget = QPushButton('{}th button'.format(n)) qindex_widget = self._datamodel.index(n, 1, QModelIndex()) self.setIndexWidget(qindex_widget, node_widget) if n == 2: std_item_child = QStandardItem('child') std_item.appendRow(std_item_child) node_widget_child = QPushButton('petit button') qindex_widget_child = self._datamodel.index(n, 1, QModelIndex()) self.setIndexWidget(qindex_widget_child, node_widget_child)
def __init__(self, parent=None): super(MainWindow, self).__init__(parent) uic.loadUi("mainwindow.ui", self) model = QStandardItemModel(7, 4, self) for row in range(7): for column in range(4): item = QStandardItem(QString("%1").arg(row * 4 + column)) model.setItem(row, column, item) self.tableView = QTableView() self.tableView.setModel(model) self.setCentralWidget(self.tableView) # 获取视图的项目选择模型 selectionModel = self.tableView.selectionModel() # 定义左上角和右下角的索引,然后使用这两个索引创建选择 topLeft = model.index(1, 1, QModelIndex()) bottomRight = model.index(5, 2, QModelIndex()) selection = QItemSelection(topLeft, bottomRight) # 使用指定的选择模式来选择项目 selectionModel.select(selection, QItemSelectionModel.Select) self.mainToolBar.addAction(_fromUtf8("当前项目"), self.getCurrentItemData) self.mainToolBar.addAction(_fromUtf8("切换选择"), self.toggleSelection)
def _show_mashups(self, mashups): self.switch_btn_apis.hide() self.switch_btn_mashups.hide() self.recommendLabel.hide() row = 0 model = QStandardItemModel(len(mashups), 4) model.setColumnCount(4) for mashup in mashups: model.setData(model.index(row, 0), QVariant(get_mashup_name(mashup))) model.setData(model.index(row, 1), QVariant(mashup['title'])) model.setData(model.index(row, 2), QVariant(mashup['self'])) model.setData(model.index(row, 3), QVariant(mashup['description'])) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("Workflow")) model.setHeaderData(1, Qt.Horizontal, QVariant("Short Description")) model.setHeaderData(2, Qt.Horizontal, QVariant("Provider")) model.setHeaderData(3, Qt.Horizontal, QVariant("Detailed Info")) # model.setHeaderData(0, Qt.Horizontal, QVariant("Info")) # model.setHeaderData(1, Qt.Horizontal, QVariant("Title")) # model.setHeaderData(2, Qt.Horizontal, QVariant("self")) # model.setHeaderData(3, Qt.Horizontal, QVariant("Description")) self.table.setModel(model) self.table.resizeColumnsToContents() self.add_btn.show()
def _show_apis(self, apis, recommend=False): self.switch_btn_apis.hide() self.switch_btn_mashups.hide() self.recommendLabel.hide() row = 0 model = QStandardItemModel(len(apis), 4) model.setColumnCount(4) for api in apis: model.setData(model.index(row, 0), QVariant(get_api_name(api))) model.setData(model.index(row, 1), QVariant(api['protocols'])) model.setData(model.index(row, 2), QVariant(api['provider'])) model.setData(model.index(row, 3), QVariant(api['version'])) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("Module")) model.setHeaderData(1, Qt.Horizontal, QVariant("Protocol")) model.setHeaderData(2, Qt.Horizontal, QVariant("Provider")) model.setHeaderData(3, Qt.Horizontal, QVariant("Version")) # model.setHeaderData(0, Qt.Horizontal, QVariant("API")) # model.setHeaderData(1, Qt.Horizontal, QVariant("Protocols")) # model.setHeaderData(2, Qt.Horizontal, QVariant("Provider")) # model.setHeaderData(3, Qt.Horizontal, QVariant("Version")) self.table.setModel(model) self.table.resizeColumnsToContents() if recommend: self.recommendLabel.show() self.add_btn.show()
def _show_related_mashups(self): self.switch_btn_apis.hide() self.switch_btn_mashups.hide() self.recommendLabel.hide() apis = [] objs = [] for mashup in self.related_mashups: apis.extend(mashup["related_mashups"]) for api in apis: objs.append(api) mashups = self.data_source.mashups_by_api(api) objs.extend(mashups) row = 0 model = QStandardItemModel(len(objs), 4) model.setColumnCount(4) for obj in objs: if obj.get('protocols'): model.setData(model.index(row, 0), QVariant(get_api_name(obj))) model.setData(model.index(row, 1), QVariant(obj['protocols'])) model.setData(model.index(row, 2), QVariant(obj['provider'])) else: model.setData(model.index(row, 3), QVariant(get_mashup_name(obj))) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("API")) model.setHeaderData(1, Qt.Horizontal, QVariant("Protocols")) model.setHeaderData(2, Qt.Horizontal, QVariant("Provider")) model.setHeaderData(3, Qt.Horizontal, QVariant("Mashup")) self.table.setModel(model) self.table.resizeColumnsToContents() self.switch_btn_apis.show()
def init_view(self): self.table = QTableView(self) self.table.setMinimumSize(600, 600) manager = core.packagemanager.get_package_manager() package = manager.get_package("edu.cmu.sv.components", "1.0.0") modules = package.descriptors apis = [] self.modules_to_upgrade = [] for module in modules.values(): api = self.data_source.api_by_id(module.name) if ("1.0" != module.version): apis.append(api) self.modules_to_upgrade.append(module) table_model = QStandardItemModel(len(apis), 4) row = 0 for api in apis: table_model.setData(table_model.index(row, 0), QVariant(api['id'])) table_model.setData(table_model.index(row, 1), QVariant(api['category'])) table_model.setData(table_model.index(row, 2), QVariant(api['version'])) table_model.setData(table_model.index(row, 3), QVariant(api['description'])) row += 1 table_model.setHeaderData(0, Qt.Horizontal, QVariant("Link")) table_model.setHeaderData(1, Qt.Horizontal, QVariant("Category")) table_model.setHeaderData(2, Qt.Horizontal, QVariant("Version")) table_model.setHeaderData(3, Qt.Horizontal, QVariant("Description")) self.table.setModel(table_model) btn = QPushButton(self) btn.clicked.connect(self.upgrade_api) btn.setText("Upgrade") btn.move(600, 500)
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 PrvTreeviewNest(QTreeView): def __init__(self): super(PrvTreeviewNest, self).__init__() loadUi('/home/user/yourproject/resource/treeview_nest.ui') # row can be 0 even when it's more than 0. self._datamodel = QStandardItemModel(0, 2) self.setModel(self._datamodel) for i in range(4): self._add_widget(i + 1) self.show() def _add_widget(self, n): item_toplevel = QStandardItem('{}th item'.format(n)) self._datamodel.setItem(n, 0, item_toplevel) widget_toplevel = QPushButton('{}th button'.format(n)) qindex_toplevel = self._datamodel.index(n, 1, QModelIndex()) self.setIndexWidget(qindex_toplevel, widget_toplevel) if n == 2: item_child_col0 = QStandardItem('child col0') item_child_col1 = QStandardItem('child col1') #item_toplevel.appendRow(item_child_col0) item_toplevel.insertRow(0, [item_child_col0, item_child_col1]) widget_child = QPushButton('child widget') qindex_child = item_child_col1.index() self.setIndexWidget(qindex_child, widget_child)
def __init__(self, parent=None): super(MainWindow, self).__init__(parent) uic.loadUi("mainwindow.ui", self) model = QStandardItemModel(7, 4, self) for row in range(7): for column in range(4): item = QStandardItem(QString("%1").arg(row * 4 + column)) model.setItem(row, column, item) self.tableView = QTableView() self.tableView.setModel(model) self.setCentralWidget(self.tableView) # 获取视图的项目选择模型 selectionModel = self.tableView.selectionModel() # 定义左上角和右下角的索引,然后使用这两个索引创建选择 topLeft = model.index(1, 1, QModelIndex()) bottomRight = model.index(5, 2, QModelIndex()) selection = QItemSelection(topLeft, bottomRight) # 使用指定的选择模式来选择项目 selectionModel.select(selection, QItemSelectionModel.Select) self.mainToolBar.addAction(_fromUtf8("当前项目"), self.getCurrentItemData) self.mainToolBar.addAction(_fromUtf8("切换选择"), self.toggleSelection) self.connect(selectionModel,SIGNAL("selectionChanged(QItemSelection,QItemSelection)"), self.updateSelection) self.connect(selectionModel, SIGNAL("currentChanged(QModelIndex,QModelIndex)"), self.changeCurrent) # 多个视图共享选择 self.tableView2 = QTableView() self.tableView2.setWindowTitle("tableView2") self.tableView2.resize(400, 300) self.tableView2.setModel(model) self.tableView2.setSelectionModel(selectionModel) self.tableView2.show() # 使用自定义委托 delegate = SpinBoxDelegate(self) self.tableView.setItemDelegate(delegate)
def _show_related_apis(self): self.switch_btn_apis.hide() self.switch_btn_mashups.hide() self.recommendLabel.hide() row = 0 objs = [] for mashup in self.related_mashups: objs.append(mashup) for api in mashup["related_mashups"]: objs.append(api) #Combining similarity and related. similar_apis = self.data_source.search_api_similarity(self.highlighted_api) #return str(mashup['id'])[(len("http://www.programmableweb.com/mashup/")):] objs.append({'id': "http://www.programmableweb.com/mashup/Using-Similarity-Metric"}) objs.extend(similar_apis) #Combining similarity and related. #http://localhost:9000/getReputation/John%20Lions model = QStandardItemModel(len(objs), 6) for obj in objs: if obj.get('protocols'): model.setData(model.index(row, 1), QVariant(get_api_name(obj))) model.setData(model.index(row, 2), QVariant(obj['protocols'])) model.setData(model.index(row, 3), QVariant(obj['provider'])) model.setData(model.index(row, 4), QVariant(obj['version'])) trust = requests.get('http://localhost:9000/getReputation/Luis Ramos').content #model.setData(model.index(row, 5), QVariant(str(random.random()))) model.setData(model.index(row, 5), QVariant(trust)) else: model.setData(model.index(row, 0), QVariant(get_mashup_name(obj))) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("Mashup")) model.setHeaderData(1, Qt.Horizontal, QVariant("API")) model.setHeaderData(2, Qt.Horizontal, QVariant("Protocols")) model.setHeaderData(3, Qt.Horizontal, QVariant("Provider")) model.setHeaderData(4, Qt.Horizontal, QVariant("Version")) model.setHeaderData(5, Qt.Horizontal, QVariant("Trust")) self.table.setModel(model) self.table.resizeColumnsToContents() self.switch_btn_mashups.show()
def _show_related_apis(self): self.switch_btn_apis.hide() self.switch_btn_mashups.hide() self.recommendLabel.hide() row = 0 objs = [] for mashup in self.related_mashups: objs.append(mashup) for api in mashup["related_mashups"]: objs.append(api) #Combining similarity and related. similar_apis = self.data_source.search_api_similarity(self.highlighted_api) #return str(mashup['id'])[(len("http://www.programmableweb.com/mashup/")):] objs.append({'id': "http://www.programmableweb.com/mashup/Using-Similarity-Metric"}) objs.extend(similar_apis) #Combining similarity and related. model = QStandardItemModel(len(objs), 5) for obj in objs: if obj.get('protocols'): model.setData(model.index(row, 1), QVariant(get_api_name(obj))) model.setData(model.index(row, 2), QVariant(obj['protocols'])) model.setData(model.index(row, 3), QVariant(obj['provider'])) model.setData(model.index(row, 4), QVariant(obj['version'])) else: model.setData(model.index(row, 0), QVariant(get_mashup_name(obj))) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("Mashup")) model.setHeaderData(1, Qt.Horizontal, QVariant("API")) model.setHeaderData(2, Qt.Horizontal, QVariant("Protocols")) model.setHeaderData(3, Qt.Horizontal, QVariant("Provider")) model.setHeaderData(4, Qt.Horizontal, QVariant("Version")) self.table.setModel(model) self.switch_btn_mashups.show()
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 PrvTreeviewNest(QTreeView): def __init__(self): super(PrvTreeviewNest, self).__init__() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_prove'), 'resource', 'treeview_nest.ui') loadUi(ui_file, self) #loadUi('/home/n130s/data/Dropbox/ROS/groovy_quantal/catkin_ws/src/' + \ #'rqt_prove/resource/treeview_nest.ui') # row can be 0 even when it's more than 0. self._datamodel = QStandardItemModel(0, 2) self.setModel(self._datamodel) for i in range(4): self._add_widget(i + 1) self.show() def _add_widget(self, n): item_toplevel = QStandardItem('{}th item'.format(n)) self._datamodel.setItem(n, 0, item_toplevel) widget_toplevel = QPushButton('{}th button'.format(n)) qindex_toplevel = self._datamodel.index(n, 1, QModelIndex()) self.setIndexWidget(qindex_toplevel, widget_toplevel) if n == 2: item_child_col0 = QStandardItem('child col0') item_child_col1 = QStandardItem('child col1') #item_toplevel.appendRow(item_child_col0) item_child_col2 = QStandardItem('child col2') item_toplevel.insertRow(0, [item_child_col0, item_child_col1]) #item_child_col0.insertColumn(0, [item_child_col1, item_child_col2]) #item_child_col0.appendColumn([item_child_col1]) # appends another child widget_child = QPushButton('child widget') #qindex_child = self._datamodel.index(n, 1, QModelIndex()) qindex_child = item_child_col1.index() #qindex_child = item_toplevel.index(0, 1, QModelIndex()) self.setIndexWidget(qindex_child, widget_child)
class Terminals(QWidget): ready = pyqtSignal(bool) def __init__(self, parent=None): QWidget.__init__(self, parent) self.ui = uic.loadUiType('terminal.ui')[0]() self.ui.setupUi(self) self.notifier = QSystemTrayIcon(QIcon('arrow-up-icon.png'), self) self.notifier.show() self.model = None self.mainloop = None self.delegate = None def test_display(self): if self.mainloop: self.mainloop.test_display() def update_device_config(self): if self.mainloop: self.mainloop.update_config() def terminal_open(self, addr): if self.mainloop: self.mainloop.terminal_open(addr) def terminal_close(self, addr): if self.mainloop: self.mainloop.terminal_close(addr) def start_mainloop(self): if self.mainloop is None: self.mainloop = Mainloop(parent=self) self.mainloop.ready.connect(self.on_mainloop_ready) self.mainloop.notify.connect(lambda title, msg: self.notifier.showMessage(title, msg)) self.mainloop.start() def stop_mainloop(self): if self.mainloop: self.mainloop.state.disconnect() self.mainloop.ready.disconnect() self.mainloop.notify.disconnect() [self.ui.terminals.closePersistentEditor(self.model.index(row, 0)) for row in xrange(self.model.rowCount())] self.mainloop.stop() self.mainloop = None def update_model(self): self.stop_mainloop() self.start_mainloop() def on_mainloop_ready(self, ok, titles): if ok: self.model = QStandardItemModel(len(titles), 1) [self.model.setItem(i, QStandardItem(str(addr))) for i, addr in enumerate(titles.keys())] self.delegate = TerminalDelegate(self.mainloop, titles) self.mainloop.report.connect(self.delegate.report) self.mainloop.state.connect(self.delegate.state) self.ui.terminals.setModel(self.model) self.ui.terminals.setItemDelegateForColumn(0, self.delegate) [self.ui.terminals.openPersistentEditor(self.model.index(row, 0)) for row in xrange(self.model.rowCount())] self.mainloop.db.free_places_update.connect(self.ui.free_places.setValue) self.mainloop.update_config() else: self.model = None self.mainloop = None self.ready.emit(ok)
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 ResultView(QWidget): """This class represent a search result view. """ def __init__(self, filter='', attributes=[], resultlist=[], parent=None): """Initialize a result view for the `SearchPlugin`. :param filter: the filter applied on the search :type filter: string :param attributes: a list containing the attributes used in the search operation. Usually extracted from the `filter`. :type attributes: list :param resultlist: a list of `SmartDataObject` from the search operation. :type resultlist: list :param parent: the parent for this widget. :type parent: QWidget """ super(ResultView, self).__init__(parent) self.setObjectName('ResultView') self.layout = QtGui.QVBoxLayout(self) # Only display the no-result message if resultlist is empty if len(resultlist) == 0: self.retranslate(all=False) self.onNoResult() return # The proxy model is used for sort and filter support self.proxymodel = QSortFilterProxyModel(self) self.proxymodel.setDynamicSortFilter(True) self.headerdata = ['dn'] self.headerdata.extend(attributes) self.resultdata = resultlist # FIXME: should we create a custom item model ? self.model = QStandardItemModel(0, len(self.headerdata), parent=self) #self.model = ResultItemModel(self) #self.model = ResultItemModel(self.headerdata, self.resultdata, self) self.proxymodel.setSourceModel(self.model) self.resultview = QTreeView(self) self.resultview.setUniformRowHeights(True) self.resultview.setRootIsDecorated(False) self.resultview.setAlternatingRowColors(True) self.resultview.setSortingEnabled(True) self.resultview.setModel(self.proxymodel) # For right-click context menu self.resultview.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.resultview.setSelectionMode(QAbstractItemView.ExtendedSelection) self.layout.addWidget(self.resultview) # The filter box enables the user to filter the returned search # results. It becomes accessible with Ctrl-F (QKeySequence.Find) self.filterBox = ResultFilterWidget(self.headerdata, parent=self) self.filterBox.setVisible(False) self.layout.addWidget(self.filterBox) # We need to call the retranslate method before populating # the result data self.retranslate() #self.model.populateHeader(self.headerdata) #self.model.populateModel(self.resultdata) self.setHeaderData(self.headerdata) self.setResultData(self.resultdata) self.resultview.resizeColumnToContents(0) self.__createContextMenu() self.__connectSlots() def __connectSlots(self): """Connect signal and slots. """ self.resultview.customContextMenuRequested.connect( self.onContextMenuRequested) self.filterBox.inputEdit.textChanged['QString'].connect( self.onFilterInputChanged) self.filterBox.columnBox.currentIndexChanged[int].connect( self.onFilterColumnChanged) def __getVSpacer(self): return QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) def __createContextMenu(self): """Display the context menu. """ self.contextMenu = QtGui.QMenu() self.contextMenuView = QtGui.QAction(self) self.contextMenuDelete = QtGui.QAction(self) self.contextMenuExport = QtGui.QAction(self) self.contextMenu.addAction(self.contextMenuView) self.contextMenu.addAction(self.contextMenuDelete) self.contextMenu.addAction(self.contextMenuExport) # Connect the context menu actions to the correct slots self.contextMenuView.triggered.connect(self.onViewItemsSelected) self.contextMenuDelete.triggered.connect(self.onDeleteItemsSelected) self.contextMenuExport.triggered.connect(self.onExportItemsSelected) def onNoResult(self): """Adds a styled *no result* message to the main layout. """ font = QtGui.QFont() font.setBold(True) sadface = QtGui.QLabel(self) sadface.setPixmap(pixmapFromTheme('face-sad', ':/icons/48/face-sad')) noresult = QtGui.QLabel(self) noresult.setText(self.str_NO_RESULT) noresult.setFont(font) hlayout = QtGui.QHBoxLayout() hlayout.addItem(self.__getVSpacer()) hlayout.addWidget(sadface) hlayout.addWidget(noresult) hlayout.addItem(self.__getVSpacer()) self.layout.addLayout(hlayout) def setHeaderData(self, data=[]): """Populates the ``resultview`` model with header data. Parameters: - `data`: a list with header items. Usually this is the attributelist from the LDAP search. """ i = 0 for header in data: self.model.setHeaderData(i, QtCore.Qt.Horizontal, header) i += 1 def setResultData(self, data=[]): """Populates the ``resultview`` model with result data. Parameters: - `data`: a list containing the SmartDataObjects representing items in the LDAP search result. """ row = 0 for obj in data: self.model.insertRow(row) col = 0 for attr in self.headerdata: if self.isDistinguishedName(attr): modelData = obj.getPrettyDN() elif self.isObjectClass(attr): modelData = ','.join(obj.getObjectClasses()) elif obj.hasAttribute(attr): if obj.isAttributeBinary(attr): modelData = self.str_BINARY_DATA else: modelData = ','.join(obj.getAttributeValueList(attr)) self.model.setData(self.model.index(row, col), modelData) col += 1 row += 1 def isDistinguishedName(self, attr): """Returns ``True`` if `attr` is a distinguished name, ``False`` otherwise. Parameters: - `attr`: the LDAP string attribute value to check. """ return attr.lower() == 'dn' def isObjectClass(self, attr): """Returns ``True`` if `attr` is an object class, ``False`` otherwise. Parameters: - `attr`: the LDAP string attribute value to check. """ return attr.lower() == 'objectclass' def onContextMenuRequested(self, point): """Display the context menu """ # FIXME: In order to be able to export, delete and view search # result entries. We should make use of the various dialogs in # the Browser plugin. Unitl we have refactored the design in a # way that allow us to use these without accessing the browser # modules, we simple don't provide these options yet. return self.selection = self.resultview.selectedIndexes() deleteSupport = True exportSupport = True rowsselected = len(self.selection) / len(self.headerdata) if not rowsselected > 0: self.contextMenu.setEnabled(False) self.contextMenu.exec_(self.resultview.mapToGlobal(point)) return self.contextMenu.setEnabled(True) # Look over at Browser plugin for implementation of # multiselect and operation support validation print rowsselected self.contextMenuView.setEnabled(True) if rowsselected == 1: self.contextMenuView.setText(self.str_VIEW_ITEM) else: self.contextMenuView.setText(self.str_VIEW_ITEMS) if deleteSupport: self.contextMenuDelete.setEnabled(True) if rowsselected == 1: self.contextMenuDelete.setText(self.str_DELETE_ITEM) else: self.contextMenuDelete.setText(self.str_DELETE_ITEMS) if exportSupport: self.contextMenuExport.setEnabled(True) if rowsselected == 1: self.contextMenuExport.setText(self.str_EXPORT_ITEM) else: self.contextMenuExport.setText(self.str_EXPORT_ITEMS) # Finally we execute the context menu self.contextMenu.exec_(self.resultview.mapToGlobal(point)) def onViewItemsSelected(self): """Slot for the *view* context menu action. """ raise NotImplementedError( 'Need to implement a proper model for this to be supported') def onDeleteItemsSelected(self): """Slot for the *delete* context menu action. """ msg = 'Delete from the Search Plugin is not implemented jet.' dialog = DeleteDialog(self, msg) dialog.setDeleteItems([]) dialog.exec_() def onExportItemsSelected(self): """Slot for the 'export' context menu action. """ msg = 'Export from the Search Plugin is not implemented jet.' dialog = ExportDialog(self, msg) # Only for proof of concept dialog.setExportData([]) dialog.exec_() def onFilterBoxVisibilityChanged(self, visible): """Slot for the QKeySequence.Find. - `visible`: a boolean value indicating wether or not to toggle the filter box widget visibility on or off. """ if visible: self.filterBox.setVisible(True) self.filterBox.inputEdit.setFocus() else: # I belive it's common practise to clear the filter when # the filter box is closed. This is at least the way the # filter boxes works for most webbrowsers. self.filterBox.inputEdit.clear() self.filterBox.setVisible(False) self.resultview.setFocus() def onFilterInputChanged(self, filter=''): """Slot for the filter input in the result filter widget. We get the selected syntax from the syntax combobox """ # The PyQt4 QVariant is causing some problems here, when we try # to use the <combobox>.itemData directly, even though the data # holds valid QRexExp.PatternSyntax values. # We therefore need to explicitly make the QVariant and integer. i = self.filterBox.syntaxBox.currentIndex() syntaxIndex = self.filterBox.syntaxBox.itemData(i).toInt()[0] syntax = QtCore.QRegExp.PatternSyntax(syntaxIndex) # As of now we do filtering in a case insensitive way, until we # come up with a way to introduce case sensitivity selection in a # UI inexpensive way. We want to keep the filter widget as clean # and simple as possible. regex = QtCore.QRegExp(filter, QtCore.Qt.CaseInsensitive, syntax) self.proxymodel.setFilterRegExp(regex) def onFilterColumnChanged(self, index): """Slot for the column combobox in the filter box widget. """ self.proxymodel.setFilterKeyColumn(index) def retranslate(self, all=True): """For dynamic translation support. """ self.str_VIEW_ITEM = QtGui.QApplication.translate( 'ResultView', 'View Item') self.str_VIEW_ITEMS = QtGui.QApplication.translate( 'ResultView', 'View Items') self.str_DELETE_ITEM = QtGui.QApplication.translate( 'ResultView', 'Delete Item') self.str_DELETE_ITEMS = QtGui.QApplication.translate( 'ResultView', 'Delete Items') self.str_EXPORT_ITEM = QtGui.QApplication.translate( 'ResultView', 'Export Item') self.str_EXPORT_ITEMS = QtGui.QApplication.translate( 'ResultView', 'Export Items') self.str_NO_RESULT = QtGui.QApplication.translate( 'ResultView', 'Sorry, no result to display!') self.str_BINARY_DATA = QtGui.QApplication.translate( 'ResultView', 'Binary Data') if all: self.filterBox.retranslate()
class FormWidget(ui_formwidget.Ui_Form, WidgetBase): def __init__(self, parent=None): super(FormWidget, self).__init__(parent) self.setupUi(self) self.form = None self.fieldsmodel = QgsFieldModel() self.widgetmodel = WidgetsModel() self.possiblewidgetsmodel = QStandardItemModel() self.formlayersmodel = QgsLayerModel(watchregistry=True) self.formlayers = CaptureLayerFilter() self.formlayers.setSourceModel(self.formlayersmodel) self.layerCombo.setModel(self.formlayers) self.useablewidgets.setModel(self.possiblewidgetsmodel) self.fieldList.setModel(self.fieldsmodel) self.userwidgets.setModel(self.widgetmodel) self.userwidgets.selectionModel().currentChanged.connect(self.load_widget) self.widgetmodel.rowsRemoved.connect(self.setwidgetconfigvisiable) self.widgetmodel.rowsInserted.connect(self.setwidgetconfigvisiable) self.widgetmodel.modelReset.connect(self.setwidgetconfigvisiable) self.addWidgetButton.pressed.connect(self.newwidget) self.removeWidgetButton.pressed.connect(self.removewidget) self.formfolderLabel.linkActivated.connect(self.openformfolder) self.expressionButton.clicked.connect(self.opendefaultexpression) self.fieldList.currentIndexChanged.connect(self.updatewidgetname) self.fieldwarninglabel.hide() self.formtab.currentChanged.connect(self.formtabchanged) for item, data in readonlyvalues: self.readonlyCombo.addItem(item, data) self.loadwidgettypes() self.formLabelText.textChanged.connect(self.form_name_changed) self.layerCombo.currentIndexChanged.connect(self.layer_updated) self.fieldList.currentIndexChanged.connect(self._save_current_widget) self.nameText.textChanged.connect(self._save_current_widget) self.useablewidgets.currentIndexChanged.connect(self._save_current_widget) self.useablewidgets.currentIndexChanged.connect(self.swapwidgetconfig) menu = QMenu("Field Actions") action = menu.addAction("Auto add all fields") action.triggered.connect(self.auto_add_fields) self.addWidgetButton.setMenu(menu) self.addWidgetButton.setPopupMode(QToolButton.MenuButtonPopup) def layer_updated(self, index): if not self.selected_layer: return self.updatefields(self.selected_layer) def form_name_changed(self, text): self.form.settings['label'] = self.formLabelText.text() self.treenode.emitDataChanged() def updatewidgetname(self, index): # Only change the edit text on name field if it's not already set to something other then the # field name. field = self.fieldsmodel.index(index, 0).data(QgsFieldModel.FieldNameRole) currenttext = self.nameText.text() foundfield = self.fieldsmodel.findfield(currenttext) if foundfield: self.nameText.setText(field) def opendefaultexpression(self): layer = self.form.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultvalueText.text().strip('[%').strip('%]').strip() dlg.setExpressionText(text) if dlg.exec_(): self.defaultvalueText.setText('[% {} %]'.format(dlg.expressionText())) def formtabchanged(self, index): def setformpreview(form): item = self.frame_2.layout().itemAt(0) if item and item.widget(): item.widget().setParent(None) featureform = FeatureForm.from_form(form, form.settings, None, {}) from roam import defaults defaultwidgets = form.widgetswithdefaults() layer = form.QGISLayer try: values = {} feature = layer.getFeatures().next() defaultvalues = defaults.default_values(defaultwidgets, feature, layer) values.update(defaultvalues) featureform.bindvalues(values) except StopIteration: pass self.frame_2.layout().addWidget(featureform) if index == 1: self.form.settings['widgets'] = list(self.widgetmodel.widgets()) setformpreview(self.form) def usedfields(self): """ Return the list of fields that have been used by the the current form's widgets """ widgets = self.widgetmodel.widgets() for widget in widgets: yield widget['field'] def openformfolder(self, url): QDesktopServices.openUrl(QUrl.fromLocalFile(self.form.folder)) def loadwidgettypes(self): self.useablewidgets.blockSignals(True) for widgettype in roam.editorwidgets.core.supportedwidgets(): try: configclass = configmanager.editorwidgets.widgetconfigs[widgettype] except KeyError: continue configwidget = configclass() item = QStandardItem(widgettype) item.setData(configwidget, Qt.UserRole) item.setData(widgettype, Qt.UserRole + 1) item.setIcon(QIcon(widgeticon(widgettype))) self.useablewidgets.model().appendRow(item) self.widgetstack.addWidget(configwidget) self.useablewidgets.blockSignals(False) def setwidgetconfigvisiable(self, *args): haswidgets = self.widgetmodel.rowCount() > 0 self.widgetConfigTabs.setVisible(haswidgets) def newwidget(self, field=None): """ Create a new widget. The default is a list. """ mapping = {QVariant.String: "Text", QVariant.Int: "Number", QVariant.Double: "Number(Double)", QVariant.ByteArray: "Image", QVariant.Date: "Date", QVariant.DateTime: "Date"} widget = {} if not field: field = self.fieldsmodel.index(0, 0).data(Qt.UserRole) if not field: return widget['field'] = field.name() else: widget['field'] = field.name() try: widget['widget'] = mapping[field.type()] except KeyError: widget['widget'] = 'Text' # Grab the first field. widget['name'] = field.name().replace("_", " ").title() currentindex = self.userwidgets.currentIndex() currentitem = self.widgetmodel.itemFromIndex(currentindex) if currentitem and currentitem.iscontainor(): parent = currentindex else: parent = currentindex.parent() index = self.widgetmodel.addwidget(widget, parent) self.userwidgets.setCurrentIndex(index) def auto_add_fields(self): used = list(self.usedfields()) for field in self.selected_layer.pendingFields(): if field.name() in used: continue self.newwidget(field) def removewidget(self): """ Remove the selected widget from the widgets list """ widget, index = self.currentuserwidget if index.isValid(): self.widgetmodel.removeRow(index.row(), index.parent()) def set_project(self, project, treenode): super(FormWidget, self).set_project(project, treenode) self.formlayers.setSelectLayers(self.project.selectlayers) form = self.treenode.form self.form = form self.setform(self.form) def updatefields(self, layer): """ Update the UI with the fields for the selected layer. """ self.fieldsmodel.setLayer(layer) def setform(self, form): """ Update the UI with the currently selected form. """ def getfirstlayer(): index = self.formlayers.index(0, 0) layer = index.data(Qt.UserRole) layer = layer.name() return layer def loadwidgets(widget): """ Load the widgets into widgets model """ self.widgetmodel.clear() self.widgetmodel.loadwidgets(form.widgets) def findlayer(layername): index = self.formlayersmodel.findlayer(layername) index = self.formlayers.mapFromSource(index) layer = index.data(Qt.UserRole) return index, layer settings = form.settings label = form.label layername = settings.setdefault('layer', getfirstlayer()) layerindex, layer = findlayer(layername) if not layer or not layerindex.isValid(): return formtype = settings.setdefault('type', 'auto') widgets = settings.setdefault('widgets', []) self.formLabelText.setText(label) folderurl = "<a href='{path}'>{name}</a>".format(path=form.folder, name=os.path.basename(form.folder)) self.formfolderLabel.setText(folderurl) self.layerCombo.setCurrentIndex(layerindex.row()) self.updatefields(layer) index = self.formtypeCombo.findText(formtype) if index == -1: self.formtypeCombo.insertItem(0, formtype) self.formtypeCombo.setCurrentIndex(0) else: self.formtypeCombo.setCurrentIndex(index) loadwidgets(widgets) # Set the first widget index = self.widgetmodel.index(0, 0) if index.isValid(): self.userwidgets.setCurrentIndex(index) self.load_widget(index, None) def swapwidgetconfig(self, index): widgetconfig, _, _ = self.current_config_widget defaultvalue = widgetconfig.defaultvalue self.defaultvalueText.setText(defaultvalue) self.updatewidgetconfig({}) def load_widget(self, index, last): """ Update the UI with the config for the current selected widget. """ self.fieldList.blockSignals(True) self.nameText.blockSignals(True) self.useablewidgets.blockSignals(True) if last: self._save_widget(last) widget = index.data(Qt.UserRole) if not widget: self.fieldList.blockSignals(False) self.nameText.blockSignals(False) self.useablewidgets.blockSignals(False) return widgettype = widget['widget'] field = widget['field'] required = widget.setdefault('required', False) savevalue = widget.setdefault('rememberlastvalue', False) name = widget.setdefault('name', field) default = widget.setdefault('default', '') readonly = widget.setdefault('read-only-rules', []) hidden = widget.setdefault('hidden', False) try: data = readonly[0] except IndexError: data = 'never' index = self.readonlyCombo.findData(data) self.readonlyCombo.setCurrentIndex(index) if not isinstance(default, dict): self.defaultvalueText.setText(default) self.defaultvalueText.setEnabled(True) self.expressionButton.setEnabled(True) else: # TODO Handle the more advanced default values. self.defaultvalueText.setText("Advanced default set in config") self.defaultvalueText.setEnabled(False) self.expressionButton.setEnabled(False) self.nameText.setText(name) self.requiredCheck.setChecked(required) self.savevalueCheck.setChecked(savevalue) self.hiddenCheck.setChecked(hidden) if field is not None: index = self.fieldList.findData(field.lower(), QgsFieldModel.FieldNameRole) if index > -1: self.fieldList.setCurrentIndex(index) else: self.fieldList.setEditText(field) index = self.useablewidgets.findText(widgettype) if index > -1: self.useablewidgets.setCurrentIndex(index) config = widget.get('config', {}) self.updatewidgetconfig(config) self.fieldList.blockSignals(False) self.nameText.blockSignals(False) self.useablewidgets.blockSignals(False) @property def currentuserwidget(self): """ Return the selected user widget. """ index = self.userwidgets.currentIndex() return index.data(Qt.UserRole), index @property def current_config_widget(self): """ Return the selected widget in the widget combo. """ index = self.useablewidgets.currentIndex() index = self.possiblewidgetsmodel.index(index, 0) return index.data(Qt.UserRole), index, index.data(Qt.UserRole + 1) def updatewidgetconfig(self, config): configwidget, _, _ = self.current_config_widget self.setconfigwidget(configwidget, config) def setconfigwidget(self, configwidget, config): """ Set the active config widget. """ try: configwidget.widgetdirty.disconnect(self._save_current_widget) except TypeError: pass self.widgetstack.setCurrentWidget(configwidget) configwidget.setconfig(config) configwidget.widgetdirty.connect(self._save_current_widget) def _save_current_widget(self, *args): _, index = self.currentuserwidget self._save_widget(index) def _save_widget(self, index): widgetdata = self._get_widget_config() self.widgetmodel.setData(index, widgetdata, Qt.UserRole) def _get_widget_config(self): def current_field(): row = self.fieldList.currentIndex() field = self.fieldsmodel.index(row, 0).data(QgsFieldModel.FieldNameRole) return field configwidget, _, widgettype = self.current_config_widget widget = {} widget['field'] = current_field() widget['default'] = self.defaultvalueText.text() widget['widget'] = widgettype widget['required'] = self.requiredCheck.isChecked() widget['rememberlastvalue'] = self.savevalueCheck.isChecked() widget['name'] = self.nameText.text() widget['read-only-rules'] = [self.readonlyCombo.itemData(self.readonlyCombo.currentIndex())] widget['hidden'] = self.hiddenCheck.isChecked() widget['config'] = configwidget.getconfig() return widget @property def selected_layer(self): index = self.formlayers.index(self.layerCombo.currentIndex(), 0) layer = index.data(Qt.UserRole) return layer def write_config(self): if not self.selected_layer: return self._save_current_widget() self.form.settings['layer'] = self.selected_layer.name() self.form.settings['type'] = self.formtypeCombo.currentText() self.form.settings['label'] = self.formLabelText.text() self.form.settings['widgets'] = list(self.widgetmodel.widgets())
class DoProfile(QWidget): def __init__(self, iface, dockwidget1 , tool1 , plugin, parent = None): QWidget.__init__(self, parent) self.profiles = None #dictionary where is saved the plotting data {"l":[l],"z":[z], "layer":layer1, "curve":curve1} self.xAxisSteps = None self.xAxisStepType = "numeric" self.iface = iface self.tool = tool1 self.dockwidget = dockwidget1 self.pointstoDraw = None self.plugin = plugin #init scale widgets self.dockwidget.sbMaxVal.setValue(0) self.dockwidget.sbMinVal.setValue(0) self.dockwidget.sbMaxVal.setEnabled(False) self.dockwidget.sbMinVal.setEnabled(False) self.dockwidget.sbMinVal.valueChanged.connect(self.reScalePlot) self.dockwidget.sbMaxVal.valueChanged.connect(self.reScalePlot) #**************************** function part ************************************************* # remove layers which were removed from QGIS def removeClosedLayers(self, model1): qgisLayerNames = [] for i in range(0, self.iface.mapCanvas().layerCount()): qgisLayerNames.append(self.iface.mapCanvas().layer(i).name()) for i in range(0 , model1.rowCount()): layerName = model1.item(i,2).data(Qt.EditRole) if not layerName in qgisLayerNames: self.plugin.removeLayer(i) self.removeClosedLayers(model1) break def calculatePointProfile(self, point, model, library): self.model = model self.library = library statName = self.getPointProfileStatNames()[0] self.removeClosedLayers(model) if point == None: return PlottingTool().clearData(self.dockwidget, model, library) self.profiles = [] #creating the plots of profiles for i in range(0 , model.rowCount()): self.profiles.append( {"layer": model.item(i,3).data(Qt.EditRole) } ) self.profiles[i][statName] = [] self.profiles[i]["l"] = [] layer = self.profiles[i]["layer"] if layer: try: ident = layer.dataProvider().identify(point, QgsRaster.IdentifyFormatValue ) except: ident = None else: ident = None #if ident is not None and ident.has_key(choosenBand+1): if ident is not None: self.profiles[i][statName] = ident.results().values() self.profiles[i]["l"] = ident.results().keys() self.setXAxisSteps() PlottingTool().attachCurves(self.dockwidget, self.profiles, model, library) PlottingTool().reScalePlot(self.dockwidget, self.profiles, model, library) self.setupTableTab(model) def getPointProfileStatNames(self): return ["value"] # The code is based on the approach of ZonalStatistics from Processing toolbox def calculatePolygonProfile(self, geometry, crs, model, library): self.model = model self.library = library self.removeClosedLayers(model) if geometry is None or geometry.isEmpty(): return PlottingTool().clearData(self.dockwidget, model, library) self.profiles = [] #creating the plots of profiles for i in range(0 , model.rowCount()): self.profiles.append( {"layer": model.item(i,3).data(Qt.EditRole) } ) self.profiles[i]["l"] = [] for statistic in self.getPolygonProfileStatNames(): self.profiles[i][statistic] = [] # Get intersection between polygon geometry and raster following ZonalStatistics code rasterDS = gdal.Open(self.profiles[i]["layer"].source(), gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() cellXSize = abs(geoTransform[1]) cellYSize = abs(geoTransform[5]) rasterXSize = rasterDS.RasterXSize rasterYSize = rasterDS.RasterYSize rasterBBox = QgsRectangle(geoTransform[0], geoTransform[3] - cellYSize * rasterYSize, geoTransform[0] + cellXSize * rasterXSize, geoTransform[3]) rasterGeom = QgsGeometry.fromRect(rasterBBox) memVectorDriver = ogr.GetDriverByName('Memory') memRasterDriver = gdal.GetDriverByName('MEM') intersectedGeom = rasterGeom.intersection(geometry) ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.exportToWkt()) bbox = intersectedGeom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startColumn, startRow) = self.mapToPixel(xMin, yMax, geoTransform) (endColumn, endRow) = self.mapToPixel(xMax, yMin, geoTransform) width = endColumn - startColumn height = endRow - startRow if width == 0 or height == 0: return srcOffset = (startColumn, startRow, width, height) newGeoTransform = ( geoTransform[0] + srcOffset[0] * geoTransform[1], geoTransform[1], 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, geoTransform[5], ) # Create a temporary vector layer in memory memVDS = memVectorDriver.CreateDataSource('out') memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon) ft = ogr.Feature(memLayer.GetLayerDefn()) ft.SetGeometry(ogrGeom) memLayer.CreateFeature(ft) ft.Destroy() # Rasterize it rasterizedDS = memRasterDriver.Create('', srcOffset[2], srcOffset[3], 1, gdal.GDT_Byte) rasterizedDS.SetGeoTransform(newGeoTransform) gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1]) rasterizedArray = rasterizedDS.ReadAsArray() for bandNumber in range(1, rasterDS.RasterCount+1): rasterBand = rasterDS.GetRasterBand(bandNumber) noData = rasterBand.GetNoDataValue() if noData is None: noData = np.nan scale = rasterBand.GetScale() if scale is None: scale = 1.0 offset = rasterBand.GetOffset() if offset is None: offset = 0.0 srcArray = rasterBand.ReadAsArray(*srcOffset) srcArray = srcArray*scale+offset masked = np.ma.MaskedArray(srcArray, mask=np.logical_or.reduce(( srcArray == noData, np.logical_not(rasterizedArray), np.isnan(srcArray)))) self.profiles[i]["l"].append(bandNumber) self.profiles[i]["count"].append(float(masked.count())) self.profiles[i]["max"].append(float(masked.max())) self.profiles[i]["mean"].append(float(masked.mean())) self.profiles[i]["median"].append(float(np.ma.median(masked))) self.profiles[i]["min"].append(float(masked.min())) self.profiles[i]["range"].append(float(masked.max()) - float(masked.min())) self.profiles[i]["std"].append(float(masked.std())) self.profiles[i]["sum"].append(float(masked.sum())) self.profiles[i]["unique"].append(np.unique(masked.compressed()).size) self.profiles[i]["var"].append(float(masked.var())) memVDS = None rasterizedDS = None rasterDS = None self.setXAxisSteps() PlottingTool().attachCurves(self.dockwidget, self.profiles, model, library) PlottingTool().reScalePlot(self.dockwidget, self.profiles, model, library) self.setupTableTab(model) def getPolygonProfileStatNames(self): return ["count", "max", "mean", "median", "min", "range", "std", "sum", "unique", "var"] def setXAxisSteps(self): if self.xAxisSteps == None: self.changeXAxisStepType("numeric") return elif self.xAxisSteps[0] == "Timesteps": self.changeXAxisStepType("numeric") for profile in self.profiles: stepsNum = len(profile["l"]) startTime = self.xAxisSteps[1] step = self.xAxisSteps[2] stepType = self.xAxisSteps[3] useNetcdfTime = self.xAxisSteps[4] if stepType == "years": stepType = "days" step = step * 365 elif stepType == "months": stepType = "days" step = step * 365/12 profile["l"] = [] if useNetcdfTime and (profile["layer"].source().startswith("NETCDF:") or profile["layer"].source().endswith(".nc")): try: import netCDF4 if profile["layer"].source().startswith("NETCDF:"): filename = re.match('NETCDF:\"(.*)\":.*$', profile["layer"].source()).group(1) else: filename = profile["layer"].source() nc = netCDF4.Dataset(filename, mode='r') profile["l"] = netCDF4.num2date(nc.variables["time"][:], units = nc.variables["time"].units, calendar = nc.variables["time"].calendar) nc.close() except ImportError: text = "Temporal/Spectral Profile Tool: netCDF4 module is required to read NetCDF " + \ "time dimension. Please use pip install netCDF4" self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) profile["l"] = [] except KeyError: text = "Temporal/Spectral Profile Tool: NetCDF file does not have " + \ "time dimension." self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) nc.close() profile["l"] = [] if profile["l"] == []: for i in range(stepsNum): timedeltaParams = {stepType: step*i} profile["l"].append(startTime + timedelta(**timedeltaParams)) self.changeXAxisStepType("timedate") else: for profile in self.profiles: # Truncate the profiles to the minimum of the length of each profile # or length of provided x-axis steps stepsNum = min(len(self.xAxisSteps), len(profile["l"])) profile["l"] = self.xAxisSteps[:stepsNum] for stat in profile.keys(): if stat == "l" or stat == "layer": continue profile[stat] = profile[stat][:stepsNum] # If any x-axis step is a NaN then remove the corresponding # value from profile nans = [i for i, x in enumerate(profile["l"]) if math.isnan(x)] for stat in profile.keys(): if stat == "layer": continue profile[stat] = [x for i, x in enumerate(profile[stat]) if i not in nans] self.changeXAxisStepType("numeric") def changeXAxisStepType(self, newType): if self.xAxisStepType == newType: return else: self.xAxisStepType = newType PlottingTool().resetAxis(self.dockwidget, self.library) def mapToPixel(self, mX, mY, geoTransform): (pX, pY) = gdal.ApplyGeoTransform( gdal.InvGeoTransform(geoTransform), mX, mY) return (int(pX), int(pY)) def setupTableTab(self, model1): #*********************** TAble tab ************************************************* try: #Reinitializing the table tab self.VLayout = self.dockwidget.scrollAreaWidgetContents.layout() while 1: child = self.VLayout.takeAt(0) if not child: break child.widget().deleteLater() except: self.VLayout = QVBoxLayout(self.dockwidget.scrollAreaWidgetContents) self.VLayout.setContentsMargins(9, -1, -1, -1) #Setup the table tab self.groupBox = [] self.profilePushButton = [] self.tableView = [] self.verticalLayout = [] for i in range(0 , model1.rowCount()): self.groupBox.append( QGroupBox(self.dockwidget.scrollAreaWidgetContents) ) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox[i].sizePolicy().hasHeightForWidth()) self.groupBox[i].setSizePolicy(sizePolicy) self.groupBox[i].setMinimumSize(QSize(0, 150)) self.groupBox[i].setMaximumSize(QSize(16777215, 350)) self.groupBox[i].setTitle(QApplication.translate("GroupBox" + str(i), self.profiles[i]["layer"].name(), None, QApplication.UnicodeUTF8)) self.groupBox[i].setObjectName("groupBox" + str(i)) self.verticalLayout.append( QVBoxLayout(self.groupBox[i]) ) self.verticalLayout[i].setObjectName("verticalLayout") #The table self.tableView.append( QTableView(self.groupBox[i]) ) self.tableView[i].setObjectName("tableView" + str(i)) font = QFont("Arial", 8) columns = len(self.profiles[i]["l"]) rowNames = self.profiles[i].keys() rowNames.remove("layer") # holds the QgsMapLayer instance rowNames.remove("l") # holds the band number rows = len(rowNames) self.mdl = QStandardItemModel(rows+1, columns) self.mdl.setVerticalHeaderLabels(["band"] + rowNames) for j in range(columns): self.mdl.setData(self.mdl.index(0, j, QModelIndex()), str(self.profiles[i]["l"][j])) self.mdl.setData(self.mdl.index(0, j, QModelIndex()), font ,Qt.FontRole) for k in range(rows): self.mdl.setData(self.mdl.index(k+1, j, QModelIndex()), str(self.profiles[i][rowNames[k]][j])) self.mdl.setData(self.mdl.index(k+1, j, QModelIndex()), font ,Qt.FontRole) #self.tableView[i].setVerticalHeaderLabels(rowNames) self.tableView[i].verticalHeader().setDefaultSectionSize(18) self.tableView[i].horizontalHeader().setDefaultSectionSize(60) self.tableView[i].setModel(self.mdl) self.verticalLayout[i].addWidget(self.tableView[i]) self.horizontalLayout = QHBoxLayout() #the copy to clipboard button self.profilePushButton.append( QPushButton(self.groupBox[i]) ) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.profilePushButton[i].sizePolicy().hasHeightForWidth()) self.profilePushButton[i].setSizePolicy(sizePolicy) self.profilePushButton[i].setText(QApplication.translate("GroupBox", "Copy to clipboard", None, QApplication.UnicodeUTF8)) self.profilePushButton[i].setObjectName(str(i)) self.horizontalLayout.addWidget(self.profilePushButton[i]) self.horizontalLayout.addStretch(0) self.verticalLayout[i].addLayout(self.horizontalLayout) self.VLayout.addWidget(self.groupBox[i]) QObject.connect(self.profilePushButton[i], SIGNAL("clicked()"), self.copyTable) def copyTable(self): #Writing the table to clipboard in excel form nr = int( self.sender().objectName() ) self.clipboard = QApplication.clipboard() text = "band" rowNames = self.profiles[nr].keys() rowNames.remove("layer") rowNames.remove("l") for name in rowNames: text += "\t"+name text += "\n" for i in range( len(self.profiles[nr]["l"]) ): text += str(self.profiles[nr]["l"][i]) for j in range(len(rowNames)): text += "\t" + str(self.profiles[nr][rowNames[j]][i]) text += "\n" self.clipboard.setText(text) def reScalePlot(self, param): # called when a spinbox value changed if type(param) != float: # don't execute it twice, for both valueChanged(int) and valueChanged(str) signals return if self.dockwidget.sbMinVal.value() == self.dockwidget.sbMaxVal.value() == 0: # don't execute it on init return PlottingTool().reScalePlot(self.dockwidget, self.profiles, self.model, self.library, autoMode = False)
QTreeView if __name__ == "__main__": app = QApplication(sys.argv) phonebook = {"Arthur": "Camelot", "Monty": "The Circus", "David": "Oslo"} model = QStandardItemModel(6, 4) row = 0 for name, address in phonebook.items(): model.setData(model.index(row, 0), QVariant(name)) model.setData(model.index(row, 1), QVariant(address)) font = QFont() font.setPointSize(16) font.setBold(True) model.setData(model.index(row, 0), QVariant(font), Qt.FontRole) model.setData(model.index(row, 1), QVariant(font), Qt.FontRole) row += 1 model.setHeaderData(0, Qt.Horizontal, QVariant("Name")) model.setHeaderData(1, Qt.Horizontal, QVariant("Address")) tree = QTreeView() tree.setModel(model) tree.show()
class ListPairTableView(QTableView): """ 2-column table view that enables pairing of list data through combo boxes. """ def __init__(self, parent=None): QTableView.__init__(self, parent) self.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked) self.setSelectionBehavior(QAbstractItemView.SelectRows) self._pair_model = QStandardItemModel(1, 2, self) self._pair_model.dataChanged.connect(self._on_pair_data_changed) self.setModel(self._pair_model) self.horizontalHeader().setResizeMode(QHeaderView.Stretch) self._combo_delegate = PairComboBoxDelegate(self) self.setItemDelegate(self._combo_delegate) def set_header_labels(self, labels): """ Set the table's header labels using labels. :param labels: Header labels. :type labels: list """ if len(labels) < 2: return lbls = [] for i in range(2): lbls.append(labels[i]) self._pair_model.setHorizontalHeaderLabels(lbls) def clear_view(self): """ Clears all row pairings in the view. """ rows = self._pair_model.rowCount() self._pair_model.removeRows(0, rows) # Insert blank row self.append_row() def append_row(self): """ Add a blank row after the last item in the view. """ items = [QStandardItem(), QStandardItem()] self._pair_model.appendRow(items) def set_combo_selection(self, selection, empty_item=True): """ Set combo selection for both columns. Any existing rows will be removed from the view. :param selection: A list containing two sub-lists for each column that correspond to the selection list for the combobox in each column. :type selection: list :param empty_item: True to insert an empty first item in each of the column comboboxes. :type empty_item: bool """ self._combo_delegate.set_items_pair(selection, empty_item) self.clear_view() def _on_pair_data_changed(self, old_index, new_index): """ This slot asserts whether selections in both columns in a row have been specified. If true, then automatically adds a new empty row for additional entries; If false, then the empty is removed from the view. :param old_index: Model index :type old_index: QModelIndex :param new_index: Model index :type new_index: QModelIndex """ row_state = self.row_data_state(new_index.row()) row_data = self.row_data(new_index.row()) if row_state == 0: self._pair_model.removeRows(new_index.row(), 1) if self._pair_model.rowCount() == 0: self.append_row() elif row_state == 2: if not self.is_last_row_empty(): self.append_row() def is_last_row_empty(self): """ :return: True if the last row in the view does not contain any data, False if one or both columns contains data. :rtype: bool """ last_row_idx = self._pair_model.rowCount() - 1 last_row_state = self.row_data_state(last_row_idx) if last_row_state == 0: return True else: return False def row_data_state(self, row_index): """ :param row_index: Row position :type row_index: int :return: 0 if data for each of the columns is empty. 1 if one column contains data and the other is empty. 2 if both columns contain data. :rtype: int """ col_0_val, col_1_val = self.row_data(row_index) if col_0_val is None and col_1_val is None: return 0 elif self._is_empty(col_0_val) and not self._is_empty(col_1_val): return 1 elif not self._is_empty(col_0_val) and self._is_empty(col_1_val): return 1 elif self._is_empty(col_0_val) and self._is_empty(col_1_val): return 0 elif not self._is_empty(col_0_val) and not self._is_empty(col_1_val): return 2 def _is_empty(self, val): if val is None: return True else: if (isinstance(val, str) or isinstance(val, unicode)) and not val: return True return False def row_data(self, row_index): """ :param row_index: Row position :type row_index: int :return: Data in both first and second columns for the specified row. :rtype: tuple """ if row_index >= 0: idx_col_0 = self._pair_model.index(row_index, 0) idx_col_1 = self._pair_model.index(row_index, 1) val_0 = self._pair_model.data(idx_col_0) val_1 = self._pair_model.data(idx_col_1) return val_0, val_1 else: return None, None def column_pairings(self): """ :return: Collection of column matchings specified as specified by the user. :rtype: dict """ col_pairings = {} for row_idx in range(self._pair_model.rowCount()): if self.row_data_state(row_idx) != 0: col_val_0, col_val_1 = self.row_data(row_idx) col_pairings[col_val_0] = col_val_1 return col_pairings
class FormWidget(ui_formwidget.Ui_Form, WidgetBase): def __init__(self, parent=None): super(FormWidget, self).__init__(parent) self.setupUi(self) self.form = None self.iconlabel.mouseReleaseEvent = self.change_icon self._currentwidgetid = '' self.fieldsmodel = QgsFieldModel() self.widgetmodel = WidgetsModel() self.possiblewidgetsmodel = QStandardItemModel() self.formlayersmodel = QgsLayerModel(watchregistry=True) self.formlayers = CaptureLayerFilter() self.formlayers.setSourceModel(self.formlayersmodel) self.layerCombo.setModel(self.formlayers) self.useablewidgets.setModel(self.possiblewidgetsmodel) self.fieldList.setModel(self.fieldsmodel) self.userwidgets.setModel(self.widgetmodel) self.userwidgets.selectionModel().currentChanged.connect(self.load_widget) self.widgetmodel.rowsRemoved.connect(self.set_widget_config_state) self.widgetmodel.rowsInserted.connect(self.set_widget_config_state) self.widgetmodel.modelReset.connect(self.set_widget_config_state) self.addWidgetButton.pressed.connect(self.newwidget) self.addSectionButton.pressed.connect(self.add_section) self.removeWidgetButton.pressed.connect(self.removewidget) self.formfolderLabel.linkActivated.connect(self.openformfolder) self.expressionButton.clicked.connect(self.opendefaultexpression) self.expressionButton_2.clicked.connect(self.opendefaultexpression_advanced) self.fieldList.currentIndexChanged.connect(self.updatewidgetname) self.fieldwarninglabel.hide() self.formtab.currentChanged.connect(self.formtabchanged) for item, data in readonlyvalues: self.readonlyCombo.addItem(item, data) for item, data in defaultevents: self.defaultEventsCombo.addItem(item, data) self.loadwidgettypes() self.formLabelText.textChanged.connect(self.form_name_changed) self.newStyleCheck.stateChanged.connect(self.form_style_changed) self.layerCombo.currentIndexChanged.connect(self.layer_updated) # Gross but ok for now. self.blockWidgets = [ self.fieldList, self.nameText, self.sectionNameText, self.useablewidgets, self.hiddenCheck, self.requiredCheck, self.readonlyCombo, self.defaultEventsCombo, self.defaultvalueText, self.defaultLayerCombo, self.defaultFieldCombo, self.defaultValueExpression, self.savevalueCheck ] for widget in self.blockWidgets: self._connect_save_event(widget) self.blockWidgetSignels(True) self.useablewidgets.currentIndexChanged.connect(self.swapwidgetconfig) menu = QMenu("Field Actions") action = menu.addAction("Auto add all fields") action.triggered.connect(self.auto_add_fields) self.addWidgetButton.setMenu(menu) self.addWidgetButton.setPopupMode(QToolButton.MenuButtonPopup) self.defaultLayerCombo.layerChanged.connect(self.defaultFieldCombo.setLayer) self.addEvent.pressed.connect(self.addEventItem) self.btnDeleteForm.pressed.connect(ConfigEvents.deleteForm.emit) def unload_project(self): print "UNLOAD PROJECT!!!" self.blockWidgetSignels(True) def _connect_save_event(self, widget): if hasattr(widget, "textChanged"): widget.textChanged.connect(self._save_current_widget) if hasattr(widget, "currentIndexChanged"): widget.currentIndexChanged.connect(self._save_current_widget) if hasattr(widget, "stateChanged"): widget.stateChanged.connect(self._save_current_widget) def change_icon(self, *args): """ Change the icon for the form """ icon = QFileDialog.getOpenFileName(self, "Select form icon image", filter="Images (*.png *.svg)") if not icon: return ext = os.path.splitext(icon)[1] shutil.copy(icon, os.path.join(self.form.folder, "icon" + ext)) self.set_icon(self.form.icon) self.treenode.emitDataChanged() def set_icon(self, path): """ Set the forms icon preview :param path: The path to icon. """ pixmap = QPixmap(path) w = self.iconlabel.width() h = self.iconlabel.height() self.iconlabel.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio)) def layer_updated(self, index): """ Called when the forms layer has changed. :param index: The index of the new layer. """ if not self.selected_layer: return self.updatefields(self.selected_layer) def form_style_changed(self, newstyle): """ Called when the form style has changed from label-above style to label-beside style. :param newstyle: True if to use the new label-above style forms. """ self.form.settings['newstyle'] = newstyle self.treenode.emitDataChanged() def form_name_changed(self, text): """ Called when the forms name has changed. Also updates the tree view to reflect the new name. :param text: The new text of the label. :return: """ self.form.settings['label'] = text self.treenode.emitDataChanged() def updatewidgetname(self, index): """ Update the widget name if the field has changed. Doesn't change the name if it has been user set already. :param index: index of the new field. """ # Only change the edit text on name field if it's not already set to something other then the # field name. field = self.fieldsmodel.index(index, 0).data(QgsFieldModel.FieldNameRole) currenttext = self.nameText.text() foundfield = self.fieldsmodel.findfield(currenttext) if foundfield: self.nameText.setText(field) def opendefaultexpression_advanced(self): """ Open the default expression builder for setting advanced default values based on QGIS Expressions. """ layer = self.form.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultValueExpression.text() dlg.setExpressionText(text) if dlg.exec_(): self.defaultValueExpression.setText(dlg.expressionText()) def opendefaultexpression(self): """ Open the default expression builder for setting default values based on QGIS Expressions. """ layer = self.form.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultvalueText.text().strip('[%').strip('%]').strip() dlg.setExpressionText(text) if dlg.exec_(): self.defaultvalueText.setText('[% {} %]'.format(dlg.expressionText())) def formtabchanged(self, index): """ Called when the tab widget changes tab. Normally used to control when to render the form preview on demand. :param index: The index of the new tab. """ # Don't generate the form preview if we are not on the preview tab. if index == 3: self.generate_form_preview() def generate_form_preview(self): """ Create the form preview to show to the user. """ form = self.form.copy() form.settings['widgets'] = list(self.widgetmodel.widgets()) item = self.frame_2.layout().itemAt(0) if item and item.widget(): item.widget().setParent(None) featureform = FeatureForm.from_form(form, form.settings, None, {}) from roam import defaults defaultwidgets = form.widgetswithdefaults() layer = form.QGISLayer try: values = {} feature = layer.getFeatures().next() defaultvalues = defaults.default_values(defaultwidgets, feature, layer) values.update(defaultvalues) featureform.bindvalues(values) except StopIteration: pass self.frame_2.layout().addWidget(featureform) def usedfields(self): """ Return the list of fields that have been used by the the current form's widgets """ widgets = self.widgetmodel.widgets() for widget in widgets: if 'field' in widget: yield widget['field'] def openformfolder(self, url): """ Open the form folder using the OS file manager. :param url: :return: """ QDesktopServices.openUrl(QUrl.fromLocalFile(self.form.folder)) def loadwidgettypes(self): """ Load all supported widgets into the combobox for the form designer. :return: """ self.useablewidgets.blockSignals(True) for widgettype in roam.editorwidgets.core.supportedwidgets(): try: configclass = configmanager.editorwidgets.widgetconfigs[widgettype] except KeyError: continue configwidget = configclass() item = QStandardItem(widgettype) item.setData(configwidget, Qt.UserRole) item.setData(widgettype, Qt.UserRole + 1) item.setIcon(QIcon(widgeticon(widgettype))) self.useablewidgets.model().appendRow(item) self.widgetstack.addWidget(configwidget) self.useablewidgets.blockSignals(False) def set_widget_config_state(self, *args): """ Enable or disable the widget config section based on widget count :param args: Unused. :return: """ haswidgets = self.widgetmodel.rowCount() > 0 self.widgetConfigTabs.setEnabled(haswidgets) def add_section(self): """ Add a new widget section into the form. Widget sections can be used to group widgets on the form together. """ currentindex = self.userwidgets.currentIndex() widget = {"widget": "Section", "name": "default"} index = self.widgetmodel.addwidget(widget, currentindex.parent()) self.userwidgets.setCurrentIndex(index) def newwidget(self, field=None): """ Create a new widget. Tries to match the field type to the right kind of widget as a best guess. """ mapping = {QVariant.String: "Text", QVariant.Int: "Number", QVariant.Double: "Number(Double)", QVariant.ByteArray: "Image", QVariant.Date: "Date", QVariant.DateTime: "Date"} widget = {} if not field: field = self.fieldsmodel.index(0, 0).data(Qt.UserRole) if not field: return widget['field'] = field.name() else: widget['field'] = field.name() try: widget['widget'] = mapping[field.type()] except KeyError: widget['widget'] = 'Text' # Grab the first field. widget['name'] = field.name().replace("_", " ").title() currentindex = self.userwidgets.currentIndex() currentitem = self.widgetmodel.itemFromIndex(currentindex) if currentitem and currentitem.iscontainor(): parent = currentindex else: parent = currentindex.parent() index = self.widgetmodel.addwidget(widget, parent) self.userwidgets.setCurrentIndex(index) def auto_add_fields(self): """ Auto add all fields to the form config. Any missing fields will be added. """ used = list(self.usedfields()) for field in self.selected_layer.pendingFields(): if field.name() in used: continue self.newwidget(field) def removewidget(self): """ Remove the selected widget from the widgets list """ widget, index = self.currentuserwidget if index.isValid(): self.widgetmodel.removeRow(index.row(), index.parent()) def set_project(self, project, treenode): """ Set the project for this widget also sets the form from the tree node. :note: This method is called from the parent node when the page and widget is loaded. :param project: The current project.j :param treenode: The current tree node. Can be used to signel a update back to the tree for it to update it self. """ roam.utils.debug("FormWidget: Set Project") self.blockWidgetSignels(True) super(FormWidget, self).set_project(project, treenode) self.formlayers.setSelectLayers(self.project.selectlayers) form = self.treenode.form self.form = form self.setform(self.form) self.blockWidgetSignels(False) def blockWidgetSignels(self, blocking): for widget in self.blockWidgets: widget.blockSignals(blocking) def updatefields(self, layer): """ Update the UI with the fields for the selected layer. """ self.fieldsmodel.setLayer(layer) def setform(self, form): """ Update the UI with the currently selected form. """ def getfirstlayer(): """ Get the first layer from the forms layer combo box """ index = self.formlayers.index(0, 0) layer = index.data(Qt.UserRole) layer = layer.name() return layer def loadwidgets(widget): """ Load the widgets into widgets model """ self.widgetmodel.clear() self.widgetmodel.loadwidgets(form.widgets) def findlayer(layername): """ Find the layer with the same name in the layer combobox widget """ index = self.formlayersmodel.findlayer(layername) index = self.formlayers.mapFromSource(index) layer = index.data(Qt.UserRole) return index, layer settings = form.settings label = form.label layername = settings.setdefault('layer', getfirstlayer()) layerindex, layer = findlayer(layername) if not layer or not layerindex.isValid(): return formtype = settings.setdefault('type', 'auto') widgets = settings.setdefault('widgets', []) newstyleform = settings.setdefault('newstyle', True) self.set_icon(form.icon) self.formLabelText.setText(label) folderurl = "<a href='{path}'>{name}</a>".format(path=form.folder, name=os.path.basename(form.folder)) self.formfolderLabel.setText(folderurl) self.newStyleCheck.setChecked(newstyleform) self.layerCombo.setCurrentIndex(layerindex.row()) self.updatefields(layer) if formtype == "auto": formtype = "Auto Generated" index = self.formtypeCombo.findText(formtype) if index == -1: self.formtypeCombo.insertItem(0, formtype) self.formtypeCombo.setCurrentIndex(0) else: self.formtypeCombo.setCurrentIndex(index) loadwidgets(widgets) # Set the first widget index = self.widgetmodel.index(0, 0) if index.isValid(): self.userwidgets.setCurrentIndex(index) # self.load_widget(index, None) for i in reversed(range(self.eventsLayout.count())): child = self.eventsLayout.itemAt(i) if child.widget() and isinstance(child.widget(), EventWidget): child = self.eventsLayout.takeAt(i) child.widget().deleteLater() events = settings.get('events', []) self.load_events(events) ## This has overhead so only do it when the tab is active. if self.formtab.currentIndex() == 3: self.generate_form_preview() def load_events(self, events): for event in events: self.addEventItem(data=event) def addEventItem(self, data=None): widget = EventWidget(self.form.QGISLayer, self.widgetmodel, self.eventsWidget) widget.removeItem.connect(self.removeEventItem) widget.set_data(data) self.eventsLayout.addWidget(widget) def removeEventItem(self, widget): child = self.eventsLayout.removeWidget(widget) widget.deleteLater() def swapwidgetconfig(self, index): widgetconfig, _, _ = self.current_config_widget defaultvalue = widgetconfig.defaultvalue self.defaultvalueText.setText(defaultvalue) self.updatewidgetconfig({}) def load_widget(self, index, last): """ Update the UI with the config for the current selected widget. """ self.blockWidgetSignels(True) if last: roam.utils.debug("Saving last widget") self._save_widget(last) widget = index.data(Qt.UserRole) if not widget: self.blockWidgetSignels(False) return try: roam.utils.debug("Loading widget: {0}".format(widget['_id'])) except KeyError: pass widgettype = widget['widget'] if widgettype == "Section": self.propertiesStack.setCurrentIndex(1) self.sectionNameText.blockSignals(True) name = widget['name'] self.sectionNameText.setText(name) self.sectionNameText.blockSignals(False) return else: self.propertiesStack.setCurrentIndex(0) field = widget['field'] self._currentwidgetid = widget.setdefault('_id', str(uuid.uuid4())) required = widget.setdefault('required', False) savevalue = widget.setdefault('rememberlastvalue', False) name = widget.setdefault('name', field) default = widget.setdefault('default', '') readonly = widget.setdefault('read-only-rules', []) hidden = widget.setdefault('hidden', False) defaultevents = widget.setdefault('default_events', ['capture']) try: data = readonly[0] except IndexError: data = 'never' index = self.readonlyCombo.findData(data) self.readonlyCombo.setCurrentIndex(index) index = self.defaultEventsCombo.findData(defaultevents) self.defaultEventsCombo.setCurrentIndex(index) if not isinstance(default, dict): self.defaultTab.setCurrentIndex(0) self.defaultvalueText.setText(default) else: self.defaultTab.setCurrentIndex(1) layer = default['layer'] # TODO Handle the case of many layer fall though with defaults # Not sure how to handle this in the UI just yet if isinstance(layer, list): layer = layer[0] if isinstance(layer, basestring): defaultfield = default['field'] expression = default['expression'] self.defaultValueExpression.setText(expression) layer = roam.api.utils.layer_by_name(layer) # self.defaultLayerCombo.setLayer(layer) self.defaultFieldCombo.setLayer(layer) self.defaultFieldCombo.setField(defaultfield) self.nameText.setText(name) self.requiredCheck.setChecked(required) self.savevalueCheck.setChecked(savevalue) self.hiddenCheck.setChecked(hidden) if field is not None: index = self.fieldList.findData(field.lower(), QgsFieldModel.FieldNameRole) if index > -1: self.fieldList.setCurrentIndex(index) else: self.fieldList.setEditText(field) index = self.useablewidgets.findText(widgettype) if index > -1: self.useablewidgets.setCurrentIndex(index) config = widget.get('config', {}) self.updatewidgetconfig(config) self.blockWidgetSignels(False) @property def currentuserwidget(self): """ Return the selected user widget. """ index = self.userwidgets.currentIndex() return index.data(Qt.UserRole), index @property def current_config_widget(self): """ Return the selected widget in the widget combo. """ index = self.useablewidgets.currentIndex() index = self.possiblewidgetsmodel.index(index, 0) return index.data(Qt.UserRole), index, index.data(Qt.UserRole + 1) def updatewidgetconfig(self, config): configwidget, _, _ = self.current_config_widget self.setconfigwidget(configwidget, config) def setconfigwidget(self, configwidget, config): """ Set the active config widget. """ try: configwidget.widgetdirty.disconnect(self._save_current_widget) except TypeError: pass self.widgetstack.setCurrentWidget(configwidget) configwidget.setconfig(config) configwidget.widgetdirty.connect(self._save_current_widget) def _save_current_widget(self, *args): _, index = self.currentuserwidget self._save_widget(index) def _save_widget(self, index): # roam.utils.debug("FormWidget: Save widget") print("SENDER: {}".format(self.sender().objectName())) if not self.project: return widgetdata = self._get_widget_config() try: roam.utils.debug("Saving widget {} in project {}".format(widgetdata['_id'], self.project.name)) except KeyError: pass self.widgetmodel.setData(index, widgetdata, Qt.UserRole) def _get_default_config(self): if self.defaultTab.currentIndex() == 0: return self.defaultvalueText.text() else: default = {} default['layer'] = self.defaultLayerCombo.currentLayer().name() default['field'] = self.defaultFieldCombo.currentField() default['expression'] = self.defaultValueExpression.text() default['type'] = 'layer-value' return default def _get_widget_config(self): def current_field(): row = self.fieldList.currentIndex() field = self.fieldsmodel.index(row, 0).data(QgsFieldModel.FieldNameRole) return field configwidget, _, widgettype = self.current_config_widget if self.propertiesStack.currentIndex() == 1: return {'name': self.sectionNameText.text(), "widget": "Section"} widget = {} widget['field'] = current_field() widget['default'] = self._get_default_config() widget['widget'] = widgettype widget['required'] = self.requiredCheck.isChecked() widget['rememberlastvalue'] = self.savevalueCheck.isChecked() widget['_id'] = self._currentwidgetid widget['name'] = self.nameText.text() widget['read-only-rules'] = [self.readonlyCombo.itemData(self.readonlyCombo.currentIndex())] widget['default_events'] = self.defaultEventsCombo.itemData(self.defaultEventsCombo.currentIndex()) widget['hidden'] = self.hiddenCheck.isChecked() widget['config'] = configwidget.getconfig() return widget @property def selected_layer(self): index = self.formlayers.index(self.layerCombo.currentIndex(), 0) layer = index.data(Qt.UserRole) return layer def write_config(self): roam.utils.debug("Write form config") if not self.selected_layer: return self._save_current_widget() self.form.settings['layer'] = self.selected_layer.name() formtype = self.formtypeCombo.currentText() self.form.settings['type'] = "auto" if formtype == "Auto Generated" else formtype self.form.settings['label'] = self.formLabelText.text() self.form.settings['newstyle'] = self.newStyleCheck.isChecked() self.form.settings['widgets'] = list(self.widgetmodel.widgets()) events = [] for i in range(self.eventsLayout.count()): child = self.eventsLayout.itemAt(i) if child.widget() and isinstance(child.widget(), EventWidget): widget = child.widget() eventdata = widget.get_data() events.append(eventdata) self.form.settings['events'] = events
class Dialog_report(QDialog, Ui_Dialog_report): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor """ QDialog.__init__(self, parent) self.setupUi(self) #construct Customer list class self.clist = Customer_list() #construct accounting class self.caccount = Dfile() #construct customer price class self.cprice = Customer_price() #construct standard table self.tablemodel = QStandardItemModel(31, len(PRODUCT_NAME)) self.setTableheader() #save customer list int self.list_customer = self.clist.readCompany() self.setCombo(1, self.list_customer) def setMode(self, str_mode): if str_mode == 'init': self.clearAllshow() def setCombo(self, comboselect, m_str): """ set combo box """ if comboselect == 1: for i in m_str: self.comboBox_name.addItem(i) elif comboselect == 2: self.comboBox_date.clear() for i in m_str: self.comboBox_date.addItem(i) def clearAllshow(self): #clear all spin box self.setAllspin(0) #clear table self.clearTableview() def setAllspin(self, int_value): self.spinBox_1.setValue(int_value) self.spinBox_2.setValue(int_value) self.spinBox_3.setValue(int_value) self.spinBox_4.setValue(int_value) self.spinBox_5.setValue(int_value) self.spinBox_6.setValue(int_value) self.spinBox_7.setValue(int_value) self.spinBox_8.setValue(int_value) self.spinBox_9.setValue(int_value) self.spinBox_10.setValue(int_value) self.spinBox_11.setValue(int_value) self.spinBox_12.setValue(int_value) self.spinBox_13.setValue(int_value) self.spinBox_14.setValue(int_value) self.spinBox_15.setValue(int_value) self.spinBox_16.setValue(int_value) self.spinBox_17.setValue(int_value) self.spinBox_18.setValue(int_value) self.spinBox_19.setValue(int_value) self.spinBox_19.setValue(0) def setTableheader(self): #set header data self.tablemodel.setHeaderData(0, Qt.Horizontal, PRODUCT_NAME[0]) self.tablemodel.setHeaderData(1, Qt.Horizontal, PRODUCT_NAME[1]) self.tablemodel.setHeaderData(2, Qt.Horizontal, PRODUCT_NAME[2]) self.tablemodel.setHeaderData(3, Qt.Horizontal, PRODUCT_NAME[3]) self.tablemodel.setHeaderData(4, Qt.Horizontal, PRODUCT_NAME[4]) self.tablemodel.setHeaderData(5, Qt.Horizontal, PRODUCT_NAME[5]) def setTableview(self, dlist_data): """ set data into tableview model """ #show data row = 0 for i in dlist_data: self.tablemodel.setData(self.tablemodel.index(row, 0), QVariant(i[0])) self.tablemodel.setData(self.tablemodel.index(row, 1), QVariant(i[1])) self.tablemodel.setData(self.tablemodel.index(row, 2), QVariant(i[2])) self.tablemodel.setData(self.tablemodel.index(row, 3), QVariant(i[3])) self.tablemodel.setData(self.tablemodel.index(row, 4), QVariant(i[4])) self.tablemodel.setData(self.tablemodel.index(row, 5), QVariant(i[5])) row += 1 #set table into tableview self.tableView.setModel(self.tablemodel) def clearTableview(self): """ clear table """ #show data row = 0 i = [0, 0, 0, 0, 0, 0] for row in range(31): self.tablemodel.setData(self.tablemodel.index(row, 0), QVariant(i[0])) self.tablemodel.setData(self.tablemodel.index(row, 1), QVariant(i[1])) self.tablemodel.setData(self.tablemodel.index(row, 2), QVariant(i[2])) self.tablemodel.setData(self.tablemodel.index(row, 3), QVariant(i[3])) self.tablemodel.setData(self.tablemodel.index(row, 4), QVariant(i[4])) self.tablemodel.setData(self.tablemodel.index(row, 5), QVariant(i[5])) #set table into tableview self.tableView.setModel(self.tablemodel) @pyqtSignature("QString") def on_comboBox_name_currentIndexChanged(self, p0): """ when name index change, set combo date """ #set to initial status self.setMode('init') #read combo text and dict value self.str_customercombo = str(self.comboBox_name.currentText().toUtf8()) self.i_customercombo = self.clist.readCvalue(self.str_customercombo) #read all guest accounting data self.list_date = self.caccount.listDatafile(self.i_customercombo) self.setCombo(2, self.list_date) @pyqtSignature("QString") def on_comboBox_date_currentIndexChanged(self, p0): """ search price data and load accounting into table """ self.str_filename = str(self.comboBox_date.currentText()) if self.str_filename != '': self.str_datecombo = self.str_filename[3:9] #get price version self.i_priceversion = self.cprice.selectPrice( self.i_customercombo, self.str_datecombo) #get price dict dict_price = self.cprice.readPrice(self.i_customercombo, self.i_priceversion) self.list_price = self.cprice.getClist(dict_price) #show price self.setPricespin(self.list_price) #show table self.caccount.open_dfile(self.str_filename) self.table_data = self.caccount.read_alldfile() self.setTableview(self.table_data) #calculate and show single amount self.eachamount = self.sumEachamount(self.table_data) self.setEachamount(self.eachamount) #calculate single price amount self.eachpriceamount = [ self.eachamount[i] * self.list_price[i] for i in range(len(PRODUCT_NAME)) ] self.setEachpriceamount(self.eachpriceamount) #show in total income self.spinBox_19.setValue(sum(self.eachpriceamount)) def setPricespin(self, list): self.spinBox_1.setValue(list[0]) self.spinBox_2.setValue(list[1]) self.spinBox_3.setValue(list[2]) self.spinBox_4.setValue(list[3]) self.spinBox_5.setValue(list[4]) self.spinBox_6.setValue(list[5]) def setEachamount(self, list): self.spinBox_7.setValue(list[0]) self.spinBox_8.setValue(list[1]) self.spinBox_9.setValue(list[2]) self.spinBox_10.setValue(list[3]) self.spinBox_11.setValue(list[4]) self.spinBox_12.setValue(list[5]) def setEachpriceamount(self, list): self.spinBox_13.setValue(list[0]) self.spinBox_14.setValue(list[1]) self.spinBox_15.setValue(list[2]) self.spinBox_16.setValue(list[3]) self.spinBox_17.setValue(list[4]) self.spinBox_18.setValue(list[5]) #sum each item total amount def sumEachamount(self, duallist): eachamount = [0, 0, 0, 0, 0, 0] count = 0 for i in duallist: for j in i: eachamount[count] += j count += 1 count = 0 return eachamount
class QMapManager(QDialog): def __init__(self, config, parent=None): QDialog.__init__(self, parent) curdir = os.path.abspath(os.path.dirname(__file__)) PyQt4.uic.loadUi(os.path.join(curdir,'manager.ui'), self) self.model = QStandardItemModel() self.projectsmodel = QStandardItemModel() self.projectlist.setModel(self.projectsmodel) self.clientlist.setModel(self.model) self.clientlist.selectionModel().selectionChanged.connect(self.update) self.installbutton.pressed.connect(self.installToClient) self.mapper = QDataWidgetMapper() self.mapper.setModel(self.model) self.mapper.addMapping(self.installpath, 1) self.config = config self.populateProjects() self.populateClients() def installToClient(self): index = self.clientlist.selectionModel().currentIndex() item = self.model.itemFromIndex(index) print "Deploying to " + item.text() build.deployTargetByName(item.text()) def update(self, selected, deselected ): index = selected.indexes()[0] self.mapper.setCurrentModelIndex(index) item = self.model.itemFromIndex(index) settings = item.data() for row in xrange(0,self.projectsmodel.rowCount()): index = self.projectsmodel.index(row, 0) item = self.projectsmodel.itemFromIndex(index) item.setCheckState(Qt.Unchecked) projects = settings['projects'] for project in projects: if project == "All": i = 0 while self.projectsmodel.item(i): item = self.projectsmodel.item(i) item.setCheckState(Qt.Checked) i += 1 break projectitem = self.projectsmodel.findItems(project)[0] projectitem.setCheckState(Qt.Checked) def populateClients(self): row = 0 for client, settings in self.config['clients'].iteritems(): name = QStandardItem(client) name.setData(settings) path = QStandardItem(settings['path']) self.model.insertRow(row, [name, path]) row += 1 def populateProjects(self): row = 0 for project in getProjects(): projectitem = QStandardItem(project.name) projectitem.setCheckable(True) self.projectsmodel.insertRow(row, projectitem) row += 1
class OWConfusionMatrix(widget.OWWidget): name = "Confusion Matrix" description = "Display confusion matrix constructed from results " \ "of evaluation of classifiers." 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"] selected_learner = settings.Setting([]) 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.widgetBox(self.controlArea, "Learners") self.learners_box = gui.listBox( box, self, "selected_learner", "learners", callback=self._learner_changed ) box = gui.widgetBox(self.controlArea, "Show") gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.widgetBox(self.controlArea, "Select") gui.button(box, self, "Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "None", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.widgetBox(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 Data", "Auto send is on") 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.clicked.connect(self.cell_clicked) grid.addWidget(view, 0, 0) self.mainArea.layout().addLayout(grid) def sizeHint(self): 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 set_results(self, results): """Set the input results.""" self.clear() self.warning([0, 1]) data = None if results is not None: if results.data is not None: data = results.data if data is not None and not data.domain.has_discrete_class: data = None results = None self.warning( 0, "Confusion Matrix cannot be used for 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 not None: nmodels, ntests = results.predicted.shape 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 #%i" % (i + 1) for i in range(nmodels)] 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, len(class_values)) self.tableview.setSpan(2, 0, len(class_values), 1) 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.setData(QBrush(QColor(208, 208, 208)), Qt.BackgroundColorRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) 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(len(class_values) + 3) self.tablemodel.setColumnCount(len(class_values) + 3) self.selected_learner = [0] self._update() def clear(self): self.results = None self.data = None self.tablemodel.clear() self.headers = [] # Clear learners last. This action will invoke `_learner_changed` # method self.learners = [] def select_correct(self): 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): 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): self.tableview.selectionModel().clear() def cell_clicked(self, model_index): 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): 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 selected_learner = self.selected_learner[0] learner_name = self.learners[selected_learner] predicted = self.results.predicted[selected_learner] 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[selected_learner, 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): self.commit() def _learner_changed(self): # The selected learner has changed indices = self.tableview.selectedIndexes() self._update() selection = QItemSelection() for sel in indices: selection.select(sel, sel) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect ) self.commit() def _update(self): # Update the displayed confusion matrix if self.results is not None and self.selected_learner: index = self.selected_learner[0] cmatrix = confusion_matrix(self.results, index) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) total = rowsum.sum() if self.selected_quantity == 0: value = lambda i, j: int(cmatrix[i, j]) elif self.selected_quantity == 1: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i]) if colsum[i] else "N/A") elif self.selected_quantity == 2: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i]) if colsum[i] else "N/A") else: assert False for i, row in enumerate(cmatrix): for j, _ in enumerate(row): item = self._item(i + 2, j + 2) item.setData(value(i, j), Qt.DisplayRole) 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) model = self.tablemodel font = model.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) def sum_item(value): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) return item N = len(colsum) for i in range(N): model.setItem(N + 2, i + 2, sum_item(int(colsum[i]))) model.setItem(i + 2, N + 2, sum_item(int(rowsum[i]))) model.setItem(N + 2, N + 2, sum_item(int(total)))
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 FormWidget(ui_formwidget.Ui_Form, WidgetBase): def __init__(self, parent=None): super(FormWidget, self).__init__(parent) self.setupUi(self) self.form = None self.fieldsmodel = QgsFieldModel() self.widgetmodel = WidgetsModel() self.possiblewidgetsmodel = QStandardItemModel() self.formlayersmodel = QgsLayerModel(watchregistry=True) self.formlayers = CaptureLayerFilter() self.formlayers.setSourceModel(self.formlayersmodel) self.layerCombo.setModel(self.formlayers) self.useablewidgets.setModel(self.possiblewidgetsmodel) self.fieldList.setModel(self.fieldsmodel) self.userwidgets.setModel(self.widgetmodel) self.userwidgets.selectionModel().currentChanged.connect(self.load_widget) self.widgetmodel.rowsRemoved.connect(self.setwidgetconfigvisiable) self.widgetmodel.rowsInserted.connect(self.setwidgetconfigvisiable) self.widgetmodel.modelReset.connect(self.setwidgetconfigvisiable) self.addWidgetButton.pressed.connect(self.newwidget) self.removeWidgetButton.pressed.connect(self.removewidget) self.formfolderLabel.linkActivated.connect(self.openformfolder) self.expressionButton.clicked.connect(self.opendefaultexpression) self.fieldList.currentIndexChanged.connect(self.updatewidgetname) self.fieldwarninglabel.hide() self.formtab.currentChanged.connect(self.formtabchanged) for item, data in readonlyvalues: self.readonlyCombo.addItem(item, data) self.loadwidgettypes() self.formLabelText.textChanged.connect(self.form_name_changed) self.layerCombo.currentIndexChanged.connect(self.layer_updated) self.fieldList.currentIndexChanged.connect(self._save_current_widget) self.nameText.textChanged.connect(self._save_current_widget) self.useablewidgets.currentIndexChanged.connect(self._save_current_widget) self.useablewidgets.currentIndexChanged.connect(self.swapwidgetconfig) menu = QMenu("Field Actions") action = menu.addAction("Auto add all fields") action.triggered.connect(self.auto_add_fields) self.addWidgetButton.setMenu(menu) self.addWidgetButton.setPopupMode(QToolButton.MenuButtonPopup) self.defaultLayerCombo.layerChanged.connect(self.default_layer_changed) def default_layer_changed(self, layer): self.defaultFieldCombo.setLayer(layer) def layer_updated(self, index): if not self.selected_layer: return self.updatefields(self.selected_layer) def form_name_changed(self, text): self.form.settings['label'] = self.formLabelText.text() self.treenode.emitDataChanged() def updatewidgetname(self, index): # Only change the edit text on name field if it's not already set to something other then the # field name. field = self.fieldsmodel.index(index, 0).data(QgsFieldModel.FieldNameRole) currenttext = self.nameText.text() foundfield = self.fieldsmodel.findfield(currenttext) if foundfield: self.nameText.setText(field) def opendefaultexpression(self): layer = self.form.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultvalueText.text().strip('[%').strip('%]').strip() dlg.setExpressionText(text) if dlg.exec_(): self.defaultvalueText.setText('[% {} %]'.format(dlg.expressionText())) def formtabchanged(self, index): def setformpreview(form): item = self.frame_2.layout().itemAt(0) if item and item.widget(): item.widget().setParent(None) featureform = FeatureForm.from_form(form, form.settings, None, {}) from roam import defaults defaultwidgets = form.widgetswithdefaults() layer = form.QGISLayer try: values = {} feature = layer.getFeatures().next() defaultvalues = defaults.default_values(defaultwidgets, feature, layer) values.update(defaultvalues) featureform.bindvalues(values) except StopIteration: pass self.frame_2.layout().addWidget(featureform) if index == 1: self.form.settings['widgets'] = list(self.widgetmodel.widgets()) setformpreview(self.form) def usedfields(self): """ Return the list of fields that have been used by the the current form's widgets """ widgets = self.widgetmodel.widgets() for widget in widgets: yield widget['field'] def openformfolder(self, url): QDesktopServices.openUrl(QUrl.fromLocalFile(self.form.folder)) def loadwidgettypes(self): self.useablewidgets.blockSignals(True) for widgettype in roam.editorwidgets.core.supportedwidgets(): try: configclass = configmanager.editorwidgets.widgetconfigs[widgettype] except KeyError: continue configwidget = configclass() item = QStandardItem(widgettype) item.setData(configwidget, Qt.UserRole) item.setData(widgettype, Qt.UserRole + 1) item.setIcon(QIcon(widgeticon(widgettype))) self.useablewidgets.model().appendRow(item) self.widgetstack.addWidget(configwidget) self.useablewidgets.blockSignals(False) def setwidgetconfigvisiable(self, *args): haswidgets = self.widgetmodel.rowCount() > 0 self.widgetConfigTabs.setVisible(haswidgets) def newwidget(self, field=None): """ Create a new widget. The default is a list. """ mapping = {QVariant.String: "Text", QVariant.Int: "Number", QVariant.Double: "Number(Double)", QVariant.ByteArray: "Image", QVariant.Date: "Date", QVariant.DateTime: "Date"} widget = {} if not field: field = self.fieldsmodel.index(0, 0).data(Qt.UserRole) if not field: return widget['field'] = field.name() else: widget['field'] = field.name() try: widget['widget'] = mapping[field.type()] except KeyError: widget['widget'] = 'Text' # Grab the first field. widget['name'] = field.name().replace("_", " ").title() currentindex = self.userwidgets.currentIndex() currentitem = self.widgetmodel.itemFromIndex(currentindex) if currentitem and currentitem.iscontainor(): parent = currentindex else: parent = currentindex.parent() index = self.widgetmodel.addwidget(widget, parent) self.userwidgets.setCurrentIndex(index) def auto_add_fields(self): used = list(self.usedfields()) for field in self.selected_layer.pendingFields(): if field.name() in used: continue self.newwidget(field) def removewidget(self): """ Remove the selected widget from the widgets list """ widget, index = self.currentuserwidget if index.isValid(): self.widgetmodel.removeRow(index.row(), index.parent()) def set_project(self, project, treenode): super(FormWidget, self).set_project(project, treenode) self.formlayers.setSelectLayers(self.project.selectlayers) form = self.treenode.form self.form = form self.setform(self.form) def updatefields(self, layer): """ Update the UI with the fields for the selected layer. """ self.fieldsmodel.setLayer(layer) def setform(self, form): """ Update the UI with the currently selected form. """ def getfirstlayer(): index = self.formlayers.index(0, 0) layer = index.data(Qt.UserRole) layer = layer.name() return layer def loadwidgets(widget): """ Load the widgets into widgets model """ self.widgetmodel.clear() self.widgetmodel.loadwidgets(form.widgets) def findlayer(layername): index = self.formlayersmodel.findlayer(layername) index = self.formlayers.mapFromSource(index) layer = index.data(Qt.UserRole) return index, layer settings = form.settings label = form.label layername = settings.setdefault('layer', getfirstlayer()) layerindex, layer = findlayer(layername) if not layer or not layerindex.isValid(): return formtype = settings.setdefault('type', 'auto') widgets = settings.setdefault('widgets', []) self.formLabelText.setText(label) folderurl = "<a href='{path}'>{name}</a>".format(path=form.folder, name=os.path.basename(form.folder)) self.formfolderLabel.setText(folderurl) self.layerCombo.setCurrentIndex(layerindex.row()) self.updatefields(layer) index = self.formtypeCombo.findText(formtype) if index == -1: self.formtypeCombo.insertItem(0, formtype) self.formtypeCombo.setCurrentIndex(0) else: self.formtypeCombo.setCurrentIndex(index) loadwidgets(widgets) # Set the first widget index = self.widgetmodel.index(0, 0) if index.isValid(): self.userwidgets.setCurrentIndex(index) self.load_widget(index, None) def swapwidgetconfig(self, index): widgetconfig, _, _ = self.current_config_widget defaultvalue = widgetconfig.defaultvalue self.defaultvalueText.setText(defaultvalue) self.updatewidgetconfig({}) def load_widget(self, index, last): """ Update the UI with the config for the current selected widget. """ self.fieldList.blockSignals(True) self.nameText.blockSignals(True) self.useablewidgets.blockSignals(True) if last: self._save_widget(last) widget = index.data(Qt.UserRole) if not widget: self.fieldList.blockSignals(False) self.nameText.blockSignals(False) self.useablewidgets.blockSignals(False) return widgettype = widget['widget'] field = widget['field'] required = widget.setdefault('required', False) savevalue = widget.setdefault('rememberlastvalue', False) name = widget.setdefault('name', field) default = widget.setdefault('default', '') readonly = widget.setdefault('read-only-rules', []) hidden = widget.setdefault('hidden', False) try: data = readonly[0] except IndexError: data = 'never' index = self.readonlyCombo.findData(data) self.readonlyCombo.setCurrentIndex(index) if not isinstance(default, dict): self.defaultTab.setCurrentIndex(0) self.defaultvalueText.setText(default) else: self.defaultTab.setCurrentIndex(1) layer = default['layer'] # TODO Handle the case of many layer fall though with defaults # Not sure how to handle this in the UI just yet if isinstance(layer, list): layer = layer[0] if isinstance(layer, basestring): field = default['field'] expression = default['expression'] self.defaultValueExpression.setText(expression) layer = roam.api.utils.layer_by_name(layer) self.defaultLayerCombo.setLayer(layer) self.defaultFieldCombo.setLayer(layer) self.defaultFieldCombo.setField(field) self.nameText.setText(name) self.requiredCheck.setChecked(required) self.savevalueCheck.setChecked(savevalue) self.hiddenCheck.setChecked(hidden) if field is not None: index = self.fieldList.findData(field.lower(), QgsFieldModel.FieldNameRole) if index > -1: self.fieldList.setCurrentIndex(index) else: self.fieldList.setEditText(field) index = self.useablewidgets.findText(widgettype) if index > -1: self.useablewidgets.setCurrentIndex(index) config = widget.get('config', {}) self.updatewidgetconfig(config) self.fieldList.blockSignals(False) self.nameText.blockSignals(False) self.useablewidgets.blockSignals(False) @property def currentuserwidget(self): """ Return the selected user widget. """ index = self.userwidgets.currentIndex() return index.data(Qt.UserRole), index @property def current_config_widget(self): """ Return the selected widget in the widget combo. """ index = self.useablewidgets.currentIndex() index = self.possiblewidgetsmodel.index(index, 0) return index.data(Qt.UserRole), index, index.data(Qt.UserRole + 1) def updatewidgetconfig(self, config): configwidget, _, _ = self.current_config_widget self.setconfigwidget(configwidget, config) def setconfigwidget(self, configwidget, config): """ Set the active config widget. """ try: configwidget.widgetdirty.disconnect(self._save_current_widget) except TypeError: pass self.widgetstack.setCurrentWidget(configwidget) configwidget.setconfig(config) configwidget.widgetdirty.connect(self._save_current_widget) def _save_current_widget(self, *args): _, index = self.currentuserwidget self._save_widget(index) def _save_widget(self, index): widgetdata = self._get_widget_config() self.widgetmodel.setData(index, widgetdata, Qt.UserRole) def _get_default_config(self): if self.defaultTab.currentIndex() == 0: return self.defaultvalueText.text() else: default = {} default['layer'] = self.defaultLayerCombo.currentLayer().name() default['field'] = self.defaultFieldCombo.currentField() default['expression'] = self.defaultValueExpression.text() default['type'] = 'layer-value' return default def _get_widget_config(self): def current_field(): row = self.fieldList.currentIndex() field = self.fieldsmodel.index(row, 0).data(QgsFieldModel.FieldNameRole) return field configwidget, _, widgettype = self.current_config_widget widget = {} widget['field'] = current_field() widget['default'] = self._get_default_config() widget['widget'] = widgettype widget['required'] = self.requiredCheck.isChecked() widget['rememberlastvalue'] = self.savevalueCheck.isChecked() widget['name'] = self.nameText.text() widget['read-only-rules'] = [self.readonlyCombo.itemData(self.readonlyCombo.currentIndex())] widget['hidden'] = self.hiddenCheck.isChecked() widget['config'] = configwidget.getconfig() return widget @property def selected_layer(self): index = self.formlayers.index(self.layerCombo.currentIndex(), 0) layer = index.data(Qt.UserRole) return layer def write_config(self): if not self.selected_layer: return self._save_current_widget() self.form.settings['layer'] = self.selected_layer.name() self.form.settings['type'] = self.formtypeCombo.currentText() self.form.settings['label'] = self.formLabelText.text() self.form.settings['widgets'] = list(self.widgetmodel.widgets())
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 ProjectWidget(Ui_Form, QWidget): SampleWidgetRole = Qt.UserRole + 1 projectsaved = pyqtSignal() projectupdated = pyqtSignal() projectloaded = pyqtSignal(object) selectlayersupdated = pyqtSignal(list) def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) self.setupUi(self) self.project = None self.mapisloaded = False self.bar = None self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.canvas.mapRenderer().setLabelingEngine(QgsPalLabeling()) self.fieldsmodel = QgsFieldModel() self.widgetmodel = WidgetsModel() self.possiblewidgetsmodel = QStandardItemModel() self.formlayersmodel = QgsLayerModel(watchregistry=False) self.formlayers = CaptureLayerFilter() self.formlayers.setSourceModel(self.formlayersmodel) self.selectlayermodel = CaptureLayersModel(watchregistry=False) self.selectlayerfilter = LayerTypeFilter() self.selectlayerfilter.setSourceModel(self.selectlayermodel) self.selectlayermodel.dataChanged.connect(self.selectlayerschanged) self.layerCombo.setModel(self.formlayers) self.widgetCombo.setModel(self.possiblewidgetsmodel) self.selectLayers.setModel(self.selectlayerfilter) self.selectLayers_2.setModel(self.selectlayerfilter) self.fieldList.setModel(self.fieldsmodel) self.widgetlist.setModel(self.widgetmodel) self.widgetlist.selectionModel().currentChanged.connect(self.updatecurrentwidget) self.widgetmodel.rowsRemoved.connect(self.setwidgetconfigvisiable) self.widgetmodel.rowsInserted.connect(self.setwidgetconfigvisiable) self.widgetmodel.modelReset.connect(self.setwidgetconfigvisiable) self.titleText.textChanged.connect(self.updatetitle) QgsProject.instance().readProject.connect(self._readproject) self.loadwidgettypes() self.addWidgetButton.pressed.connect(self.newwidget) self.removeWidgetButton.pressed.connect(self.removewidget) self.roamVersionLabel.setText("You are running IntraMaps Roam version {}".format(roam.__version__)) self.openProjectFolderButton.pressed.connect(self.openprojectfolder) self.openinQGISButton.pressed.connect(self.openinqgis) self.filewatcher = QFileSystemWatcher() self.filewatcher.fileChanged.connect(self.qgisprojectupdated) self.formfolderLabel.linkActivated.connect(self.openformfolder) self.projectupdatedlabel.linkActivated.connect(self.reloadproject) self.projectupdatedlabel.hide() self.formtab.currentChanged.connect(self.formtabchanged) self.expressionButton.clicked.connect(self.opendefaultexpression) self.fieldList.currentIndexChanged.connect(self.updatewidgetname) self.fieldwarninglabel.hide() for item, data in readonlyvalues: self.readonlyCombo.addItem(item, data) self.setpage(4) self.form = None def setaboutinfo(self): self.versionLabel.setText(roam.__version__) self.qgisapiLabel.setText(str(QGis.QGIS_VERSION)) def checkcapturelayers(self): haslayers = self.project.hascapturelayers() self.formslayerlabel.setVisible(not haslayers) return haslayers def opendefaultexpression(self): layer = self.currentform.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultvalueText.text().strip('[%').strip('%]').strip() dlg.setExpressionText(text) if dlg.exec_(): self.defaultvalueText.setText('[% {} %]'.format(dlg.expressionText())) def openformfolder(self, url): openfolder(url) def selectlayerschanged(self, *args): self.formlayers.setSelectLayers(self.project.selectlayers) self.checkcapturelayers() self.selectlayersupdated.emit(self.project.selectlayers) def formtabchanged(self, index): # preview if index == 1: self.form.settings['widgets'] = list(self.widgetmodel.widgets()) self.setformpreview(self.form) def setpage(self, page): self.stackedWidget.setCurrentIndex(page) def reloadproject(self, *args): self.setproject(self.project) def qgisprojectupdated(self, path): self.projectupdatedlabel.show() self.projectupdatedlabel.setText("The QGIS project has been updated. <a href='reload'> " "Click to reload</a>. <b style=\"color:red\">Unsaved data will be lost</b>") def openinqgis(self): projectfile = self.project.projectfile qgislocation = r'C:\OSGeo4W\bin\qgis.bat' qgislocation = roam.config.settings.setdefault('configmanager', {}) \ .setdefault('qgislocation', qgislocation) try: openqgis(projectfile, qgislocation) except WindowsError: self.bar.pushMessage("Looks like I couldn't find QGIS", "Check qgislocation in roam.config", QgsMessageBar.WARNING) def openprojectfolder(self): folder = self.project.folder openfolder(folder) def setwidgetconfigvisiable(self, *args): haswidgets = self.widgetmodel.rowCount() > 0 self.widgetframe.setEnabled(haswidgets) def removewidget(self): """ Remove the selected widget from the widgets list """ widget, index = self.currentuserwidget if index.isValid(): self.widgetmodel.removeRow(index.row(), index.parent()) def newwidget(self): """ Create a new widget. The default is a list. """ widget = {} widget['widget'] = 'Text' # Grab the first field. widget['field'] = self.fieldsmodel.index(0, 0).data(QgsFieldModel.FieldNameRole) currentindex = self.widgetlist.currentIndex() currentitem = self.widgetmodel.itemFromIndex(currentindex) if currentitem and currentitem.iscontainor(): parent = currentindex else: parent = currentindex.parent() index = self.widgetmodel.addwidget(widget, parent) self.widgetlist.setCurrentIndex(index) def loadwidgettypes(self): self.widgetCombo.blockSignals(True) for widgettype in roam.editorwidgets.core.supportedwidgets(): try: configclass = configmanager.editorwidgets.widgetconfigs[widgettype] except KeyError: continue configwidget = configclass() item = QStandardItem(widgettype) item.setData(configwidget, Qt.UserRole) item.setData(widgettype, Qt.UserRole + 1) item.setIcon(QIcon(widgeticon(widgettype))) self.widgetCombo.model().appendRow(item) self.widgetstack.addWidget(configwidget) self.widgetCombo.blockSignals(False) def usedfields(self): """ Return the list of fields that have been used by the the current form's widgets """ for widget in self.currentform.widgets: yield widget['field'] @property def currentform(self): """ Return the current selected form. """ return self.form @property def currentuserwidget(self): """ Return the selected user widget. """ index = self.widgetlist.currentIndex() return index.data(Qt.UserRole), index @property def currentwidgetconfig(self): """ Return the selected widget in the widget combo. """ index = self.widgetCombo.currentIndex() index = self.possiblewidgetsmodel.index(index, 0) return index.data(Qt.UserRole), index, index.data(Qt.UserRole + 1) def updatewidgetname(self, index): # Only change the edit text on name field if it's not already set to something other then the # field name. field = self.fieldsmodel.index(index, 0).data(QgsFieldModel.FieldNameRole) currenttext = self.nameText.text() foundfield = self.fieldsmodel.findfield(currenttext) if foundfield: self.nameText.setText(field) def _save_widgetfield(self, index): """ Save the selected field for the current widget. Shows a error if the field is already used but will allow the user to still set it in the case of extra logic for that field in the forms Python logic. """ widget, index = self.currentuserwidget row = self.fieldList.currentIndex() field = self.fieldsmodel.index(row, 0).data(QgsFieldModel.FieldNameRole) showwarning = field in self.usedfields() self.fieldwarninglabel.setVisible(showwarning) widget['field'] = field self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_selectedwidget(self, index): configwidget, index, widgettype = self.currentwidgetconfig widget, index = self.currentuserwidget if not widget: return widget['widget'] = widgettype widget['required'] = self.requiredCheck.isChecked() widget['config'] = configwidget.getconfig() widget['name'] = self.nameText.text() widget['read-only-rules'] = [self.readonlyCombo.itemData(self.readonlyCombo.currentIndex())] widget['hidden'] = self.hiddenCheck.isChecked() self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_default(self): widget, index = self.currentuserwidget default = self.defaultvalueText.text() widget['default'] = default self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_selectionlayers(self, index, layer, value): config = self.project.settings self.selectlayermodel.dataChanged.emit(index, index) def _save_formtype(self, index): formtype = self.formtypeCombo.currentText() form = self.currentform form.settings['type'] = formtype def _save_formname(self, text): """ Save the form label to the settings file. """ try: form = self.currentform if form is None: return form.settings['label'] = text self.projectupdated.emit() except IndexError: return def _save_layer(self, index): """ Save the selected layer to the settings file. """ index = self.formlayers.index(index, 0) layer = index.data(Qt.UserRole) if not layer: return form = self.currentform if form is None: return form.settings['layer'] = layer.name() self.updatefields(layer) def setsplash(self, splash): pixmap = QPixmap(splash) w = self.splashlabel.width() h = self.splashlabel.height() self.splashlabel.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) def setproject(self, project, loadqgis=True): """ Set the widgets active project. """ self.disconnectsignals() self.mapisloaded = False self.filewatcher.removePaths(self.filewatcher.files()) self.projectupdatedlabel.hide() self._closeqgisproject() if project.valid: self.startsettings = copy.deepcopy(project.settings) self.project = project self.projectlabel.setText(project.name) self.versionText.setText(project.version) self.selectlayermodel.config = project.settings self.formlayers.setSelectLayers(self.project.selectlayers) self.setsplash(project.splash) self.loadqgisproject(project, self.project.projectfile) self.filewatcher.addPath(self.project.projectfile) self.projectloaded.emit(self.project) def loadqgisproject(self, project, projectfile): QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def _closeqgisproject(self): if self.canvas.isDrawing(): return self.canvas.freeze(True) self.formlayersmodel.removeall() self.selectlayermodel.removeall() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.freeze(False) def loadmap(self): if self.mapisloaded: return # This is a dirty hack to work around the timer that is in QgsMapCanvas in 2.2. # Refresh will stop the canvas timer # Repaint will redraw the widget. # loadmap is only called once per project load so it's safe to do this here. self.canvas.refresh() self.canvas.repaint() parser = roam.projectparser.ProjectParser.fromFile(self.project.projectfile) canvasnode = parser.canvasnode self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) self.canvas.updateScale() self.canvas.refresh() self.mapisloaded = True def _readproject(self, doc): self.formlayersmodel.refresh() self.selectlayermodel.refresh() self._updateforproject(self.project) def _updateforproject(self, project): self.titleText.setText(project.name) self.descriptionText.setPlainText(project.description) def swapwidgetconfig(self, index): widgetconfig, _, _ = self.currentwidgetconfig defaultvalue = widgetconfig.defaultvalue self.defaultvalueText.setText(defaultvalue) self.updatewidgetconfig({}) def updatetitle(self, text): self.project.settings['title'] = text self.projectlabel.setText(text) self.projectupdated.emit() def updatewidgetconfig(self, config): widgetconfig, index, widgettype = self.currentwidgetconfig self.setconfigwidget(widgetconfig, config) def setformpreview(self, form): def removewidget(): item = self.frame_2.layout().itemAt(0) if item and item.widget(): item.widget().setParent(None) removewidget() featureform = FeatureForm.from_form(form, form.settings, None, {}) self.frame_2.layout().addWidget(featureform) def connectsignals(self): self.formLabelText.textChanged.connect(self._save_formname) self.layerCombo.currentIndexChanged.connect(self._save_layer) self.formtypeCombo.currentIndexChanged.connect(self._save_formtype) #widget settings self.fieldList.currentIndexChanged.connect(self._save_widgetfield) self.requiredCheck.toggled.connect(self._save_selectedwidget) self.defaultvalueText.textChanged.connect(self._save_default) self.widgetCombo.currentIndexChanged.connect(self._save_selectedwidget) self.widgetCombo.currentIndexChanged.connect(self.swapwidgetconfig) self.nameText.textChanged.connect(self._save_selectedwidget) self.readonlyCombo.currentIndexChanged.connect(self._save_selectedwidget) self.hiddenCheck.toggled.connect(self._save_selectedwidget) def disconnectsignals(self): try: self.formLabelText.textChanged.disconnect(self._save_formname) self.layerCombo.currentIndexChanged.disconnect(self._save_layer) self.formtypeCombo.currentIndexChanged.disconnect(self._save_formtype) #widget settings self.fieldList.currentIndexChanged.disconnect(self._save_widgetfield) self.requiredCheck.toggled.disconnect(self._save_selectedwidget) self.defaultvalueText.textChanged.disconnect(self._save_default) self.widgetCombo.currentIndexChanged.disconnect(self._save_selectedwidget) self.widgetCombo.currentIndexChanged.disconnect(self.swapwidgetconfig) self.nameText.textChanged.disconnect(self._save_selectedwidget) self.readonlyCombo.currentIndexChanged.disconnect(self._save_selectedwidget) self.hiddenCheck.toggled.disconnect(self._save_selectedwidget) except TypeError: pass def setform(self, form): """ Update the UI with the currently selected form. """ def getfirstlayer(): index = self.formlayers.index(0,0) layer = index.data(Qt.UserRole) layer = layer.name() return layer def loadwidgets(widget): """ Load the widgets into widgets model """ self.widgetmodel.clear() self.widgetmodel.loadwidgets(form.widgets) def findlayer(layername): index = self.formlayersmodel.findlayer(layername) index = self.formlayers.mapFromSource(index) layer = index.data(Qt.UserRole) return index, layer self.disconnectsignals() self.form = form settings = form.settings label = form.label layername = settings.setdefault('layer', getfirstlayer()) layerindex, layer = findlayer(layername) if not layer or not layerindex.isValid(): return formtype = settings.setdefault('type', 'auto') widgets = settings.setdefault('widgets', []) self.formLabelText.setText(label) folderurl = "<a href='{path}'>{name}</a>".format(path=form.folder, name=os.path.basename(form.folder)) self.formfolderLabel.setText(folderurl) self.layerCombo.setCurrentIndex(layerindex.row()) self.updatefields(layer) index = self.formtypeCombo.findText(formtype) if index == -1: self.formtypeCombo.insertItem(0, formtype) self.formtypeCombo.setCurrentIndex(0) else: self.formtypeCombo.setCurrentIndex(index) loadwidgets(widgets) # Set the first widget index = self.widgetmodel.index(0, 0) if index.isValid(): self.widgetlist.setCurrentIndex(index) self.updatecurrentwidget(index, None) self.connectsignals() def updatefields(self, layer): """ Update the UI with the fields for the selected layer. """ self.fieldsmodel.setLayer(layer) def setconfigwidget(self, configwidget, config): """ Set the active config widget. """ try: configwidget.widgetdirty.disconnect(self._save_selectedwidget) except TypeError: pass #self.descriptionLabel.setText(configwidget.description) self.widgetstack.setCurrentWidget(configwidget) configwidget.setconfig(config) configwidget.widgetdirty.connect(self._save_selectedwidget) def updatecurrentwidget(self, index, _): """ Update the UI with the config for the current selected widget. """ if not index.isValid(): return widget = index.data(Qt.UserRole) widgettype = widget['widget'] field = widget['field'] required = widget.setdefault('required', False) name = widget.setdefault('name', field) default = widget.setdefault('default', '') readonly = widget.setdefault('read-only-rules', []) hidden = widget.setdefault('hidden', False) try: data = readonly[0] except: data = 'never' self.readonlyCombo.blockSignals(True) index = self.readonlyCombo.findData(data) self.readonlyCombo.setCurrentIndex(index) self.readonlyCombo.blockSignals(False) self.defaultvalueText.blockSignals(True) if not isinstance(default, dict): self.defaultvalueText.setText(default) self.defaultvalueText.setEnabled(True) self.expressionButton.setEnabled(True) else: # TODO Handle the more advanced default values. self.defaultvalueText.setText("Advanced default set in config") self.defaultvalueText.setEnabled(False) self.expressionButton.setEnabled(False) self.defaultvalueText.blockSignals(False) self.nameText.blockSignals(True) self.nameText.setText(name) self.nameText.blockSignals(False) self.requiredCheck.blockSignals(True) self.requiredCheck.setChecked(required) self.requiredCheck.blockSignals(False) self.hiddenCheck.blockSignals(True) self.hiddenCheck.setChecked(hidden) self.hiddenCheck.blockSignals(False) if not field is None: self.fieldList.blockSignals(True) index = self.fieldList.findData(field.lower(), QgsFieldModel.FieldNameRole) if index > -1: self.fieldList.setCurrentIndex(index) else: self.fieldList.setEditText(field) self.fieldList.blockSignals(False) index = self.widgetCombo.findText(widgettype) self.widgetCombo.blockSignals(True) if index > -1: self.widgetCombo.setCurrentIndex(index) self.widgetCombo.blockSignals(False) self.updatewidgetconfig(config=widget.setdefault('config', {})) def _saveproject(self): """ Save the project config to disk. """ title = self.titleText.text() description = self.descriptionText.toPlainText() version = str(self.versionText.text()) settings = self.project.settings settings['title'] = title settings['description'] = description settings['version'] = version form = self.currentform if form: form.settings['widgets'] = list(self.widgetmodel.widgets()) logger.debug(form.settings) self.project.save() self.projectsaved.emit()
class ListPairTableView(QTableView): """ 2-column table view that enables pairing of list data through combo boxes. """ def __init__(self, parent=None): QTableView.__init__(self, parent) self.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked) self.setSelectionBehavior(QAbstractItemView.SelectRows) self._pair_model = QStandardItemModel(1, 2, self) self._pair_model.dataChanged.connect(self._on_pair_data_changed) self.setModel(self._pair_model) self.horizontalHeader().setResizeMode(QHeaderView.Stretch) self._combo_delegate = PairComboBoxDelegate(self) self.setItemDelegate(self._combo_delegate) def set_header_labels(self, labels): """ Set the table's header labels using labels. :param labels: Header labels. :type labels: list """ if len(labels) < 2: return lbls = [] for i in range(2): lbls.append(labels[i]) self._pair_model.setHorizontalHeaderLabels(lbls) def clear_view(self): """ Clears all row pairings in the view. """ rows = self._pair_model.rowCount() self._pair_model.removeRows(0, rows) #Insert blank row self.append_row() def append_row(self): """ Add a blank row after the last item in the view. """ items = [QStandardItem(), QStandardItem()] self._pair_model.appendRow(items) def set_combo_selection(self, selection, empty_item=True): """ Set combo selection for both columns. Any existing rows will be removed from the view. :param selection: A list containing two sub-lists for each column that correspond to the selection list for the combobox in each column. :type selection: list :param empty_item: True to insert an empty first item in each of the column comboboxes. :type empty_item: bool """ self._combo_delegate.set_items_pair(selection, empty_item) self.clear_view() def _on_pair_data_changed(self, old_index, new_index): """ This slot asserts whether selections in both columns in a row have been specified. If true, then automatically adds a new empty row for additional entries; If false, then the empty is removed from the view. :param old_index: Model index :type old_index: QModelIndex :param new_index: Model index :type new_index: QModelIndex """ row_state = self.row_data_state(new_index.row()) row_data = self.row_data(new_index.row()) if row_state == 0: self._pair_model.removeRows(new_index.row(), 1) if self._pair_model.rowCount() == 0: self.append_row() elif row_state == 2: if not self.is_last_row_empty(): self.append_row() def is_last_row_empty(self): """ :return: True if the last row in the view does not contain any data, False if one or both columns contains data. :rtype: bool """ last_row_idx = self._pair_model.rowCount() - 1 last_row_state = self.row_data_state(last_row_idx) if last_row_state == 0: return True else: return False def row_data_state(self, row_index): """ :param row_index: Row position :type row_index: int :return: 0 if data for each of the columns is empty. 1 if one column contains data and the other is empty. 2 if both columns contain data. :rtype: int """ col_0_val, col_1_val = self.row_data(row_index) if col_0_val is None and col_1_val is None: return 0 elif self._is_empty(col_0_val) and not self._is_empty(col_1_val): return 1 elif not self._is_empty(col_0_val) and self._is_empty(col_1_val): return 1 elif self._is_empty(col_0_val) and self._is_empty(col_1_val): return 0 elif not self._is_empty(col_0_val) and not self._is_empty(col_1_val): return 2 def _is_empty(self, val): if val is None: return True else: if (isinstance(val, str) or isinstance(val, unicode)) and not val: return True return False def row_data(self, row_index): """ :param row_index: Row position :type row_index: int :return: Data in both first and second columns for the specified row. :rtype: tuple """ if row_index >= 0: idx_col_0 = self._pair_model.index(row_index, 0) idx_col_1 = self._pair_model.index(row_index, 1) val_0 = self._pair_model.data(idx_col_0) val_1 = self._pair_model.data(idx_col_1) return val_0, val_1 else: return None, None def column_pairings(self): """ :return: Collection of column matchings specified as specified by the user. :rtype: dict """ col_pairings = {} for row_idx in range(self._pair_model.rowCount()): if self.row_data_state(row_idx) != 0: col_val_0, col_val_1 = self.row_data(row_idx) col_pairings[col_val_0] = col_val_1 return col_pairings
class TreeLegend(QObject): toggledLegend = pyqtSignal(list) descriptionLegend = pyqtSignal(str) def __init__(self, treeView): def init(): self.setHeader() self.tree.setModel(self.model) self.headerView.setMovable(False) self.headerView.setClickable(True) self.tree.setSelectionMode(0) # no selection super(TreeLegend, self).__init__() self.tree = treeView # self.hasConnect = self.layer = self.legendItems = None self.visibleItems = [] self.model = QStandardItemModel(0, 1) self.headerView = self.tree.header() # init() self._connect() def __del__(self): if self.hasConnect: self._connect(False) self.model.clear() self.layer.legendChanged.disconnect(self.updateLegendItems) def _connect(self, isConnect=True): ss = [{ 'signal': self.tree.clicked, 'slot': self.toggleItem }, { 'signal': self.headerView.sectionClicked, 'slot': self.toggleHeader }, { 'signal': self.headerView.sectionDoubleClicked, 'slot': self.emitDescription }] if isConnect: self.hasConnect = True for item in ss: item['signal'].connect(item['slot']) else: self.hasConnect = False for item in ss: item['signal'].disconnect(item['slot']) def setHeader(self, data=None): if data is None: self.model.clear() nameHeader = 'Select Raster Layer(Palette)' font = QFont() font.setStrikeOut(False) headerModel = QStandardItem(nameHeader) headerModel.setData(font, Qt.FontRole) tip = "Raster with Palette(Single Band)" headerModel.setData(tip, Qt.ToolTipRole) self.model.setHorizontalHeaderItem(0, headerModel) else: headerModel = self.model.horizontalHeaderItem(0) label = "%s" % data['name'] formatMgs = "Layer: %s\nSource: %s\nNumber Class: %d\nWidth: %d\nHeight: %d\nRes.X: %f\nRes.Y: %f\n\n* Double click copy to Clipboard" dataMsg = (data['name'], data['source'], data['num_class'], data['width'], data['height'], data['resX'], data['resY']) tip = formatMgs % dataMsg headerModel.setData(data, Qt.UserRole) headerModel.setData(label, Qt.DisplayRole) headerModel.setData(tip, Qt.ToolTipRole) def setLayer(self, layer): self.legendItems = layer.legendSymbologyItems() total = len(self.legendItems) self.visibleItems = [True for x in range(total)] data = { 'name': layer.name(), 'source': layer.source(), 'num_class': total, 'width': layer.width(), 'height': layer.height(), 'resX': layer.rasterUnitsPerPixelX(), 'resY': layer.rasterUnitsPerPixelY() } self.setHeader(data) # if not self.layer is None: self.layer.legendChanged.disconnect(self.updateLegendItems) layer.legendChanged.connect(self.updateLegendItems) self.layer = layer def setLegend(self, values): def setHeader(): headerModel = self.model.horizontalHeaderItem(0) data = headerModel.data(Qt.UserRole) data['num_class'] = len(values) self.setHeader(data) def createItem(item): (pixel, total) = item (legend, color) = self.legendItems[pixel] name = "[%d] %s" % (pixel, legend) tip = "Value pixel: %d\nTotal pixels: %d\nClass name: %s" % ( pixel, total, legend) pix = QPixmap(16, 16) pix.fill(color) font.setStrikeOut(not self.visibleItems[pixel]) # itemModel = QStandardItem(QIcon(pix), name) itemModel.setEditable(False) itemModel.setData(font, Qt.FontRole) itemModel.setData(tip, Qt.ToolTipRole) itemModel.setData(item, Qt.UserRole) # return itemModel setHeader() self.model.removeRows(0, self.model.rowCount()) # font = QFont() for item in values: self.model.appendRow(createItem(item)) def setEnabled(self, isEnable=True): self._connect(isEnable) self.tree.setEnabled(isEnable) def getLayerName(self): headerModel = self.model.horizontalHeaderItem(0) return headerModel.data(Qt.UserRole)['name'] @pyqtSlot() def updateLegendItems(self): self.legendItems = self.layer.legendSymbologyItems() # Refresh legend rows = self.model.rowCount() row = 0 while row < rows: index = self.model.index(row, 0) (pixel, total) = self.model.data(index, Qt.UserRole) (legend, color) = self.legendItems[pixel] pix = QPixmap(16, 16) pix.fill(color) self.model.setData(index, QIcon(pix), Qt.DecorationRole) row += 1 @pyqtSlot('QModelIndex') def toggleItem(self, index): font = index.data(Qt.FontRole) strike = not font.strikeOut() font.setStrikeOut(strike) self.model.setData(index, font, Qt.FontRole) # (pixel, total) = index.data(Qt.UserRole) visible = not strike self.visibleItems[pixel] = visible # self.toggledLegend.emit(self.visibleItems) @pyqtSlot(int) def toggleHeader(self, logical): rowCount = self.model.rowCount() if rowCount == 0: return header = self.model.horizontalHeaderItem(0) font = header.data(Qt.FontRole) strike = not font.strikeOut() font.setStrikeOut(strike) header.setData(font, Qt.FontRole) # items = [] row = 0 while row < self.model.rowCount(): index = self.model.index(row, 0) self.model.setData(index, font, Qt.FontRole) items.append(index.data(Qt.UserRole)) row += 1 visible = not strike for item in items: (pixel, total) = item self.visibleItems[pixel] = visible # self.toggledLegend.emit(self.visibleItems) @pyqtSlot(int) def emitDescription(self): def getDescription(): data = self.model.horizontalHeaderItem(0).data(Qt.UserRole) formatMgs = "Layer: %s\nSource: %s\nNumber Class: %d\nWidth: %d\nHeight: %d\nRes.X: %f\nRes.Y: %f" dataMsg = (data['name'], data['source'], data['num_class'], data['width'], data['height'], data['resX'], data['resY']) descHeader = formatMgs % dataMsg # descItems = ["Value pixel;Total pixels;Class name"] rows = self.model.rowCount() row = 0 while row < rows: index = self.model.index(row, 0) (pixel, total) = self.model.data(index, Qt.UserRole) (legend, color) = self.legendItems[pixel] descItems.append("%d;%d;%s" % (pixel, total, legend)) row += 1 return "%s\n\n%s" % (descHeader, '\n'.join(descItems)) if self.model.rowCount() > 0: self.descriptionLegend.emit(getDescription())
class TemporalSpectralProfilePlugin: POINT_SELECTION = 0 SELECTED_POLYGON = 1 def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.wdg = None self.pointTool = None def initGui(self): # create action self.action = QAction( QIcon( ":/plugins/temporalprofiletool/icons/temporalProfileIcon.png"), "Temporal/Spectral Profile", self.iface.mainWindow()) self.action.setWhatsThis("Plots temporal/spectral profiles") QObject.connect(self.action, SIGNAL("triggered()"), self.run) self.aboutAction = QAction("About", self.iface.mainWindow()) QObject.connect(self.aboutAction, SIGNAL("triggered()"), self.about) # add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Profile Tool", self.action) self.iface.addPluginToMenu("&Profile Tool", self.aboutAction) #Init class variables self.pointTool = ProfiletoolMapTool(self.iface.mapCanvas(), self.action) #the mouselistener self.dockOpened = False #remember for not reopening dock if there's already one opened self.pointstoDraw = None #Polyline in mapcanvas CRS analysed self.dblclktemp = None #enable disctinction between leftclick and doubleclick self.mdl = None #the model whitch in are saved layers analysed caracteristics self.selectionmethod = 0 #The selection method defined in option self.saveTool = self.canvas.mapTool( ) #Save the standard mapttool for restoring it at the end self.plotlibrary = None #The plotting library to use self.pointSelectionInstructions = "Click on a raster for temporal/spectral profile (right click to cancel then quit)" self.selectedPolygonInstructions = 'Use "Select Features" tool to select polygon(s) designating AOI for which temporal/spectral profile should be calculated' def unload(self): if not self.wdg is None: self.wdg.close() self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu("&Profile Tool", self.action) self.iface.removePluginMenu("&Profile Tool", self.aboutAction) def run(self): # first, check posibility if self.checkIfOpening() == False: return #if dock not already opened, open the dock and all the necessary thing (model,doProfile...) if self.dockOpened == False: self.mdl = QStandardItemModel(0, 6) self.wdg = PTDockWidget(self.iface.mainWindow(), self.iface, self.mdl) self.wdg.showIt() self.doprofile = DoProfile(self.iface, self.wdg, self.pointTool, self) self.tableViewTool = TableViewTool() QObject.connect(self.wdg, SIGNAL("closed(PyQt_PyObject)"), self.cleaning2) QObject.connect(self.wdg.tableView, SIGNAL("clicked(QModelIndex)"), self._onClick) QObject.connect(self.wdg.pushButton_2, SIGNAL("clicked()"), self.addLayer) QObject.connect(self.wdg.pushButton, SIGNAL("clicked()"), self.removeLayer) QObject.connect(self.wdg.comboBox, SIGNAL("currentIndexChanged(int)"), self.selectionMethod) QObject.connect(self.wdg.cboLibrary, SIGNAL("currentIndexChanged(int)"), self.changePlotLibrary) QObject.connect(self.wdg.cboXAxis, SIGNAL("currentIndexChanged(int)"), self.changeXAxisLabeling) QObject.connect(self.wdg.leXAxisSteps, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.dateTimeEditCurrentTime, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.spinBoxTimeExtent, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.cboTimeExtent, SIGNAL("currentIndexChanged(int)"), self.changeXAxisLabeling) QObject.connect(self.wdg.cbTimeDimension, SIGNAL("stateChanged(int)"), self.changeXAxisLabeling) self.wdg.addOptionComboboxItems() self.addLayer() self.dockOpened = True #Listeners of mouse self.connectPointMapTool() #init the mouse listener comportement and save the classic to restore it on quit self.canvas.setMapTool(self.pointTool) #Help about what doing if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.iface.mainWindow().statusBar().showMessage( self.pointSelectionInstructions) elif self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: self.iface.mainWindow().statusBar().showMessage( self.selectedPolygonInstructions) QObject.connect(QgsMapLayerRegistry.instance(), SIGNAL("layersWillBeRemoved (QStringList)"), self.onLayersWillBeRemoved) #************************************* Canvas listener actions ********************************************** # Used when layer is about to be removed from QGIS Map Layer Registry def onLayersWillBeRemoved(self, layersIds): if self.mdl is not None: for layerId in layersIds: for row in range(self.mdl.rowCount()): if layerId == self.mdl.index(row, 3).data().id(): self.removeLayer(row) self.onLayersWillBeRemoved(layersIds) break # Use for selected polygon option def selectionChanged(self, layer): if not layer.geometryType() == QGis.Polygon: return fullGeometry = QgsGeometry() for feature in layer.selectedFeatures(): if fullGeometry.isEmpty(): fullGeometry = QgsGeometry(feature.constGeometry()) else: fullGeometry = fullGeometry.combine(feature.constGeometry()) if not fullGeometry.isEmpty(): crs = osr.SpatialReference() crs.ImportFromProj4(str(layer.crs().toProj4())) self.doprofile.calculatePolygonProfile(fullGeometry, crs, self.mdl, self.plotlibrary) #************************************* Mouse listener actions *********************************************** # Used for point selection option def moved(self, point): if self.wdg and not self.wdg.cbPlotWhenClick.isChecked(): if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.doubleClicked(point) if self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: pass def rightClicked(self, point): #used to quit the current action self.cleaning() def leftClicked(self, point): self.doubleClicked(point) def doubleClicked(self, point): if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.iface.mainWindow().statusBar().showMessage( str(point.x()) + ", " + str(point.y())) self.doprofile.calculatePointProfile(point, self.mdl, self.plotlibrary) if self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: return #***************************** open and quit options ******************************************* def checkIfOpening(self): if self.iface.mapCanvas().layerCount() == 0: #Check a layer is opened QMessageBox.warning(self.iface.mainWindow(), "Profile", "First open a raster layer, please") return False layer = self.iface.activeLayer() if layer == None or not isProfilable( layer): #Check if a raster layer is opened and selected if self.mdl == None or self.mdl.rowCount() == 0: QMessageBox.warning(self.iface.mainWindow(), "Profile Tool", "Please select a raster layer") return False return True def connectPointMapTool(self): QObject.connect(self.pointTool, SIGNAL("moved"), self.moved) QObject.connect(self.pointTool, SIGNAL("rightClicked"), self.rightClicked) QObject.connect(self.pointTool, SIGNAL("leftClicked"), self.leftClicked) QObject.connect(self.pointTool, SIGNAL("doubleClicked"), self.doubleClicked) QObject.connect(self.pointTool, SIGNAL("deactivate"), self.deactivatePointMapTool) def deactivatePointMapTool(self): #enable clean exit of the plugin QObject.disconnect(self.pointTool, SIGNAL("moved"), self.moved) QObject.disconnect(self.pointTool, SIGNAL("leftClicked"), self.leftClicked) QObject.disconnect(self.pointTool, SIGNAL("rightClicked"), self.rightClicked) QObject.disconnect(self.pointTool, SIGNAL("doubleClicked"), self.doubleClicked) self.iface.mainWindow().statusBar().showMessage("") def connectSelectedPolygonsTool(self): QObject.connect(self.iface.mapCanvas(), SIGNAL("selectionChanged(QgsMapLayer *)"), self.selectionChanged) def deactivateSelectedPolygonsTools(self): QObject.disconnect(self.iface.mapCanvas(), SIGNAL("selectionChanged(QgsMapLayer *)"), self.selectionChanged) def cleaning(self): #used on right click self.canvas.unsetMapTool(self.pointTool) self.canvas.setMapTool(self.saveTool) self.iface.mainWindow().statusBar().showMessage("") def cleaning2(self): #used when Dock dialog is closed QObject.disconnect(self.wdg.tableView, SIGNAL("clicked(QModelIndex)"), self._onClick) if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.deactivatePointMapTool() else: self.deactivateSelectedPolygonsTools() self.selectionmethod = TemporalSpectralProfilePlugin.POINT_SELECTION QObject.disconnect(self.wdg.comboBox, SIGNAL("currentIndexChanged(int)"), self.selectionMethod) QObject.disconnect(QgsMapLayerRegistry.instance(), SIGNAL("layersWillBeRemoved (QStringList)"), self.onLayersWillBeRemoved) self.mdl = None self.dockOpened = False self.cleaning() self.wdg = None #***************************** Options ******************************************* def selectionMethod(self, item): if item == TemporalSpectralProfilePlugin.POINT_SELECTION: self.selectionmethod = TemporalSpectralProfilePlugin.POINT_SELECTION self.pointTool.setCursor(Qt.CrossCursor) self.deactivateSelectedPolygonsTools() self.connectPointMapTool() if not self.canvas.mapTool() == self.pointTool: self.canvas.setMapTool(self.pointTool) self.iface.mainWindow().statusBar().showMessage( self.pointSelectionInstructions) self.wdg.changeStatComboBoxItems( self.doprofile.getPointProfileStatNames()) elif item == TemporalSpectralProfilePlugin.SELECTED_POLYGON: self.selectionmethod = TemporalSpectralProfilePlugin.SELECTED_POLYGON self.deactivatePointMapTool() self.connectSelectedPolygonsTool() self.iface.actionSelectRectangle().trigger() self.iface.mainWindow().statusBar().showMessage( self.selectedPolygonInstructions) self.wdg.changeStatComboBoxItems( self.doprofile.getPolygonProfileStatNames(), "mean") def changePlotLibrary(self, item): self.plotlibrary = self.wdg.cboLibrary.itemText(item) self.wdg.addPlotWidget(self.plotlibrary) self.changeXAxisLabeling() def changeXAxisLabeling(self): self.xAxisSteps = {} # default band number labeling if self.wdg.cboXAxis.currentIndex() == 0: self.doprofile.xAxisSteps = None # Labels from string elif self.wdg.cboXAxis.currentIndex() == 1: self.doprofile.xAxisSteps = self.wdg.leXAxisSteps.text().split(';') try: self.doprofile.xAxisSteps = [ float(x) for x in self.doprofile.xAxisSteps ] except ValueError: self.doprofile.xAxisSteps = None text = "Temporal/Spectral Profile Tool: The X-axis steps' string " + \ "is invalid. Using band numbers instead." self.iface.messageBar().pushWidget( self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) # Labels based on time elif self.wdg.cboXAxis.currentIndex() == 2: self.doprofile.xAxisSteps = [ "Timesteps", self.wdg.dateTimeEditCurrentTime.dateTime().toPyDateTime(), int(self.wdg.spinBoxTimeExtent.cleanText()), self.wdg.cboTimeExtent.currentText(), self.wdg.cbTimeDimension.isChecked() ] if self.plotlibrary == "Qwt5": text = "Temporal/Spectral Profile Tool: There is currently no support using " + \ "Time steps while using the Qwt plotlibrary" self.iface.messageBar().pushWidget( self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) self.doprofile.xAxisSteps = None #************************* tableview function ****************************************** def addLayer(self): layer = self.iface.activeLayer() if isProfilable(layer): self.tableViewTool.addLayer(self.iface, self.mdl, layer) def _onClick(self, index1): #action when clicking the tableview self.tableViewTool.onClick(self.iface, self.wdg, self.mdl, self.plotlibrary, index1) def removeLayer(self, index=None): if index is None: index = self.tableViewTool.chooseLayerForRemoval( self.iface, self.mdl) if index is not None: self.tableViewTool.removeLayer(self.mdl, index) PlottingTool().clearData(self.wdg, self.mdl, self.plotlibrary) def about(self): from ui.dlgabout import DlgAbout DlgAbout(self.iface.mainWindow()).exec_()
class TemporalSpectralProfilePlugin: POINT_SELECTION = 0 SELECTED_POLYGON = 1 def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.wdg = None self.pointTool = None def initGui(self): # create action self.action = QAction(QIcon(":/plugins/temporalprofiletool/icons/temporalProfileIcon.png"), "Temporal/Spectral Profile", self.iface.mainWindow()) self.action.setWhatsThis("Plots temporal/spectral profiles") QObject.connect(self.action, SIGNAL("triggered()"), self.run) self.aboutAction = QAction("About", self.iface.mainWindow()) QObject.connect(self.aboutAction, SIGNAL("triggered()"), self.about) # add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Profile Tool", self.action) self.iface.addPluginToMenu("&Profile Tool", self.aboutAction) #Init class variables self.pointTool = ProfiletoolMapTool(self.iface.mapCanvas(),self.action) #the mouselistener self.dockOpened = False #remember for not reopening dock if there's already one opened self.pointstoDraw = None #Polyline in mapcanvas CRS analysed self.dblclktemp = None #enable disctinction between leftclick and doubleclick self.mdl = None #the model whitch in are saved layers analysed caracteristics self.selectionmethod = 0 #The selection method defined in option self.saveTool = self.canvas.mapTool() #Save the standard mapttool for restoring it at the end self.plotlibrary = None #The plotting library to use self.pointSelectionInstructions = "Click on a raster for temporal/spectral profile (right click to cancel then quit)" self.selectedPolygonInstructions = 'Use "Select Features" tool to select polygon(s) designating AOI for which temporal/spectral profile should be calculated' def unload(self): if not self.wdg is None: self.wdg.close() self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu("&Profile Tool", self.action) self.iface.removePluginMenu("&Profile Tool", self.aboutAction) def run(self): # first, check posibility if self.checkIfOpening() == False: return #if dock not already opened, open the dock and all the necessary thing (model,doProfile...) if self.dockOpened == False: self.mdl = QStandardItemModel(0, 6) self.wdg = PTDockWidget(self.iface.mainWindow(), self.iface, self.mdl) self.wdg.showIt() self.doprofile = DoProfile(self.iface,self.wdg,self.pointTool, self) self.tableViewTool = TableViewTool() QObject.connect(self.wdg, SIGNAL( "closed(PyQt_PyObject)" ), self.cleaning2) QObject.connect(self.wdg.tableView,SIGNAL("clicked(QModelIndex)"), self._onClick) QObject.connect(self.wdg.pushButton_2, SIGNAL("clicked()"), self.addLayer) QObject.connect(self.wdg.pushButton, SIGNAL("clicked()"), self.removeLayer) QObject.connect(self.wdg.comboBox, SIGNAL("currentIndexChanged(int)"), self.selectionMethod) QObject.connect(self.wdg.cboLibrary, SIGNAL("currentIndexChanged(int)"), self.changePlotLibrary) QObject.connect(self.wdg.cboXAxis, SIGNAL("currentIndexChanged(int)"), self.changeXAxisLabeling) QObject.connect(self.wdg.leXAxisSteps, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.dateTimeEditCurrentTime, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.spinBoxTimeExtent, SIGNAL("editingFinished()"), self.changeXAxisLabeling) QObject.connect(self.wdg.cboTimeExtent, SIGNAL("currentIndexChanged(int)"), self.changeXAxisLabeling) QObject.connect(self.wdg.cbTimeDimension, SIGNAL("stateChanged(int)"), self.changeXAxisLabeling) self.wdg.addOptionComboboxItems() self.addLayer() self.dockOpened = True #Listeners of mouse self.connectPointMapTool() #init the mouse listener comportement and save the classic to restore it on quit self.canvas.setMapTool(self.pointTool) #Help about what doing if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.iface.mainWindow().statusBar().showMessage(self.pointSelectionInstructions ) elif self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: self.iface.mainWindow().statusBar().showMessage(self.selectedPolygonInstructions) QObject.connect(QgsMapLayerRegistry.instance(), SIGNAL("layersWillBeRemoved (QStringList)"), self.onLayersWillBeRemoved) #************************************* Canvas listener actions ********************************************** # Used when layer is about to be removed from QGIS Map Layer Registry def onLayersWillBeRemoved(self, layersIds): if self.mdl is not None: for layerId in layersIds: for row in range(self.mdl.rowCount()): if layerId == self.mdl.index(row, 3).data().id(): self.removeLayer(row) self.onLayersWillBeRemoved(layersIds) break # Use for selected polygon option def selectionChanged(self, layer): if not layer.geometryType() == QGis.Polygon: return fullGeometry = QgsGeometry() for feature in layer.selectedFeatures(): if fullGeometry.isEmpty(): fullGeometry = QgsGeometry(feature.constGeometry()) else: fullGeometry = fullGeometry.combine(feature.constGeometry()) if not fullGeometry.isEmpty(): crs = osr.SpatialReference() crs.ImportFromProj4(str(layer.crs().toProj4())) self.doprofile.calculatePolygonProfile(fullGeometry, crs, self.mdl, self.plotlibrary) #************************************* Mouse listener actions *********************************************** # Used for point selection option def moved(self, point): if self.wdg and not self.wdg.cbPlotWhenClick.isChecked(): if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.doubleClicked(point) if self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: pass def rightClicked(self, point): #used to quit the current action self.cleaning() def leftClicked(self, point): self.doubleClicked(point) def doubleClicked(self, point): if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.iface.mainWindow().statusBar().showMessage(str(point.x())+", "+str(point.y())) self.doprofile.calculatePointProfile(point, self.mdl, self.plotlibrary) if self.selectionmethod == TemporalSpectralProfilePlugin.SELECTED_POLYGON: return #***************************** open and quit options ******************************************* def checkIfOpening(self): if self.iface.mapCanvas().layerCount() == 0: #Check a layer is opened QMessageBox.warning(self.iface.mainWindow(), "Profile", "First open a raster layer, please") return False layer = self.iface.activeLayer() if layer == None or not isProfilable(layer) : #Check if a raster layer is opened and selected if self.mdl == None or self.mdl.rowCount() == 0: QMessageBox.warning(self.iface.mainWindow(), "Profile Tool", "Please select a raster layer") return False return True def connectPointMapTool(self): QObject.connect(self.pointTool, SIGNAL("moved"), self.moved) QObject.connect(self.pointTool, SIGNAL("rightClicked"), self.rightClicked) QObject.connect(self.pointTool, SIGNAL("leftClicked"), self.leftClicked) QObject.connect(self.pointTool, SIGNAL("doubleClicked"), self.doubleClicked) QObject.connect(self.pointTool, SIGNAL("deactivate"), self.deactivatePointMapTool) def deactivatePointMapTool(self): #enable clean exit of the plugin QObject.disconnect(self.pointTool, SIGNAL("moved"), self.moved) QObject.disconnect(self.pointTool, SIGNAL("leftClicked"), self.leftClicked) QObject.disconnect(self.pointTool, SIGNAL("rightClicked"), self.rightClicked) QObject.disconnect(self.pointTool, SIGNAL("doubleClicked"), self.doubleClicked) self.iface.mainWindow().statusBar().showMessage("") def connectSelectedPolygonsTool(self): QObject.connect(self.iface.mapCanvas(), SIGNAL("selectionChanged(QgsMapLayer *)"), self.selectionChanged) def deactivateSelectedPolygonsTools(self): QObject.disconnect(self.iface.mapCanvas(), SIGNAL("selectionChanged(QgsMapLayer *)"), self.selectionChanged) def cleaning(self): #used on right click self.canvas.unsetMapTool(self.pointTool) self.canvas.setMapTool(self.saveTool) self.iface.mainWindow().statusBar().showMessage("") def cleaning2(self): #used when Dock dialog is closed QObject.disconnect(self.wdg.tableView,SIGNAL("clicked(QModelIndex)"), self._onClick) if self.selectionmethod == TemporalSpectralProfilePlugin.POINT_SELECTION: self.deactivatePointMapTool() else: self.deactivateSelectedPolygonsTools() self.selectionmethod = TemporalSpectralProfilePlugin.POINT_SELECTION QObject.disconnect(self.wdg.comboBox, SIGNAL("currentIndexChanged(int)"), self.selectionMethod) QObject.disconnect(QgsMapLayerRegistry.instance(), SIGNAL("layersWillBeRemoved (QStringList)"), self.onLayersWillBeRemoved) self.mdl = None self.dockOpened = False self.cleaning() self.wdg = None #***************************** Options ******************************************* def selectionMethod(self,item): if item == TemporalSpectralProfilePlugin.POINT_SELECTION: self.selectionmethod = TemporalSpectralProfilePlugin.POINT_SELECTION self.pointTool.setCursor(Qt.CrossCursor) self.deactivateSelectedPolygonsTools() self.connectPointMapTool() if not self.canvas.mapTool() == self.pointTool: self.canvas.setMapTool(self.pointTool) self.iface.mainWindow().statusBar().showMessage(self.pointSelectionInstructions) self.wdg.changeStatComboBoxItems(self.doprofile.getPointProfileStatNames()) elif item == TemporalSpectralProfilePlugin.SELECTED_POLYGON: self.selectionmethod = TemporalSpectralProfilePlugin.SELECTED_POLYGON self.deactivatePointMapTool() self.connectSelectedPolygonsTool() self.iface.actionSelectRectangle().trigger() self.iface.mainWindow().statusBar().showMessage(self.selectedPolygonInstructions) self.wdg.changeStatComboBoxItems(self.doprofile.getPolygonProfileStatNames(), "mean") def changePlotLibrary(self, item): self.plotlibrary = self.wdg.cboLibrary.itemText(item) self.wdg.addPlotWidget(self.plotlibrary) self.changeXAxisLabeling() def changeXAxisLabeling(self): self.xAxisSteps = {} # default band number labeling if self.wdg.cboXAxis.currentIndex() == 0: self.doprofile.xAxisSteps = None # Labels from string elif self.wdg.cboXAxis.currentIndex() == 1: self.doprofile.xAxisSteps = self.wdg.leXAxisSteps.text().split(';') try: self.doprofile.xAxisSteps = [ float(x) for x in self.doprofile.xAxisSteps ] except ValueError: self.doprofile.xAxisSteps = None text = "Temporal/Spectral Profile Tool: The X-axis steps' string " + \ "is invalid. Using band numbers instead." self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) # Labels based on time elif self.wdg.cboXAxis.currentIndex() == 2: self.doprofile.xAxisSteps = ["Timesteps", self.wdg.dateTimeEditCurrentTime.dateTime().toPyDateTime(), int(self.wdg.spinBoxTimeExtent.cleanText()), self.wdg.cboTimeExtent.currentText(), self.wdg.cbTimeDimension.isChecked()] if self.plotlibrary == "Qwt5": text = "Temporal/Spectral Profile Tool: There is currently no support using " + \ "Time steps while using the Qwt plotlibrary" self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), QgsMessageBar.WARNING, 5) self.doprofile.xAxisSteps = None #************************* tableview function ****************************************** def addLayer(self): layer = self.iface.activeLayer() if isProfilable(layer): self.tableViewTool.addLayer(self.iface, self.mdl, layer) def _onClick(self,index1): #action when clicking the tableview self.tableViewTool.onClick(self.iface, self.wdg, self.mdl, self.plotlibrary, index1) def removeLayer(self, index = None): if index is None: index = self.tableViewTool.chooseLayerForRemoval(self.iface, self.mdl) if index is not None: self.tableViewTool.removeLayer(self.mdl, index) PlottingTool().clearData(self.wdg, self.mdl, self.plotlibrary) def about(self): from ui.dlgabout import DlgAbout DlgAbout(self.iface.mainWindow()).exec_()
class ProjectWidget(Ui_Form, QWidget): SampleWidgetRole = Qt.UserRole + 1 projectsaved = pyqtSignal() projectupdated = pyqtSignal() projectloaded = pyqtSignal(object) selectlayersupdated = pyqtSignal(list) projectlocationchanged = pyqtSignal(str) def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) self.setupUi(self) self.project = None self.mapisloaded = False self.bar = None self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.canvas.mapRenderer().setLabelingEngine(QgsPalLabeling()) self.fieldsmodel = QgsFieldModel() self.widgetmodel = WidgetsModel() self.possiblewidgetsmodel = QStandardItemModel() self.formlayersmodel = QgsLayerModel(watchregistry=False) self.formlayers = CaptureLayerFilter() self.formlayers.setSourceModel(self.formlayersmodel) self.selectlayermodel = CaptureLayersModel(watchregistry=False) self.selectlayerfilter = LayerTypeFilter() self.selectlayerfilter.setSourceModel(self.selectlayermodel) self.selectlayermodel.dataChanged.connect(self.selectlayerschanged) self.layerCombo.setModel(self.formlayers) self.widgetCombo.setModel(self.possiblewidgetsmodel) self.selectLayers.setModel(self.selectlayerfilter) self.selectLayers_2.setModel(self.selectlayerfilter) self.fieldList.setModel(self.fieldsmodel) self.widgetlist.setModel(self.widgetmodel) self.widgetlist.selectionModel().currentChanged.connect(self.updatecurrentwidget) self.widgetmodel.rowsRemoved.connect(self.setwidgetconfigvisiable) self.widgetmodel.rowsInserted.connect(self.setwidgetconfigvisiable) self.widgetmodel.modelReset.connect(self.setwidgetconfigvisiable) self.titleText.textChanged.connect(self.updatetitle) QgsProject.instance().readProject.connect(self._readproject) self.loadwidgettypes() self.addWidgetButton.pressed.connect(self.newwidget) self.removeWidgetButton.pressed.connect(self.removewidget) self.roamVersionLabel.setText("You are running IntraMaps Roam version {}".format(roam.__version__)) self.openProjectFolderButton.pressed.connect(self.openprojectfolder) self.openinQGISButton.pressed.connect(self.openinqgis) self.filewatcher = QFileSystemWatcher() self.filewatcher.fileChanged.connect(self.qgisprojectupdated) self.formfolderLabel.linkActivated.connect(self.openformfolder) self.projectupdatedlabel.linkActivated.connect(self.reloadproject) self.projectupdatedlabel.hide() self.formtab.currentChanged.connect(self.formtabchanged) self.expressionButton.clicked.connect(self.opendefaultexpression) self.fieldList.currentIndexChanged.connect(self.updatewidgetname) self.fieldwarninglabel.hide() for item, data in readonlyvalues: self.readonlyCombo.addItem(item, data) self.setpage(4) self.form = None self.projectlocations.currentIndexChanged[str].connect(self.projectlocationchanged.emit) def setaboutinfo(self): self.versionLabel.setText(roam.__version__) self.qgisapiLabel.setText(str(QGis.QGIS_VERSION)) def checkcapturelayers(self): haslayers = self.project.hascapturelayers() self.formslayerlabel.setVisible(not haslayers) return haslayers def opendefaultexpression(self): layer = self.currentform.QGISLayer dlg = QgsExpressionBuilderDialog(layer, "Create default value expression", self) text = self.defaultvalueText.text().strip('[%').strip('%]').strip() dlg.setExpressionText(text) if dlg.exec_(): self.defaultvalueText.setText('[% {} %]'.format(dlg.expressionText())) def openformfolder(self, url): openfolder(url) def selectlayerschanged(self, *args): self.formlayers.setSelectLayers(self.project.selectlayers) self.checkcapturelayers() self.selectlayersupdated.emit(self.project.selectlayers) def formtabchanged(self, index): # preview if index == 1: self.form.settings['widgets'] = list(self.widgetmodel.widgets()) self.setformpreview(self.form) def setprojectfolders(self, folders): for folder in folders: self.projectlocations.addItem(folder) def setpage(self, page): self.stackedWidget.setCurrentIndex(page) def reloadproject(self, *args): self.setproject(self.project) def qgisprojectupdated(self, path): self.projectupdatedlabel.show() self.projectupdatedlabel.setText("The QGIS project has been updated. <a href='reload'> " "Click to reload</a>. <b style=\"color:red\">Unsaved data will be lost</b>") def openinqgis(self): projectfile = self.project.projectfile qgislocation = r'C:\OSGeo4W\bin\qgis.bat' qgislocation = roam.config.settings.setdefault('configmanager', {}) \ .setdefault('qgislocation', qgislocation) try: openqgis(projectfile, qgislocation) except WindowsError: self.bar.pushMessage("Looks like I couldn't find QGIS", "Check qgislocation in settings.config", QgsMessageBar.WARNING) def openprojectfolder(self): folder = self.project.folder openfolder(folder) def setwidgetconfigvisiable(self, *args): haswidgets = self.widgetmodel.rowCount() > 0 self.widgetframe.setEnabled(haswidgets) def removewidget(self): """ Remove the selected widget from the widgets list """ widget, index = self.currentuserwidget if index.isValid(): self.widgetmodel.removeRow(index.row(), index.parent()) def newwidget(self): """ Create a new widget. The default is a list. """ widget = {} widget['widget'] = 'List' # Grab the first field. widget['field'] = self.fieldsmodel.index(0, 0).data(QgsFieldModel.FieldNameRole) currentindex = self.widgetlist.currentIndex() currentitem = self.widgetmodel.itemFromIndex(currentindex) if currentitem and currentitem.iscontainor(): parent = currentindex else: parent = currentindex.parent() index = self.widgetmodel.addwidget(widget, parent) self.widgetlist.setCurrentIndex(index) def loadwidgettypes(self): self.widgetCombo.blockSignals(True) for widgettype in roam.editorwidgets.core.supportedwidgets(): try: configclass = configmanager.editorwidgets.widgetconfigs[widgettype] except KeyError: continue configwidget = configclass() item = QStandardItem(widgettype) item.setData(configwidget, Qt.UserRole) item.setData(widgettype, Qt.UserRole + 1) item.setIcon(QIcon(widgeticon(widgettype))) self.widgetCombo.model().appendRow(item) self.widgetstack.addWidget(configwidget) self.widgetCombo.blockSignals(False) def usedfields(self): """ Return the list of fields that have been used by the the current form's widgets """ for widget in self.currentform.widgets: yield widget['field'] @property def currentform(self): """ Return the current selected form. """ return self.form @property def currentuserwidget(self): """ Return the selected user widget. """ index = self.widgetlist.currentIndex() return index.data(Qt.UserRole), index @property def currentwidgetconfig(self): """ Return the selected widget in the widget combo. """ index = self.widgetCombo.currentIndex() index = self.possiblewidgetsmodel.index(index, 0) return index.data(Qt.UserRole), index, index.data(Qt.UserRole + 1) def updatewidgetname(self, index): # Only change the edit text on name field if it's not already set to something other then the # field name. field = self.fieldsmodel.index(index, 0).data(QgsFieldModel.FieldNameRole) currenttext = self.nameText.text() foundfield = self.fieldsmodel.findfield(currenttext) if foundfield: self.nameText.setText(field) def _save_widgetfield(self, index): """ Save the selected field for the current widget. Shows a error if the field is already used but will allow the user to still set it in the case of extra logic for that field in the forms Python logic. """ widget, index = self.currentuserwidget row = self.fieldList.currentIndex() field = self.fieldsmodel.index(row, 0).data(QgsFieldModel.FieldNameRole) showwarning = field in self.usedfields() self.fieldwarninglabel.setVisible(showwarning) widget['field'] = field self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_selectedwidget(self, index): configwidget, index, widgettype = self.currentwidgetconfig widget, index = self.currentuserwidget if not widget: return widget['widget'] = widgettype widget['required'] = self.requiredCheck.isChecked() widget['config'] = configwidget.getconfig() widget['name'] = self.nameText.text() widget['read-only-rules'] = [self.readonlyCombo.itemData(self.readonlyCombo.currentIndex())] widget['hidden'] = self.hiddenCheck.isChecked() self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_default(self): widget, index = self.currentuserwidget default = self.defaultvalueText.text() widget['default'] = default self.widgetmodel.setData(index, widget, Qt.UserRole) def _save_selectionlayers(self, index, layer, value): config = self.project.settings self.selectlayermodel.dataChanged.emit(index, index) def _save_formtype(self, index): formtype = self.formtypeCombo.currentText() form = self.currentform form.settings['type'] = formtype def _save_formname(self, text): """ Save the form label to the settings file. """ try: form = self.currentform if form is None: return form.settings['label'] = text self.projectupdated.emit() except IndexError: return def _save_layer(self, index): """ Save the selected layer to the settings file. """ index = self.formlayers.index(index, 0) layer = index.data(Qt.UserRole) if not layer: return form = self.currentform if form is None: return form.settings['layer'] = layer.name() self.updatefields(layer) def setsplash(self, splash): pixmap = QPixmap(splash) w = self.splashlabel.width() h = self.splashlabel.height() self.splashlabel.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) def setproject(self, project, loadqgis=True): """ Set the widgets active project. """ self.disconnectsignals() self.mapisloaded = False self.filewatcher.removePaths(self.filewatcher.files()) self.projectupdatedlabel.hide() self._closeqgisproject() if project.valid: self.startsettings = copy.deepcopy(project.settings) self.project = project self.projectlabel.setText(project.name) self.versionText.setText(project.version) self.selectlayermodel.config = project.settings self.formlayers.setSelectLayers(self.project.selectlayers) self.setsplash(project.splash) self.loadqgisproject(project, self.project.projectfile) self.filewatcher.addPath(self.project.projectfile) self.projectloaded.emit(self.project) def loadqgisproject(self, project, projectfile): QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def _closeqgisproject(self): if self.canvas.isDrawing(): return self.canvas.freeze(True) self.formlayersmodel.removeall() self.selectlayermodel.removeall() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.freeze(False) def loadmap(self): if self.mapisloaded: return # This is a dirty hack to work around the timer that is in QgsMapCanvas in 2.2. # Refresh will stop the canvas timer # Repaint will redraw the widget. # loadmap is only called once per project load so it's safe to do this here. self.canvas.refresh() self.canvas.repaint() parser = roam.projectparser.ProjectParser.fromFile(self.project.projectfile) canvasnode = parser.canvasnode self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) self.canvas.updateScale() self.canvas.refresh() self.mapisloaded = True def _readproject(self, doc): self.formlayersmodel.refresh() self.selectlayermodel.refresh() self._updateforproject(self.project) def _updateforproject(self, project): self.titleText.setText(project.name) self.descriptionText.setPlainText(project.description) def swapwidgetconfig(self, index): widgetconfig, _, _ = self.currentwidgetconfig defaultvalue = widgetconfig.defaultvalue self.defaultvalueText.setText(defaultvalue) self.updatewidgetconfig({}) def updatetitle(self, text): self.project.settings['title'] = text self.projectlabel.setText(text) self.projectupdated.emit() def updatewidgetconfig(self, config): widgetconfig, index, widgettype = self.currentwidgetconfig self.setconfigwidget(widgetconfig, config) def setformpreview(self, form): def removewidget(): item = self.frame_2.layout().itemAt(0) if item and item.widget(): item.widget().setParent(None) removewidget() featureform = FeatureForm.from_form(form, form.settings, None, {}) self.frame_2.layout().addWidget(featureform) def connectsignals(self): self.formLabelText.textChanged.connect(self._save_formname) self.layerCombo.currentIndexChanged.connect(self._save_layer) self.formtypeCombo.currentIndexChanged.connect(self._save_formtype) #widget settings self.fieldList.currentIndexChanged.connect(self._save_widgetfield) self.requiredCheck.toggled.connect(self._save_selectedwidget) self.defaultvalueText.textChanged.connect(self._save_default) self.widgetCombo.currentIndexChanged.connect(self._save_selectedwidget) self.widgetCombo.currentIndexChanged.connect(self.swapwidgetconfig) self.nameText.textChanged.connect(self._save_selectedwidget) self.readonlyCombo.currentIndexChanged.connect(self._save_selectedwidget) self.hiddenCheck.toggled.connect(self._save_selectedwidget) def disconnectsignals(self): try: self.formLabelText.textChanged.disconnect(self._save_formname) self.layerCombo.currentIndexChanged.disconnect(self._save_layer) self.formtypeCombo.currentIndexChanged.disconnect(self._save_formtype) #widget settings self.fieldList.currentIndexChanged.disconnect(self._save_widgetfield) self.requiredCheck.toggled.disconnect(self._save_selectedwidget) self.defaultvalueText.textChanged.disconnect(self._save_default) self.widgetCombo.currentIndexChanged.disconnect(self._save_selectedwidget) self.widgetCombo.currentIndexChanged.disconnect(self.swapwidgetconfig) self.nameText.textChanged.disconnect(self._save_selectedwidget) self.readonlyCombo.currentIndexChanged.disconnect(self._save_selectedwidget) self.hiddenCheck.toggled.disconnect(self._save_selectedwidget) except TypeError: pass def setform(self, form): """ Update the UI with the currently selected form. """ def getfirstlayer(): index = self.formlayers.index(0,0) layer = index.data(Qt.UserRole) layer = layer.name() return layer def loadwidgets(widget): """ Load the widgets into widgets model """ self.widgetmodel.clear() self.widgetmodel.loadwidgets(form.widgets) def findlayer(layername): index = self.formlayersmodel.findlayer(layername) index = self.formlayers.mapFromSource(index) layer = index.data(Qt.UserRole) return index, layer self.disconnectsignals() self.form = form settings = form.settings label = form.label layername = settings.setdefault('layer', getfirstlayer()) layerindex, layer = findlayer(layername) if not layer or not layerindex.isValid(): return formtype = settings.setdefault('type', 'auto') widgets = settings.setdefault('widgets', []) self.formLabelText.setText(label) folderurl = "<a href='{path}'>{name}</a>".format(path=form.folder, name=os.path.basename(form.folder)) self.formfolderLabel.setText(folderurl) self.layerCombo.setCurrentIndex(layerindex.row()) self.updatefields(layer) index = self.formtypeCombo.findText(formtype) if index == -1: self.formtypeCombo.insertItem(0, formtype) self.formtypeCombo.setCurrentIndex(0) else: self.formtypeCombo.setCurrentIndex(index) loadwidgets(widgets) # Set the first widget index = self.widgetmodel.index(0, 0) if index.isValid(): self.widgetlist.setCurrentIndex(index) self.updatecurrentwidget(index, None) self.connectsignals() def updatefields(self, layer): """ Update the UI with the fields for the selected layer. """ self.fieldsmodel.setLayer(layer) def setconfigwidget(self, configwidget, config): """ Set the active config widget. """ try: configwidget.widgetdirty.disconnect(self._save_selectedwidget) except TypeError: pass #self.descriptionLabel.setText(configwidget.description) self.widgetstack.setCurrentWidget(configwidget) configwidget.setconfig(config) configwidget.widgetdirty.connect(self._save_selectedwidget) def updatecurrentwidget(self, index, _): """ Update the UI with the config for the current selected widget. """ if not index.isValid(): return widget = index.data(Qt.UserRole) widgettype = widget['widget'] field = widget['field'] required = widget.setdefault('required', False) name = widget.setdefault('name', field) default = widget.setdefault('default', '') readonly = widget.setdefault('read-only-rules', []) hidden = widget.setdefault('hidden', False) try: data = readonly[0] except: data = 'never' self.readonlyCombo.blockSignals(True) index = self.readonlyCombo.findData(data) self.readonlyCombo.setCurrentIndex(index) self.readonlyCombo.blockSignals(False) self.defaultvalueText.blockSignals(True) if not isinstance(default, dict): self.defaultvalueText.setText(default) else: # TODO Handle the more advanced default values. pass self.defaultvalueText.blockSignals(False) self.nameText.blockSignals(True) self.nameText.setText(name) self.nameText.blockSignals(False) self.requiredCheck.blockSignals(True) self.requiredCheck.setChecked(required) self.requiredCheck.blockSignals(False) self.hiddenCheck.blockSignals(True) self.hiddenCheck.setChecked(hidden) self.hiddenCheck.blockSignals(False) if not field is None: self.fieldList.blockSignals(True) index = self.fieldList.findData(field.lower(), QgsFieldModel.FieldNameRole) if index > -1: self.fieldList.setCurrentIndex(index) else: self.fieldList.setEditText(field) self.fieldList.blockSignals(False) index = self.widgetCombo.findText(widgettype) self.widgetCombo.blockSignals(True) if index > -1: self.widgetCombo.setCurrentIndex(index) self.widgetCombo.blockSignals(False) self.updatewidgetconfig(config=widget.setdefault('config', {})) def _saveproject(self): """ Save the project config to disk. """ title = self.titleText.text() description = self.descriptionText.toPlainText() version = str(self.versionText.text()) settings = self.project.settings settings['title'] = title settings['description'] = description settings['version'] = version form = self.currentform if form: form.settings['widgets'] = list(self.widgetmodel.widgets()) logger.debug(form.settings) self.project.save() self.projectsaved.emit()
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 Dialog_report(QDialog, Ui_Dialog_report): """ Class documentation goes here. """ def __init__(self, parent = None): """ Constructor """ QDialog.__init__(self, parent) self.setupUi(self) #construct Customer list class self.clist = Customer_list() #construct accounting class self.caccount = Dfile() #construct customer price class self.cprice = Customer_price() #construct standard table self.tablemodel = QStandardItemModel(31, len(PRODUCT_NAME) ) self.setTableheader() #save customer list int self.list_customer = self.clist.readCompany() self.setCombo( 1, self.list_customer ) def setMode(self, str_mode): if str_mode == 'init': self.clearAllshow() def setCombo(self, comboselect, m_str): """ set combo box """ if comboselect == 1: for i in m_str: self.comboBox_name.addItem(i) elif comboselect == 2: self.comboBox_date.clear() for i in m_str: self.comboBox_date.addItem(i) def clearAllshow(self): #clear all spin box self.setAllspin(0) #clear table self.clearTableview() def setAllspin(self, int_value): self.spinBox_1.setValue(int_value) self.spinBox_2.setValue(int_value) self.spinBox_3.setValue(int_value) self.spinBox_4.setValue(int_value) self.spinBox_5.setValue(int_value) self.spinBox_6.setValue(int_value) self.spinBox_7.setValue(int_value) self.spinBox_8.setValue(int_value) self.spinBox_9.setValue(int_value) self.spinBox_10.setValue(int_value) self.spinBox_11.setValue(int_value) self.spinBox_12.setValue(int_value) self.spinBox_13.setValue(int_value) self.spinBox_14.setValue(int_value) self.spinBox_15.setValue(int_value) self.spinBox_16.setValue(int_value) self.spinBox_17.setValue(int_value) self.spinBox_18.setValue(int_value) self.spinBox_19.setValue(int_value) self.spinBox_19.setValue(0) def setTableheader(self): #set header data self.tablemodel.setHeaderData(0, Qt.Horizontal, PRODUCT_NAME[0] ) self.tablemodel.setHeaderData(1, Qt.Horizontal, PRODUCT_NAME[1] ) self.tablemodel.setHeaderData(2, Qt.Horizontal, PRODUCT_NAME[2] ) self.tablemodel.setHeaderData(3, Qt.Horizontal, PRODUCT_NAME[3] ) self.tablemodel.setHeaderData(4, Qt.Horizontal, PRODUCT_NAME[4] ) self.tablemodel.setHeaderData(5, Qt.Horizontal, PRODUCT_NAME[5] ) def setTableview(self, dlist_data ): """ set data into tableview model """ #show data row = 0 for i in dlist_data: self.tablemodel.setData(self.tablemodel.index(row, 0), QVariant(i[0])) self.tablemodel.setData(self.tablemodel.index(row, 1), QVariant(i[1])) self.tablemodel.setData(self.tablemodel.index(row, 2), QVariant(i[2])) self.tablemodel.setData(self.tablemodel.index(row, 3), QVariant(i[3])) self.tablemodel.setData(self.tablemodel.index(row, 4), QVariant(i[4])) self.tablemodel.setData(self.tablemodel.index(row, 5), QVariant(i[5])) row += 1 #set table into tableview self.tableView.setModel(self.tablemodel) def clearTableview(self): """ clear table """ #show data row = 0 i = [0, 0, 0, 0, 0, 0] for row in range(31): self.tablemodel.setData(self.tablemodel.index(row, 0), QVariant(i[0])) self.tablemodel.setData(self.tablemodel.index(row, 1), QVariant(i[1])) self.tablemodel.setData(self.tablemodel.index(row, 2), QVariant(i[2])) self.tablemodel.setData(self.tablemodel.index(row, 3), QVariant(i[3])) self.tablemodel.setData(self.tablemodel.index(row, 4), QVariant(i[4])) self.tablemodel.setData(self.tablemodel.index(row, 5), QVariant(i[5])) #set table into tableview self.tableView.setModel(self.tablemodel) @pyqtSignature("QString") def on_comboBox_name_currentIndexChanged(self, p0): """ when name index change, set combo date """ #set to initial status self.setMode('init') #read combo text and dict value self.str_customercombo = str( self.comboBox_name.currentText().toUtf8() ) self.i_customercombo = self.clist.readCvalue( self.str_customercombo ) #read all guest accounting data self.list_date = self.caccount.listDatafile( self.i_customercombo ) self.setCombo(2, self.list_date) @pyqtSignature("QString") def on_comboBox_date_currentIndexChanged(self, p0): """ search price data and load accounting into table """ self.str_filename = str( self.comboBox_date.currentText() ) if self.str_filename != '': self.str_datecombo = self.str_filename[3:9] #get price version self.i_priceversion = self.cprice.selectPrice( self.i_customercombo, self.str_datecombo ) #get price dict dict_price = self.cprice.readPrice( self.i_customercombo, self.i_priceversion ) self.list_price = self.cprice.getClist( dict_price ) #show price self.setPricespin( self.list_price ) #show table self.caccount.open_dfile( self.str_filename ) self.table_data = self.caccount.read_alldfile() self.setTableview( self.table_data ) #calculate and show single amount self.eachamount = self.sumEachamount( self.table_data ) self.setEachamount( self.eachamount ) #calculate single price amount self.eachpriceamount = [ self.eachamount[i]*self.list_price[i] for i in range(len(PRODUCT_NAME))] self.setEachpriceamount( self.eachpriceamount ) #show in total income self.spinBox_19.setValue( sum(self.eachpriceamount ) ) def setPricespin( self, list ): self.spinBox_1.setValue( list[0] ) self.spinBox_2.setValue( list[1] ) self.spinBox_3.setValue( list[2] ) self.spinBox_4.setValue( list[3] ) self.spinBox_5.setValue( list[4] ) self.spinBox_6.setValue( list[5] ) def setEachamount( self, list ): self.spinBox_7.setValue( list[0] ) self.spinBox_8.setValue( list[1] ) self.spinBox_9.setValue( list[2] ) self.spinBox_10.setValue( list[3] ) self.spinBox_11.setValue( list[4] ) self.spinBox_12.setValue( list[5] ) def setEachpriceamount(self, list ): self.spinBox_13.setValue( list[0] ) self.spinBox_14.setValue( list[1] ) self.spinBox_15.setValue( list[2] ) self.spinBox_16.setValue( list[3] ) self.spinBox_17.setValue( list[4] ) self.spinBox_18.setValue( list[5] ) #sum each item total amount def sumEachamount(self, duallist ): eachamount = [0, 0, 0, 0, 0, 0] count = 0 for i in duallist: for j in i: eachamount[count] += j count += 1 count = 0 return eachamount
class OWConfusionMatrix(widget.OWWidget): name = "Confusion Matrix" description = "Shows a confusion matrix." icon = "icons/ConfusionMatrix.svg" priority = 1001 inputs = [{"name": "Evaluation Results", "type": Orange.evaluation.testing.Results, "handler": "set_results"}] outputs = [{"name": "Selected Data", "type": Orange.data.Table}] quantities = ["Number of instances", "Observed and expected instances", "Proportion of predicted", "Proportion of true"] selected_learner = settings.Setting([]) selected_quantity = settings.Setting(0) append_predictions = settings.Setting(True) append_probabilities = settings.Setting(False) autocommit = settings.Setting(True) def __init__(self, parent=None): super().__init__(parent) self.results = None self.learners = [] self._invalidated = False box = gui.widgetBox(self.controlArea, "Learners") self.learners_box = gui.listBox( box, self, "selected_learner", "learners", callback=self._learner_changed ) box = gui.widgetBox(self.controlArea, "Show") combo = gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.widgetBox(self.controlArea, "Selection") gui.button(box, self, "Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "None", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.widgetBox(self.controlArea, "Output") gui.checkBox(box, self, "append_predictions", "Append class predictions", callback=self._invalidate) gui.checkBox(box, self, "append_probabilities", "Append predicted class probabilities", callback=self._invalidate) b = gui.button(box, self, "Commit", callback=self.commit, default=True) cb = gui.checkBox(box, self, "autocommit", "Commit automatically") gui.setStopper(self, b, cb, "_invalidated", callback=self.commit) grid = QGridLayout() grid.setContentsMargins(0, 0, 0, 0) grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter) grid.addWidget(VerticalLabel("Correct Class"), 1, 0, Qt.AlignCenter) self.tablemodel = QStandardItemModel() self.tableview = QTableView( editTriggers=QTableView.NoEditTriggers, ) self.tableview.setModel(self.tablemodel) self.tableview.selectionModel().selectionChanged.connect( self._invalidate ) grid.addWidget(self.tableview, 1, 1) self.mainArea.layout().addLayout(grid) def set_results(self, results): """Set the input results.""" self.clear() self.warning([0, 1]) data = None if results is not None: if results.data is not None: data = results.data if data is not None and \ not isinstance(data.domain.class_var, Orange.data.DiscreteVariable): data = None results = None self.warning( 0, "Confusion Matrix cannot be used for 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 not None: nmodels, ntests = results.predicted.shape headers = class_values + [unicodedata.lookup("N-ARY SUMMATION")] # NOTE: The 'fitter_names' is set in 'Test Learners' widget. if hasattr(results, "fitter_names"): self.learners = results.fitter_names else: self.learners = ["L %i" % (i + 1) for i in range(nmodels)] self.tablemodel.setVerticalHeaderLabels(headers) self.tablemodel.setHorizontalHeaderLabels(headers) self.tablemodel.setRowCount(len(class_values) + 1) self.tablemodel.setColumnCount(len(class_values) + 1) self.selected_learner = [0] self._update() def clear(self): self.learners = [] self.results = None self.data = None self.tablemodel.clear() def select_correct(self): selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(n): index = self.tablemodel.index(i, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect ) def select_wrong(self): selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(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): self.tableview.selectionModel().clear() def commit(self): if self.results and self.data: indices = self.tableview.selectedIndexes() indices = {(ind.row(), ind.column()) for ind in indices} actual = self.results.actual selected_learner = self.selected_learner[0] learner_name = self.learners[selected_learner] predicted = self.results.predicted[selected_learner] 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[selected_learner, 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] 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) else: data = None self.send("Selected Data", data) self._invalidated = False def _invalidate(self): if self.autocommit: self.commit() else: self._invalidated = True def _learner_changed(self): # The selected learner has changed self._update() def _update(self): # Update the displayed confusion matrix if self.results is not None and self.selected_learner: index = self.selected_learner[0] cmatrix = confusion_matrix(self.results, index) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) total = rowsum.sum() if self.selected_quantity == 0: value = lambda i, j: int(cmatrix[i, j]) elif self.selected_quantity == 1: priors = numpy.outer(rowsum, colsum) / total value = lambda i, j: \ "{} / {:5.3f}".format(cmatrix[i, j], priors[i, j]) elif self.selected_quantity == 2: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i]) if colsum[i] else "N/A") elif self.selected_quantity == 3: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i]) if colsum[i] else "N/A") else: assert False model = self.tablemodel for i, row in enumerate(cmatrix): for j, _ in enumerate(row): item = model.item(i, j) if item is None: item = QStandardItem() item.setData(value(i, j), Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) model.setItem(i, j, item) font = model.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) def sum_item(value): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) return item N = len(colsum) for i in range(N): model.setItem(N, i, sum_item(int(colsum[i]))) model.setItem(i, N, sum_item(int(rowsum[i]))) model.setItem(N, N, sum_item(int(total)))
class Emotion(QtGui.QWidget): EMOTION_DIR = "./resource/expression" WIDTH = 460 HEIGHT = 300 selectChanged = pyqtSignal(str) def __init__(self,parent=None):# super(Emotion,self).__init__(parent) super(Emotion,self).setWindowFlags(QtCore.Qt.Popup) self.resize(QSize(Emotion.WIDTH,Emotion.HEIGHT)) self.setWindowTitle("表情選擇") #self.setModal(True) #self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.emotion_initial() def emotion_initial(self): self.emotion_table = QTableView() self.emotion_table.horizontalHeader().setVisible(False) self.emotion_table.verticalHeader().setVisible(False) self.emotion_table.setMouseTracking(True) self.emotion_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.emotion_table.verticalHeader().setDefaultSectionSize(30) self.emotion_table.horizontalHeader().setDefaultSectionSize(30) self.emotion_table.setIconSize(QSize(30,30)) self.emotion_table.entered.connect(self.showEmotionTips) self.emotion_model = QStandardItemModel() emotions = os.listdir(Emotion.EMOTION_DIR) i = 0 emotions_size = len(emotions) emotions = sorted(emotions,cmp=emotioncmp) while i < emotions_size: self.add_emotion(emotions[i:i+14]) i = i + 14 self.emotion_table.setModel(self.emotion_model) self.emotion_table.clicked.connect(self.emotion_click) # mainLayout=QVBoxLayout() mainLayout.addWidget(self.emotion_table) self.setLayout(mainLayout) #self. def showEmotionTips(self,index): if index.isValid(): QToolTip.showText(QCursor.pos(), "Hello", None) def add_emotion(self,emotions): ''' :param emotions a list of emotion will be adding to emotion table ''' cells = [] for emotion in emotions: item = QtGui.QStandardItem(QIcon(os.path.join(Emotion.EMOTION_DIR,emotion)),emotion) cells.append(item) self.emotion_model.appendRow(cells) #def eventFilter(self, event): #p = QCursor.pos() - self.pos() #item = self.emotion_table def emotion_click(self): row = self.emotion_table.currentIndex().row() column = self.emotion_table.currentIndex().column() #self.accept() self.close() self.selectChanged.emit(self.get_selected_emotion(row,column)) def get_selected_emotion(self,row,column): emotion = self.emotion_model.data(self.emotion_model.index(row, column)) if emotion: return str(emotion.toString()) else: return "N/A"
class OWConfusionMatrix(widget.OWWidget): name = "Confusion Matrix" description = "Display confusion matrix constructed from results " \ "of evaluation of classifiers." 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" ] selected_learner = settings.Setting([]) selected_quantity = settings.Setting(0) append_predictions = settings.Setting(True) append_probabilities = settings.Setting(False) autocommit = settings.Setting(True) def __init__(self): super().__init__() self.data = None self.results = None self.learners = [] self.headers = [] box = gui.widgetBox(self.controlArea, "Learners") self.learners_box = gui.listBox(box, self, "selected_learner", "learners", callback=self._learner_changed) box = gui.widgetBox(self.controlArea, "Show") gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.widgetBox(self.controlArea, "Select") gui.button(box, self, "Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "None", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.widgetBox(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 Data", "Auto send is on") 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.clicked.connect(self.cell_clicked) grid.addWidget(view, 0, 0) self.mainArea.layout().addLayout(grid) def sizeHint(self): 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 set_results(self, results): """Set the input results.""" self.clear() self.warning([0, 1]) data = None if results is not None: if results.data is not None: data = results.data if data is not None and not data.domain.has_discrete_class: data = None results = None self.warning( 0, "Confusion Matrix cannot be used for 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 not None: nmodels, ntests = results.predicted.shape 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 #%i" % (i + 1) for i in range(nmodels) ] 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, len(class_values)) self.tableview.setSpan(2, 0, len(class_values), 1) 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.setData(QBrush(QColor(208, 208, 208)), Qt.BackgroundColorRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) 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(len(class_values) + 3) self.tablemodel.setColumnCount(len(class_values) + 3) self.selected_learner = [0] self._update() def clear(self): self.results = None self.data = None self.tablemodel.clear() self.headers = [] # Clear learners last. This action will invoke `_learner_changed` # method self.learners = [] def select_correct(self): 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): 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): self.tableview.selectionModel().clear() def cell_clicked(self, model_index): 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): 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 selected_learner = self.selected_learner[0] learner_name = self.learners[selected_learner] predicted = self.results.predicted[selected_learner] 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[selected_learner, 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): self.commit() def _learner_changed(self): # The selected learner has changed indices = self.tableview.selectedIndexes() self._update() selection = QItemSelection() for sel in indices: selection.select(sel, sel) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) self.commit() def _update(self): # Update the displayed confusion matrix if self.results is not None and self.selected_learner: index = self.selected_learner[0] cmatrix = confusion_matrix(self.results, index) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) total = rowsum.sum() if self.selected_quantity == 0: value = lambda i, j: int(cmatrix[i, j]) elif self.selected_quantity == 1: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i]) if colsum[i] else "N/A") elif self.selected_quantity == 2: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i]) if colsum[i] else "N/A") else: assert False for i, row in enumerate(cmatrix): for j, _ in enumerate(row): item = self._item(i + 2, j + 2) item.setData(value(i, j), Qt.DisplayRole) 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) model = self.tablemodel font = model.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) def sum_item(value): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) return item N = len(colsum) for i in range(N): model.setItem(N + 2, i + 2, sum_item(int(colsum[i]))) model.setItem(i + 2, N + 2, sum_item(int(rowsum[i]))) model.setItem(N + 2, N + 2, sum_item(int(total)))
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 Mineral_Params(QDialog, QTableView): def __init__(self, Pressure=1e5, Temperature=300, Volume=None, VolumeOff=True): super(Mineral_Params, self).__init__() self.Solidsolution = [an,ab,sp,hc,en,fs,mgts,odi,hpcen,hpcfs,di,he,cen,cats,jd,py,al,gr,mgmj,jdmj, \ capv,fo,fa,mgwa,fewa,mgri,feri,mgil,feil,co,mgpv,fepv,alpv,mppv,fppv,appv,mgcf,fecf, \ nacf,pe,wu,qtz,coes,st,an,ky,neph] self.row = len(self.Solidsolution) self.layout = QGridLayout(self) self.Pressure = Pressure self.Temperature = Temperature self.table = QTableView() self.model = QStandardItemModel(10, 10, self) if Volume is None: self.Volume = Volume self.model.setHorizontalHeaderLabels([ 'Name', 'formuala', 'Vp (km/s)', 'Vs (km/s)', 'Rho (kg/m³)', 'F (KJ/mol)', 'V (cm³/mol)', 'K (GPa)', "k'", 'θ' + '(K)', 'γ', 'q', 'G (GPa)', "G'", 'η' ]) else: self.Volume = Volume[:-3] self.model.setHorizontalHeaderLabels([ 'Name', 'formuala', 'Vp (km/s)', 'Vs (km/s)', 'Rho (kg/m³)', 'F (KJ/mol)', 'V (cm³/mol)', 'K (GPa)', "k'", 'θ' + '(K)', 'γ', 'q', 'G (GPa)', "G'", 'η', 'Volume fraction' ]) #self.model.setHorizontalHeaderLabels(['Name','formuala','Vp (km/s)','Vs (km/s)','Rho (kg/m³)','F (KJ/mol)','V (cm³/mol)','K (GPa)',"k'",'θ'+'(K)','γ','q','G (GPa)',"G'",'η','Volume fraction']) self.table.setModel(self.model) self.layout.addWidget(self.table, 0, 0, 1, 5) self.BTN() self.table_view() self.resize(1800, 800) #self.restore() def BTN(self): return 0 self.Update = QPushButton(self) self.Update.setText("Update") self.Update.clicked.connect(self.update_data) self.Update.setAutoDefault(False) self.Restore = QPushButton(self) self.Restore.setText("Restore") self.Restore.clicked.connect(self.restore) self.Restore.setAutoDefault(False) self.Random = QPushButton(self) self.Random.setText("Random within error") self.Random.clicked.connect(self.random) self.Random.setAutoDefault(False) self.Save = QPushButton(self) self.Save.setText("Save") self.Save.clicked.connect(self.save) self.Save.setAutoDefault(False) self.Iutput = QPushButton(self) self.Iutput.setText("Load") self.Iutput.clicked.connect(self.iutput) self.Iutput.setAutoDefault(False) self.layout.addWidget(self.Update, 1, 0, 1, 1) self.layout.addWidget(self.Restore, 1, 1, 1, 1) self.layout.addWidget(self.Random, 1, 2, 1, 1) self.layout.addWidget(self.Save, 1, 3, 1, 1) self.layout.addWidget(self.Iutput, 1, 4, 1, 1) def save(self): options = QFileDialog.Options() fileName = QFileDialog.getSaveFileName( self, "QFileDialog.getSaveFileName()", "", "All Files (*);;Text Files (*.txt)", options=options) #except: # fileName, _= QFileDialog.getSaveFileName(self,"QFileDialog.getSaveFileName()","","All Files (*);;Text Files (*.txt)", options=options) if PYQT == 5: fileName = fileName[0] else: pass if fileName: file1 = open(fileName, 'w') #print ('open',fileName) file1.write( 'name, F_0,V_0,K_0,Kprime_0 Debye_0,grueneisen-0,q_0,G_0,Gprime_0, eta_s0 ' ) file1.write('\n') for i in self.Solidsolution: for j in i.parameters(self.Pressure, self.Temperature): file1.write('{:8.8}'.format(j)) file1.write(' ') file1.write('\n') file1.close() #print ('save') def iutput(self): fileName = QFileDialog.getOpenFileName(self, 'Open file', '/home') if PYQT == 5: fileName = fileName[0] else: pass if fileName: file1 = open(fileName, 'r') next(file1) for i, line in enumerate(file1): line = line.split() newItem = QStandardItem(self.Solidsolution[i].name) self.model.setItem(i, 0, newItem) for col in range(len(line)): try: string = "{:5.2f}".format(line[col]) except: string = line[col] item = QStandardItem(string) self.model.setItem(i, col, item) file1.close() #print (string) #print ('input') #self.table_view() def table_view(self): #self.row_list=[] for i in range(self.row): newItem = QStandardItem(self.Solidsolution[i].name) self.model.setItem(i, 0, newItem) params = self.Solidsolution[i].parameters(1e5, 300) for col in range(len(params)): try: string = "{:5.2f}".format(params[col]) except: string = params[col] item = QStandardItem(string) self.model.setItem(i, col, item) if self.Volume is not None: for num, i in enumerate(self.Volume): newItem = QStandardItem(str(self.Volume[num])) self.model.setItem(num, 15, newItem) def random(self): for i in range(self.row): newItem = QStandardItem(self.Solidsolution[i].name) self.model.setItem(i, 0, newItem) params = self.Solidsolution[i].parameters_random( self.Pressure, self.Temperature) #print ('random') for col in range(len(params)): try: string = "{:5.2f}".format(params[col]) except: string = params[col] item = QStandardItem(string) self.model.setItem(i, col, item) #self.table_view() #print ('random') def update_data(self): for i in range(len(self.Solidsolution)): params = [] for j in range(15): index = self.model.index(i, j) params.append(self.model.itemData(index)[0]) self.Solidsolution[i].change_parameters(params) a, b, c = self.Solidsolution[i].Vp_Vs(self.Pressure * 1e4, self.Temperature) c *= 1000 item = QStandardItem("{:5.2f}".format(a)) self.model.setItem(i, 2, item) item = QStandardItem("{:5.2f}".format(b)) self.model.setItem(i, 3, item) item = QStandardItem("{:5.2f}".format(c)) self.model.setItem(i, 4, item) #print ('wf') def restore(self): try: address = os.path.join(os.path.dirname(__file__), 'EXPDATA', 'All.txt') self.address = address file1 = open(address, 'r+') except: address = os.path.join(os.path.dirname(__file__), 'Mineral_Physics', 'EXPDATA', 'All.txt') self.address = address file1 = open(address, 'r') next(file1) for i, line in enumerate(file1): line = line.split() newItem = QStandardItem(self.Solidsolution[i].name) self.model.setItem(i, 0, newItem) for col in range(len(line)): try: string = "{:5.2f}".format(line[col]) except: string = line[col] item = QStandardItem(string) self.model.setItem(i, col, item) file1.close() self.update_data()
class Main(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setup_signals() self.initialize_project() def initialize_project(self): print 'initializing' prj_files = glob.glob('../data/*.conf') self.projects = {} for config in prj_files: path_fname = list(os.path.split(os.path.abspath(config))) config_name = os.path.splitext(path_fname[1])[0] self.projects[config_name] = path_fname self.prj_model = QStandardItemModel(self.ui.ProjectsListView) for prj_name in self.projects: item = QStandardItem(prj_name) print "Adding " + prj_name self.prj_model.appendRow(item) self.ui.ProjectsListView.setModel(self.prj_model) self.ui.ProjectsListView.selectionModel().select( self.prj_model.index(0, 0, QModelIndex()), QtGui.QItemSelectionModel.Select) def show_about(self): print "its all about me!" dlg = QtGui.QDialog() ui = Ui_aboutDialog() ui.setupUi(dlg) dlg.show() dlg.exec_() def show_help(self): print "show Help!" pass def new_prj(self): print "create new tag name" dlg = QtGui.QDialog() TagNames(dlg) dlg.show() dlg.exec_() def delete_prj(self): print "Delete" def do_save(self): print "save it" def do_save_as(self): print "save as this" def prj_menu(self, QPos): self.listMenu = QtGui.QMenu(self.ui.ProjectsListView) menu_item = self.listMenu.addAction("New") self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.new_prj) menu_item = self.listMenu.addAction("Save") self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.do_save) menu_item = self.listMenu.addAction("Save as") self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.do_save_as) menu_item = self.listMenu.addAction("Delete") self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.delete_prj) parentPosition = self.ui.ProjectsListView.mapToGlobal( QtCore.QPoint(0, 0)) self.listMenu.move(parentPosition + QPos) self.listMenu.show() def setup_signals(self): # will be setting up slots and signals here print "setting up slots and signals" QtCore.QObject.connect(self.ui.actionAbout, QtCore.SIGNAL(_fromUtf8("activated()")), self.show_about) QtCore.QObject.connect(self.ui.actionNew, QtCore.SIGNAL(_fromUtf8("activated()")), self.new_prj) QtCore.QObject.connect(self.ui.actionSave, QtCore.SIGNAL(_fromUtf8("activated()")), self.do_save) QtCore.QObject.connect(self.ui.actionSave_as, QtCore.SIGNAL(_fromUtf8("activated()")), self.do_save_as) QtCore.QObject.connect(self.ui.actionHelp, QtCore.SIGNAL(_fromUtf8("activated()")), self.show_help) self.ui.ProjectsListView.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.ui.ProjectsListView.connect( self.ui.ProjectsListView, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.prj_menu)
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 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 QMapManager(QDialog): def __init__(self, config, parent=None): QDialog.__init__(self, parent) curdir = os.path.abspath(os.path.dirname(__file__)) PyQt4.uic.loadUi(os.path.join(curdir, 'manager.ui'), self) self.model = QStandardItemModel() self.projectsmodel = QStandardItemModel() self.projectlist.setModel(self.projectsmodel) self.clientlist.setModel(self.model) self.clientlist.selectionModel().selectionChanged.connect(self.update) self.installbutton.pressed.connect(self.installToClient) self.mapper = QDataWidgetMapper() self.mapper.setModel(self.model) self.mapper.addMapping(self.installpath, 1) self.config = config self.populateProjects() self.populateClients() def installToClient(self): index = self.clientlist.selectionModel().currentIndex() item = self.model.itemFromIndex(index) print "Deploying to " + item.text() build.deployTargetByName(item.text()) def update(self, selected, deselected): index = selected.indexes()[0] self.mapper.setCurrentModelIndex(index) item = self.model.itemFromIndex(index) settings = item.data() for row in xrange(0, self.projectsmodel.rowCount()): index = self.projectsmodel.index(row, 0) item = self.projectsmodel.itemFromIndex(index) item.setCheckState(Qt.Unchecked) projects = settings['projects'] for project in projects: if project == "All": i = 0 while self.projectsmodel.item(i): item = self.projectsmodel.item(i) item.setCheckState(Qt.Checked) i += 1 break projectitem = self.projectsmodel.findItems(project)[0] projectitem.setCheckState(Qt.Checked) def populateClients(self): row = 0 for client, settings in self.config['clients'].iteritems(): name = QStandardItem(client) name.setData(settings) path = QStandardItem(settings['path']) self.model.insertRow(row, [name, path]) row += 1 def populateProjects(self): row = 0 for project in getProjects(): projectitem = QStandardItem(project.name) projectitem.setCheckable(True) self.projectsmodel.insertRow(row, projectitem) row += 1
class Regression_PLOT_PyQt(QDialog): """ This calss return a PyQt GUI with a regression plot """ def __init__(self, Minerals=None, string=None, flag=None): super(Regression_PLOT_PyQt, self).__init__() if string is not None: self.stringK, self.stringG, self.stringRho, self.user_input = string else: self.stringK = None self.stringG = None self.stringRho = None self.user_input = False self.resize(1400, 600) self.Minerals = Minerals self.dirty = False #self.user_input = user_input self.Minerals.original_flag() self.Minerals.read_data() self.table = QTableView() self.model = QStandardItemModel(25, 7, self) self.model.setHorizontalHeaderLabels([ 'flag', 'Water Content', 'Iron Content', 'K (Gpa)', 'G (Gpa)', 'Rho (g/cm³)', 'Reference' ]) for i in range(len(self.Minerals.Flag)): a = self.Minerals.Return_original_data(i) for j in range(0, 7): item = QStandardItem(str(a[j])) self.model.setItem(i, j, item) if j != 0: item.setFlags(Qt.ItemIsEnabled) item.setBackground(QColor(211, 211, 211)) if flag is not None: self.Minerals.change_flag(flag) for i in range(len(self.Minerals.Flag)): item = QStandardItem(str(self.Minerals.Flag[i])) self.model.setItem(i, 0, item) self.table.setModel(self.model) self.button = QPushButton('Update and use in thermoelastic model') self.button.clicked.connect(self.Update) self.button.setAutoDefault(False) self.button1 = QPushButton('Add data file ') self.button1.clicked.connect(self.Export) self.button1.setAutoDefault(False) self.layout = QGridLayout() self.label = QLabel() self.label.setText(''' Please input equation, Water: water content (wt%) and Fe: iron content (mol%) for example -2.41*Water-30*Fe+81,K'=4.1, ''') self.Kinput_formula = QLineEdit() self.Ginput_formula = QLineEdit() self.Rhoinput_formula = QLineEdit() if self.stringK is not None: self.Kinput_formula.setText(self.stringK) self.Ginput_formula.setText(self.stringG) self.Rhoinput_formula.setText(self.stringRho) self.Userinput() else: self.Kinput_formula.setText( self.Minerals.Show_fit_function(self.Minerals.function_K()[0], self.Minerals.function_K()[1], "K'", error=False)) self.Ginput_formula.setText( self.Minerals.Show_fit_function(self.Minerals.function_G()[0], self.Minerals.function_G()[1], "G'", error=False)) self.Rhoinput_formula.setText( self.Minerals.Show_fit_function( self.Minerals.function_Rho()[0], self.Minerals.function_Rho()[1], '', error=False)) self.Kinput_formula.returnPressed.connect(self.Kformula) self.Ginput_formula.returnPressed.connect(self.Gformula) self.Rhoinput_formula.returnPressed.connect(self.Rhoformula) #self.connect(self.Kinput_formula,SIGNAL("returnPressed()"),self.Kformula) #self.connect(self.Ginput_formula,SIGNAL("returnPressed()"),self.Gformula) #self.connect(self.Rhoinput_formula,SIGNAL("returnPressed()"),self.Rhoformula) self.user_change_confrim = QPushButton('Change to user input') self.user_change_confrim.clicked.connect(self.Userinput) self.user_change_confrim.setAutoDefault(False) self.extension = QWidget() self.extensionLayout = QGridLayout() self.extensionLayout.setContentsMargins(0, 0, 0, 0) labelK = QLabel() labelK.setText('K<sub>0</sub>=') labelG = QLabel() labelG.setText('G<sub>0</sub>=') labelRho = QLabel() labelRho.setText('Rho<sub>0</sub>=') self.extensionLayout.addWidget(labelK, 0, 0, 1, 3) self.extensionLayout.addWidget(labelG, 1, 0, 1, 3) self.extensionLayout.addWidget(labelRho, 2, 0, 1, 3) self.extensionLayout.addWidget(self.Kinput_formula, 0, 1, 1, 3) self.extensionLayout.addWidget(self.Ginput_formula, 1, 1, 1, 3) self.extensionLayout.addWidget(self.Rhoinput_formula, 2, 1, 1, 3) self.extensionLayout.addWidget(self.user_change_confrim, 3, 0, 9, 4) self.extension.setLayout(self.extensionLayout) self.check_change = QCheckBox("user input") self.check_change.setChecked(False) self.check_change.toggled.connect(self.extension.setVisible) #self.PLOT(switch=True) self.PLOT() self.layout.addWidget(self.table, 0, 1, 1, 17) self.layout.addWidget(self.button, 2, 0, 1, 9) self.layout.addWidget(self.button1, 2, 9, 1, 9) self.layout.addWidget(self.check_change, 3, 0, 1, 1) self.layout.addWidget(self.label, 3, 3, 1, 5) self.layout.addWidget(self.extension, 4, 0, 1, 9) self.setLayout(self.layout) self.extension.hide() def Kformula(self): self.stringK = str(self.Kinput_formula.text()) self.K0 = np.array( re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", self.stringK)) return self.K0, self.stringK def Gformula(self): self.stringG = str(self.Ginput_formula.text()) self.G0 = np.array( re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", self.stringG)) return self.G0, self.stringG def Rhoformula(self): self.stringRho = str(self.Rhoinput_formula.text()) self.Rho0 = np.array( re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", self.stringRho)) return self.Rho0, self.stringRho def Userinput(self): self.Minerals.User_Change(self.Kformula(), self.Gformula(), self.Rhoformula()) self.user_input = True self.PLOT() def PLOT(self, switch=True): if self.dirty == False: #self.Minerals.Clean_content() params = [] for i in range(20): index = self.model.index(i, 0) try: aa = (float(self.model.itemData(index)[0])) #print (aa) params.append(aa) except: break #print (params) self.Minerals.Change_data_from_table(params) #print ('wf') else: self.model.setHorizontalHeaderLabels([ 'flag', 'Water Content', 'Iron Content', 'K (Gpa)', 'G (Gpa)', 'Rho (g/cm3)', 'Reference' ]) for i in range(len(self.Minerals.Flag)): #a=self.Minerals.Return_original_data(i) item = QStandardItem(str(self.Minerals.Flag[i])) self.model.setItem(i, 0, item) #============================================================================== # for j in range(1,7): # item = QStandardItem(str(a[j])) # self.model.setItem(i, j,item) # if j != 0: # item.setFlags(Qt.ItemIsEnabled) # item.setBackground(QColor(211,211,211)) #============================================================================== #print (self.Minerals.Change) if self.user_input == False: self.a, self.b, self.c = self.Minerals.PLOT(return_fig=False) #print (self.Minerals.number_of_data) self.Kinput_formula.setText( self.Minerals.Show_fit_function(self.Minerals.function_K()[0], self.Minerals.function_K()[1], "K'", error=False)) self.Ginput_formula.setText( self.Minerals.Show_fit_function(self.Minerals.function_G()[0], self.Minerals.function_G()[1], "G'", error=False)) self.Rhoinput_formula.setText( self.Minerals.Show_fit_function( self.Minerals.function_Rho()[0], self.Minerals.function_Rho()[1], '', error=False)) else: self.a, self.b, self.c = self.Minerals.PLOT_input_formula( return_fig=False) self.canvas1 = FigureCanvas3D(self.a) self.canvas2 = FigureCanvas3D(self.b) self.canvas3 = FigureCanvas3D(self.c) self.canvas1.mpl_connect('pick_event', self.onpick) self.canvas2.mpl_connect('pick_event', self.onpick) self.canvas3.mpl_connect('pick_event', self.onpick) self.toolbar1 = NavigationToolbar(self.canvas1, self) self.toolbar2 = NavigationToolbar(self.canvas2, self) self.toolbar3 = NavigationToolbar(self.canvas3, self) self.layout1_widget = QWidget() self.layout1 = QGridLayout(self.layout1_widget) self.layout1_widget.setFixedSize(600, 600) self.layout1.addWidget(self.canvas1, 0, 1, 5, 5) self.layout1.addWidget(self.toolbar1, 5, 1, 1, 5) self.layout1.addWidget(self.canvas2, 6, 1, 5, 5) self.layout1.addWidget(self.toolbar2, 11, 1, 1, 5) self.layout1.addWidget(self.canvas3, 12, 1, 5, 5) self.layout1.addWidget(self.toolbar3, 17, 1, 1, 5) self.layout.addWidget(self.layout1_widget, 0, 0, 1, 1) def onpick(self, event): try: for i in range(6): self.model.item(self.ind, i + 1).setBackground(QColor(211, 211, 211)) except: pass count = -1 for j in range(len((self.Minerals.Flag))): if self.Minerals.Flag[j] == 1: count += 1 if count == event.ind[0]: self.ind = j break #print (self.ind) #self.ind = event.ind for i in range(6): self.model.item(self.ind, i + 1).setBackground(QColor(111, 111, 111)) def Update(self): self.user_input = False self.dirty = False self.check_change.setChecked(False) self.PLOT() def Export(self): self.dirty = True dialog = TextEditor(name=self.Minerals.name) if dialog.exec_(): pass self.Minerals.read_data() self.PLOT() def ReturnString(self): aa = self.Minerals.Flag bb = str(int(aa[0])) for i in range(1, len(aa)): bb += str(int(aa[i])) return [self.stringK, self.stringG, self.stringRho, self.user_input], bb
class OWConfusionMatrix(widget.OWWidget): name = "Confusion Matrix" description = "Shows a confusion matrix." icon = "icons/ConfusionMatrix.svg" priority = 1001 inputs = [{ "name": "Evaluation Results", "type": Orange.evaluation.Results, "handler": "set_results" }] outputs = [{"name": "Selected Data", "type": Orange.data.Table}] quantities = [ "Number of instances", "Proportion of predicted", "Proportion of actual" ] selected_learner = settings.Setting([]) selected_quantity = settings.Setting(0) append_predictions = settings.Setting(True) append_probabilities = settings.Setting(False) autocommit = settings.Setting(True) def __init__(self, parent=None): super().__init__(parent) self.data = None self.results = None self.learners = [] box = gui.widgetBox(self.controlArea, "Learners") self.learners_box = gui.listBox(box, self, "selected_learner", "learners", callback=self._learner_changed) box = gui.widgetBox(self.controlArea, "Show") gui.comboBox(box, self, "selected_quantity", items=self.quantities, callback=self._update) box = gui.widgetBox(self.controlArea, "Select") gui.button(box, self, "Correct", callback=self.select_correct, autoDefault=False) gui.button(box, self, "Misclassified", callback=self.select_wrong, autoDefault=False) gui.button(box, self, "None", callback=self.select_none, autoDefault=False) self.outputbox = box = gui.widgetBox(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 Data", "Auto send is on") grid = QGridLayout() grid.setContentsMargins(0, 0, 0, 0) grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter) grid.addWidget(VerticalLabel("Actual Class"), 1, 0, Qt.AlignCenter) self.tablemodel = QStandardItemModel() self.tableview = QTableView(editTriggers=QTableView.NoEditTriggers) self.tableview.setModel(self.tablemodel) self.tableview.selectionModel().selectionChanged.connect( self._invalidate) grid.addWidget(self.tableview, 1, 1) self.mainArea.layout().addLayout(grid) def set_results(self, results): """Set the input results.""" self.clear() self.warning([0, 1]) data = None if results is not None: if results.data is not None: data = results.data if data is not None and \ not isinstance(data.domain.class_var, Orange.data.DiscreteVariable): data = None results = None self.warning( 0, "Confusion Matrix cannot be used for 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 not None: nmodels, ntests = results.predicted.shape 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 = ["L %i" % (i + 1) for i in range(nmodels)] self.tablemodel.setVerticalHeaderLabels(headers) self.tablemodel.setHorizontalHeaderLabels(headers) self.tablemodel.setRowCount(len(class_values) + 1) self.tablemodel.setColumnCount(len(class_values) + 1) self.selected_learner = [0] self._update() def clear(self): self.results = None self.data = None self.tablemodel.clear() # Clear learners last. This action will invoke `_learner_changed` # method self.learners = [] def select_correct(self): selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(n): index = self.tablemodel.index(i, i) selection.select(index, index) self.tableview.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def select_wrong(self): selection = QItemSelection() n = self.tablemodel.rowCount() for i in range(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): self.tableview.selectionModel().clear() def commit(self): if self.results is not None and self.data is not None \ and self.selected_learner: indices = self.tableview.selectedIndexes() indices = {(ind.row(), ind.column()) for ind in indices} actual = self.results.actual selected_learner = self.selected_learner[0] learner_name = self.learners[selected_learner] predicted = self.results.predicted[selected_learner] 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[selected_learner, 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): self.commit() def _learner_changed(self): # The selected learner has changed self._update() self._invalidate() def _update(self): # Update the displayed confusion matrix if self.results is not None and self.selected_learner: index = self.selected_learner[0] cmatrix = confusion_matrix(self.results, index) colsum = cmatrix.sum(axis=0) rowsum = cmatrix.sum(axis=1) total = rowsum.sum() if self.selected_quantity == 0: value = lambda i, j: int(cmatrix[i, j]) elif self.selected_quantity == 1: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i]) if colsum[i] else "N/A") elif self.selected_quantity == 2: value = lambda i, j: \ ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i]) if colsum[i] else "N/A") else: assert False model = self.tablemodel for i, row in enumerate(cmatrix): for j, _ in enumerate(row): item = model.item(i, j) if item is None: item = QStandardItem() item.setData(value(i, j), Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) model.setItem(i, j, item) font = model.invisibleRootItem().font() bold_font = QFont(font) bold_font.setBold(True) def sum_item(value): item = QStandardItem() item.setData(value, Qt.DisplayRole) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) item.setFlags(Qt.ItemIsEnabled) item.setFont(bold_font) return item N = len(colsum) for i in range(N): model.setItem(N, i, sum_item(int(colsum[i]))) model.setItem(i, N, sum_item(int(rowsum[i]))) model.setItem(N, N, sum_item(int(total)))
item1 = QStandardItem() item1.setText("B") pixmap1 = QPixmap(50, 50) pixmap1.fill(Qt.blue) item1.setIcon(QIcon(pixmap1)) item1.setToolTip("indexB") parentItem.appendRow(item1) # 创建新的标准项,这里使用了另一种方法来设置文本、图标和工具提示 item2 = QStandardItem() pixmap2 = QPixmap(50, 50) pixmap2.fill(Qt.green) item2.setData("C", Qt.EditRole) # 等同于 setText("C") item2.setData("indexC", Qt.ToolTipRole) # 等同于 setToolTip("indexB") item2.setData(QIcon(pixmap2), Qt.DecorationRole) #等同于 setIcon(QIcon(pixmap1)) parentItem.appendRow(item2) # 在树视图中显示模型 view.setModel(model) view.show() # 获取item0的索引并输出item0的子项数目,然后输出了item1的显示文本和工具提示 indexA = model.index(0, 0, QModelIndex()) print "indexA row count: ", model.rowCount(indexA) indexB = model.index(0, 0, indexA) print "indexB text: ", model.data(indexB, Qt.EditRole).toString() print "indexB toolTip: ", model.data(indexB, Qt.ToolTipRole).toString() app.exec_()
class NeoNavigationDock(QDockWidget, Ui_neoNavigationDock): """ Implements a navigation dock for Neo hierarchies. Tightly coupled with :class:`main_window_neo.MainWindowNeo`, the main reason for this class to exist is to keep the dock out of the general ui file. """ object_removed = pyqtSignal() # Signal to remove an object def __init__(self, parent): QDockWidget.__init__(self, parent) self.parent = parent self.setupUi(self) self.block_model = QStandardItemModel() self.segment_model = QStandardItemModel() self.channelgroup_model = QStandardItemModel() self.channel_model = QStandardItemModel() self.unit_model = QStandardItemModel() self.neoBlockList.setModel(self.block_model) self.neoSegmentList.setModel(self.segment_model) self.neoChannelGroupList.setModel(self.channelgroup_model) self.neoChannelList.setModel(self.channel_model) self.neoUnitList.setModel(self.unit_model) self.neoBlockList.doubleClicked.connect( lambda x: self._edit_item_annotations(x, self.block_model)) self.neoSegmentList.doubleClicked.connect( lambda x: self._edit_item_annotations(x, self.segment_model)) self.neoChannelGroupList.doubleClicked.connect( lambda x: self._edit_item_annotations(x, self.channelgroup_model)) self.neoChannelList.doubleClicked.connect( lambda x: self._edit_item_annotations(x, self.channel_model)) self.neoUnitList.doubleClicked.connect( lambda x: self._edit_item_annotations(x, self.unit_model)) self.neoBlockList.selectionModel().selectionChanged.connect( self.selected_blocks_changed) self.neoChannelGroupList.selectionModel().selectionChanged.connect( self.selected_channel_groups_changed) self.neoChannelList.selectionModel().selectionChanged.connect( self.selected_channels_changed) self.neoUnitList.selectionModel().selectionChanged.connect( self.selected_units_changed) self.neoSegmentList.selectionModel().selectionChanged.connect( self.selected_segments_changed) def clear(self): """ Clear all lists """ self.neoBlockList.clearSelection() self.block_model.clear() def get_letter_id(self, id_, small=False): """ Return a name consisting of letters given an integer """ if id_ < 0: return '' name = '' id_ += 1 if small: start = ord('a') else: start = ord('A') while id_ > 26: id_ -= 1 name += chr(start + (id_ % 26)) id_ /= 26 name += chr(start + id_ - 1) return name[::-1] def ensure_not_filtered(self, objects, all_objects, filters): """ Deactivates all filters that prevent the the given sequence of objects to be displayed. The passed filter tuple list is modified to only include valid filters. :param sequence objects: The objects that need to be visible. :param sequence all_objects: The whole object list to be filtered, including objects that are allowed to be hidden. :param sequence filters: A sequence of (Filter, name) tuples. """ objset = set(objects) if not objset.issubset( set(self.parent.filter_list(all_objects, filters))): i = 1 while i <= len(filters): test_filters = filters[:i] if objset.issubset(set(self.parent.filter_list( all_objects, test_filters))): i += 1 else: test_filters[-1][0].active = False filters.pop(i - 1) for o in objects: i = 0 while i < len(filters): if self.parent.is_filtered(o, [filters[i]]): filters[i][0].active = False filters.pop(i) else: i += 1 def filter_ordered(self, objects, filters): """ Filter a sequence of objects with a sequence of filters. Apply the filters in the order given by the sequence. Return the filtered list. """ for f in filters: if f[0].combined: objects = self.parent.filter_list(objects, [f]) else: objects = [o for o in objects if not self.parent.is_filtered(o, [f])] return objects def populate_neo_block_list(self): """ Fill the block list with appropriate entries. Qt.UserRole: The :class:`neo.Block` object """ self.block_model.clear() filters = self.parent.get_active_filters('Block') blocks = self.filter_ordered( self.parent.block_names.keys(), filters) for b in blocks: item = QStandardItem(self.parent.block_names[b]) item.setData(b, Qt.UserRole) self.block_model.appendRow(item) self.neoBlockList.setCurrentIndex(self.block_model.index(0, 0)) self.set_blocks_label() if not blocks: self.selected_blocks_changed() def populate_neo_segment_list(self): """ Fill the segment list with appropriate entries. Qt.UserRole: The :class:`neo.Segment` object """ self.segment_model.clear() segments = [] for b in self.blocks(): segments.extend(b.segments) filters = self.parent.get_active_filters('Segment') segments = self.filter_ordered(segments, filters) for i, s in enumerate(segments): if s.name: name = s.name + ' (%s-%i)' % \ (self.parent.block_ids[s.block], i) else: name = '%s-%i' % (self.parent.block_ids[s.block], i) new_item = QStandardItem(name) new_item.setData(s, Qt.UserRole) self.segment_model.appendRow(new_item) self.neoSegmentList.setCurrentIndex(self.segment_model.index(0, 0)) if api.config.autoselect_segments: self.neoSegmentList.selectAll() self.selected_segments_changed() def populate_neo_channel_group_list(self): """ Fill the channel group list with appropriate entries. Qt.UserRole: The :class:`neo.RecordingChannelGroup` object """ self.neoChannelGroupList.clearSelection() self.channelgroup_model.clear() self.parent.channel_group_names.clear() rcgs = [] for b in self.blocks(): rcgs.extend(b.recordingchannelgroups) filters = self.parent.get_active_filters( 'Recording Channel Group') rcgs = self.filter_ordered(rcgs, filters) for i, rcg in enumerate(rcgs): self.parent.channel_group_names[rcg] = '%s-%s' % ( self.parent.block_ids[rcg.block], self.get_letter_id(i, True)) if rcg.name: name = rcg.name + ' (%s)' % \ self.parent.channel_group_names[rcg] else: name = self.parent.channel_group_names[rcg] new_item = QStandardItem(name) new_item.setData(rcg, Qt.UserRole) self.channelgroup_model.appendRow(new_item) self.neoChannelGroupList.setCurrentIndex( self.channelgroup_model.index(0, 0)) if api.config.autoselect_channel_groups: self.neoChannelGroupList.selectAll() elif not rcgs: self.selected_channel_groups_changed() def populate_neo_channel_list(self): """ Fill the channel list with appropriate entries. Data slots: Qt.UserRole: The :class:`neo.RecordingChannel` Qt.UserRole+1: The channel index """ self.channel_model.clear() channels = set() rcs = [] rc_group_name = {} for rcg in self.recording_channel_groups(): for rc in rcg.recordingchannels: if not api.config.duplicate_channels and rc in channels: continue channels.add(rc) rcs.append(rc) rc_group_name[rc] = self.parent.channel_group_names[rcg] filters = self.parent.get_active_filters( 'Recording Channel') rcs = self.filter_ordered(rcs, filters) for rc in rcs: identifier = '%s.%d' % \ (rc_group_name[rc], rc.index) if rc.name: name = rc.name + ' (%s)' % identifier else: name = identifier new_item = QStandardItem(name) new_item.setData(rc, Qt.UserRole) new_item.setData(rc.index, Qt.UserRole + 1) self.channel_model.appendRow(new_item) if api.config.autoselect_channels: self.neoChannelList.selectAll() self.selected_channels_changed() def populate_neo_unit_list(self): """ Fill the unit list with appropriate entries. Qt.UserRole: The :class:`neo.Unit` object """ self.unit_model.clear() units = [] for rcg in self.recording_channel_groups(): units.extend(rcg.units) filters = self.parent.get_active_filters('Unit') units = self.filter_ordered(units, filters) for i, u in enumerate(units): if self.parent.is_filtered(u, filters): continue if u.name: name = u.name + ' (%s-%d)' % \ (self.parent.channel_group_names[rcg], i) else: name = '%s-%d' % (self.parent.channel_group_names[rcg], i) new_item = QStandardItem(name) new_item.setData(u, Qt.UserRole) self.unit_model.appendRow(new_item) if api.config.autoselect_units: self.neoUnitList.selectAll() self.selected_units_changed() def set_blocks_label(self): self.blocksLabel.setText( 'Blocks (%d/%d):' % (len(self.neoBlockList.selectedIndexes()), self.block_model.rowCount())) def set_channel_groups_label(self): self.channelGroupsLabel.setText( 'Channel Groups (%d/%d):' % ( len(self.neoChannelGroupList.selectedIndexes()), self.channelgroup_model.rowCount())) def selected_blocks_changed(self): self.set_blocks_label() self.populate_neo_channel_group_list() self.populate_neo_segment_list() def selected_channel_groups_changed(self): self.set_channel_groups_label() self.populate_neo_channel_list() self.populate_neo_unit_list() def selected_channels_changed(self): self.channelsLabel.setText( 'Channels (%d/%d):' % ( len(self.neoChannelList.selectedIndexes()), self.channel_model.rowCount())) def selected_units_changed(self): self.unitsLabel.setText( 'Units (%d/%d):' % ( len(self.neoUnitList.selectedIndexes()), self.unit_model.rowCount())) def selected_segments_changed(self): self.segmentsLabel.setText( 'Segments (%d/%d):' % ( len(self.neoSegmentList.selectedIndexes()), self.segment_model.rowCount())) def _edit_item_annotations(self, index, model): api.annotation_editor(model.data(index, Qt.UserRole)) def remove_selected(self, list_widget): """ Remove all selected objects from the given list widget. """ items = list_widget.selectedIndexes() if len(items) < 1: return model = list_widget.model() question = ('Do you really want to remove %d %s' % (len(items), type(model.data(items[0], Qt.UserRole)).__name__)) if len(items) > 1: question += 's' question += '?' if QMessageBox.question( self, 'Please confirm', question, QMessageBox.Yes | QMessageBox.No) == QMessageBox.No: return for i in list_widget.selectedIndexes(): data = model.data(i, Qt.UserRole) if isinstance(data, neo.Block): self.parent.block_names.pop(data) else: spykeutils.tools.remove_from_hierarchy(data) list_widget.selectionModel().select(i, QItemSelectionModel.Deselect) self.object_removed.emit() def _context_actions(self, list_widget): idx = list_widget.currentIndex() if not idx: return [] data = list_widget.model().data(idx, Qt.UserRole) edit_action = QAction(get_icon('edit.png'), 'Edit annotations...', self) edit_action.triggered.connect( lambda x: self._edit_item_annotations(idx, list_widget.model())) delete_name = 'Delete %s' % type(data).__name__ if len(list_widget.selectedIndexes()) > 1: delete_name += 's' delete_action = QAction(get_icon('editdelete.png'), delete_name, self) delete_action.triggered.connect( lambda x: self.remove_selected(list_widget)) return [edit_action, delete_action] def on_neoBlockList_customContextMenuRequested(self, pos): if not self.neoBlockList.selectedIndexes(): return context_menu = QMenu(self) context_menu.addActions(self._context_actions(self.neoBlockList)) context_menu.popup(self.neoBlockList.mapToGlobal(pos)) def on_neoSegmentList_customContextMenuRequested(self, pos): if not self.neoSegmentList.selectedIndexes(): return context_menu = QMenu(self) context_menu.addActions(self._context_actions(self.neoSegmentList)) context_menu.popup(self.neoSegmentList.mapToGlobal(pos)) def on_neoChannelGroupList_customContextMenuRequested(self, pos): if not self.neoChannelGroupList.selectedIndexes(): return context_menu = QMenu(self) context_menu.addActions(self._context_actions(self.neoChannelGroupList)) context_menu.popup(self.neoChannelGroupList.mapToGlobal(pos)) def on_neoChannelList_customContextMenuRequested(self, pos): if not self.neoChannelList.selectedIndexes(): return context_menu = QMenu(self) context_menu.addActions(self._context_actions(self.neoChannelList)) context_menu.popup(self.neoChannelList.mapToGlobal(pos)) def on_neoUnitList_customContextMenuRequested(self, pos): if not self.neoUnitList.selectedIndexes(): return context_menu = QMenu(self) context_menu.addActions(self._context_actions(self.neoUnitList)) context_menu.popup(self.neoUnitList.mapToGlobal(pos)) def blocks(self): """ Return selected :class:`neo.Block` objects. """ return [self.block_model.data(i, Qt.UserRole) for i in self.neoBlockList.selectedIndexes()] def segments(self): """ Return selected :class:`neo.Segment` objects. """ return [self.segment_model.data(i, Qt.UserRole) for i in self.neoSegmentList.selectedIndexes()] def recording_channel_groups(self): """ Return selected :class:`neo.RecordingChannelGroup` objects. """ return [self.channelgroup_model.data(i, Qt.UserRole) for i in self.neoChannelGroupList.selectedIndexes()] def recording_channels(self): """ Return selected :class:`neo.RecordingChannel` objects. """ return [self.channel_model.data(i, Qt.UserRole) for i in self.neoChannelList.selectedIndexes()] def units(self): """ Return selected :class:`neo.Unit` objects. """ return [self.unit_model.data(i, Qt.UserRole) for i in self.neoUnitList.selectedIndexes()] def set_selection(self, data): """ Set the selected data. """ block_list = [] for b in data['blocks']: cl = None rp = None if len(b) > 2: cl = NeoDataProvider.find_io_class(b[2]) if len(b) > 3: rp = b[3] loaded = NeoDataProvider.get_block( b[1], b[0], force_io=cl, read_params=rp) if loaded is None: raise IOError('One of the files contained in the ' 'selection could not be loaded!') block_list.append(loaded) block_set = set([(b[0], b[1]) for b in data['blocks']]) # Select blocks self.ensure_not_filtered(block_list, self.parent.block_names.keys(), self.parent.get_active_filters('Block')) self.populate_neo_block_list() selection = QItemSelection() for i in self.block_model.findItems( '*', Qt.MatchWrap | Qt.MatchWildcard): block = i.data(Qt.UserRole) t = (NeoDataProvider.block_indices[block], self.parent.block_files[block]) if t in block_set: selection.append(QItemSelectionRange( self.block_model.indexFromItem(i))) self.neoBlockList.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) # Select segments seg_list = [block_list[idx[1]].segments[idx[0]] for idx in data['segments']] all_segs = [] for b in self.blocks(): all_segs.extend(b.segments) self.ensure_not_filtered(seg_list, all_segs, self.parent.get_active_filters('Segment')) self.populate_neo_segment_list() selection = QItemSelection() for i in self.segment_model.findItems( '*', Qt.MatchWrap | Qt.MatchWildcard): segment = i.data(Qt.UserRole) if not segment.block in block_list: continue seg_idx = segment.block.segments.index(segment) block_idx = block_list.index(segment.block) if [seg_idx, block_idx] in data['segments']: selection.append(QItemSelectionRange( self.segment_model.indexFromItem(i))) self.neoSegmentList.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) # Select recording channel groups rcg_list = [block_list[rcg[1]].recordingchannelgroups[rcg[0]] for rcg in data['channel_groups']] all_rcgs = [] for b in self.blocks(): all_rcgs.extend(b.recordingchannelgroups) self.ensure_not_filtered( rcg_list, all_rcgs, self.parent.get_active_filters('Recording Channel Group')) self.populate_neo_channel_group_list() selection = QItemSelection() for i in self.channelgroup_model.findItems( '*', Qt.MatchWrap | Qt.MatchWildcard): rcg = i.data(Qt.UserRole) if not rcg.block in block_list: continue rcg_idx = rcg.block.recordingchannelgroups.index(rcg) block_idx = block_list.index(rcg.block) if [rcg_idx, block_idx] in data['channel_groups']: selection.append(QItemSelectionRange( self.channelgroup_model.indexFromItem(i))) self.neoChannelGroupList.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) # Select channels rc_list = [rcg_list[rc[1]].recordingchannels[rc[0]] for rc in data['channels']] all_rcs = [] for rcg in self.recording_channel_groups(): for rc in rcg.recordingchannels: if not api.config.duplicate_channels and rc in all_rcs: continue all_rcs.append(rc) self.ensure_not_filtered( rc_list, all_rcs, self.parent.get_active_filters('Recording Channel')) self.populate_neo_channel_list() selection = QItemSelection() rcg_set = set(rcg_list) for i in self.channel_model.findItems( '*', Qt.MatchWrap | Qt.MatchWildcard): channel = i.data(Qt.UserRole) if not set(channel.recordingchannelgroups).intersection(rcg_set): continue for rcg in channel.recordingchannelgroups: if [rcg.recordingchannels.index(channel), rcg_list.index(rcg)] in data['channels']: selection.append(QItemSelectionRange( self.channel_model.indexFromItem(i))) break self.neoChannelList.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) # Select units unit_list = [rcg_list[u[1]].units[u[0]] for u in data['units']] all_units = [] for rcg in self.recording_channel_groups(): all_units.extend(rcg.units) self.ensure_not_filtered( unit_list, all_units, self.parent.get_active_filters('Unit')) self.populate_neo_unit_list() selection = QItemSelection() for i in self.unit_model.findItems( '*', Qt.MatchWrap | Qt.MatchWildcard): unit = i.data(Qt.UserRole) if unit.recordingchannelgroup not in rcg_list: continue rcg_idx = rcg_list.index(unit.recordingchannelgroup) unit_idx = unit.recordingchannelgroup.units.index(unit) if [unit_idx, rcg_idx] in data['units']: selection.append(QItemSelectionRange( self.unit_model.indexFromItem(i))) self.neoUnitList.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) self.parent.refresh_filters()
class MainWindow(mainwindow_widget, mainwindow_base): """ Main application window """ def __init__(self, settings): super(MainWindow, self).__init__() self.setupUi(self) self.settings = settings roam.featureform.settings = settings.settings self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self) self.actionMap.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) #TODO Extract GPS out into a service and remove UI stuff self.actionGPS = GPSAction(":/icons/gps", self.canvas, self.settings, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget = ProjectsWidget(self) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.project_page.layout().addWidget(self.projectwidget) self.syncwidget = SyncWidget() self.syncpage.layout().addWidget(self.syncwidget) self.settingswidget = SettingsWidget(settings, self) self.settings_page.layout().addWidget(self.settingswidget) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) self.dataentrywidget.openimage.connect(self.openimage) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.stackedWidget.currentChanged.connect(self.updateUIState) self.panels = [] self.connectButtons() self.band = QgsRubberBand(self.canvas) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentrymodel = QStandardItemModel(self) self.dataentrycombo = QComboBox(self.projecttoolbar) self.dataentrycombo.setIconSize(QSize(48,48)) self.dataentrycombo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.dataentrycombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.dataentrycombo.setModel(self.dataentrymodel) self.dataentrycomboaction = self.projecttoolbar.insertWidget(self.topspaceraction, self.dataentrycombo) self.dataentrycombo.showPopup = self.selectdataentry self.biglist = BigList(self.canvas) self.biglist.setlabel("Select data entry form") self.biglist.setmodel(self.dataentrymodel) self.biglist.itemselected.connect(self.dataentrychanged) self.biglist.hide() self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.requestopenform.connect(self.openForm) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.resultscleared.connect(self.clearselection) self.infodock.openurl.connect(self.viewurl) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) self.projecttoolbar.toolButtonStyleChanged.connect(self.updatecombo) def selectdataentry(self, ): if self.dataentrycombo.count() == 0: return self.biglist.show() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] except KeyError: # It's not a image so lets just pass it of as a normal # URL QDesktopServices.openUrl(url) return pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def updatecombo(self, *args): self.dataentrycombo.setMinimumHeight(0) def settingsupdated(self, settings): settings.save() self.show() self.actionGPS.updateGPSPort() # eww! roam.featureform.settings = settings.settings def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def highlightselection(self, results): for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 150)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.band.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.band.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): wasactive = self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentrycombo.setCurrentIndex(index.row()) self.createCaptureButtons(form, wasactive) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError('Seems something has gone wrong. Press for more details', info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = TouchMapTool(self.canvas) self.moveTool = MoveTool(self.canvas, []) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionMove, self.moveTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(self.showInfoResults) # The edit toolbutton is currently not being used but leaving it for feature. self.moveTool.layersupdated.connect(self.actionMove.setEnabled) self.moveTool.layersupdated.connect(self.actionEdit_Tools.setEnabled) self.actionGPSFeature.triggered.connect(self.addFeatureAtGPS) self.actionGPSFeature.setEnabled(self.actionGPS.isConnected) self.actionGPS.gpsfixed.connect(self.actionGPSFeature.setEnabled) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def showToolError(self, label, message): self.bar.pushMessage(label, message, QgsMessageBar.WARNING) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form, wasselected): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) if action.isdefault: action.setChecked(wasselected) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showToolError, form.label)) self.projecttoolbar.insertAction(self.topspaceraction, self.actionGPSFeature) self.actionGPSFeature.setVisible(not tool.isEditTool()) def createFormButtons(self, forms): """ Create buttons for each form that is defined """ self.dataentrymodel.clear() self.clearCapatureTools() def captureFeature(form): item = QStandardItem(QIcon(form.icon), form.icontext) item.setData(form, Qt.UserRole + 1) item.setSizeHint(QSize(item.sizeHint().width(), self.projecttoolbar.height())) self.dataentrymodel.appendRow(item) capabilitityhandlers = {"capture": captureFeature} failedforms = [] for form in forms: valid, reasons = form.valid if not valid: roam.utils.log("Form is invalid for data entry because {}".format(reasons)) failedforms.append((form, reasons)) continue for capability in form.capabilities: try: capabilitityhandlers[capability](form) except KeyError: # Just ignore capabilities we don't support yet. continue if failedforms: for form, reasons in failedforms: html = "<h3>{}</h3><br>{}".format(form.label, "<br>".join(reasons)) self.bar.pushMessage("Form errors", "Looks like some forms couldn't be loaded", level=QgsMessageBar.WARNING, extrainfo=html) visible = self.dataentrymodel.rowCount() > 0 self.dataentrycomboaction.setVisible(visible) self.dataentrycombo.setMinimumHeight(self.projecttoolbar.height()) index = self.dataentrymodel.index(0, 0) self.dataentrychanged(index) def addFeatureAtGPS(self): """ Add a record at the current GPS location. """ index = self.dataentrycombo.currentIndex() modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) point = self.actionGPS.position point = QgsGeometry.fromPoint(point) self.addNewFeature(form=form, geometry=point) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self): self.dataentryfinished() self.bar.pushMessage("Deleted", "Feature Deleted", QgsMessageBar.INFO, 1) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.band.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: self.bar.pushMessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature): """ Open the form that is assigned to the layer """ self.band.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): self.infodock.clearResults() forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = self.settings.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ pass @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) self.createFormButtons(forms=self.project.forms) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) # TODO Abstract this out if not self.project.selectlayers: selectionlayers = QgsMapLayerRegistry.instance().mapLayers().values() else: selectionlayers = [] for layername in self.project.selectlayers: try: layer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0] except IndexError: roam.utils.warning("Can't find QGIS layer for select layer {}".format(layername)) continue selectionlayers.append(layer) self.infoTool.selectionlayers = selectionlayers self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() self.infodock.clearResults() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler(self.badLayerHandler) self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.dataentrymodel.clear() self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
class Terminals(QWidget): ready = pyqtSignal(bool) def __init__(self, parent=None): QWidget.__init__(self, parent) self.ui = uic.loadUiType('terminal.ui')[0]() self.ui.setupUi(self) self.notifier = QSystemTrayIcon(QIcon('arrow-up-icon.png'), self) self.notifier.show() self.session = None self.model = None self.devices = {} self.mainloop = None self.delegate = None def test_display(self): if self.mainloop: self.mainloop.test_display() def update_device_config(self): if self.mainloop: self.mainloop.update_config() def terminal_open(self, addr): if self.mainloop: self.mainloop.terminal_open(addr) def terminal_close(self, addr): if self.mainloop: self.mainloop.terminal_close(addr) def begin_session(self, fio, access): if access in ['operator']: self.ui.cashier.setText(fio) self.session = (fio, access) return True return False def end_session(self, block=False): self.ui.cashier.setText(u'') self.session = None self.stop_mainloop(block) return True def on_mainloop_stopped(self): self.mainloop = None if self.session: self.start_mainloop() def start_mainloop(self): if self.mainloop is None: self.mainloop = Mainloop(devices=self.devices) self.mainloop.ready.connect(self.on_mainloop_ready) self.mainloop.stopped.connect(self.on_mainloop_stopped) self.mainloop.notify.connect(lambda title, msg: self.notifier.showMessage(title, msg)) self.mainloop.start() def stop_mainloop(self, block=False): if self.mainloop: try: self.mainloop.state.disconnect() self.mainloop.ready.disconnect() self.mainloop.notify.disconnect() except TypeError: print 'NOTE: mainloop signals disconnect' if self.model: [self.ui.terminals.closePersistentEditor(self.model.index(row, 0)) for row in xrange(self.model.rowCount())] self.mainloop.stop(block) else: self.ready.emit(False) def reset_mainloop(self, devices): self.devices = devices if self.mainloop is None: self.start_mainloop() else: self.stop_mainloop() def on_mainloop_ready(self, ok, titles): if ok: self.model = QStandardItemModel(len(titles), 1) [self.model.setItem(i, QStandardItem(str(addr))) for i, addr in enumerate(titles.keys())] self.delegate = TerminalDelegate(self.mainloop, titles) self.mainloop.report.connect(self.delegate.report) self.mainloop.state.connect(self.delegate.state) self.ui.terminals.setModel(self.model) self.ui.terminals.setItemDelegateForColumn(0, self.delegate) [self.ui.terminals.openPersistentEditor(self.model.index(row, 0)) for row in xrange(self.model.rowCount())] self.mainloop.db.free_places_update.connect(self.ui.free_places.setValue) self.mainloop.update_config() else: self.model = None self.mainloop = None self.ready.emit(ok)