class MVCConfigurationGUI(MVCConfigurationBase): """ GUI implementation of MVCConfigurationBase """ def __init__(self, configuration): super().__init__(configuration) assertMainThread() srv = Services.getService("MainWindow") srv.aboutToClose.connect(self._aboutToClose) confMenu = srv.menuBar().addMenu("&Configuration") toolBar = srv.getToolBar() configuration.configNameChanged.connect(self._configNameChanged) configuration.dirtyChanged.connect(self._dirtyChanged) style = QApplication.style() self.actLoad = QAction( QIcon.fromTheme("document-open", style.standardIcon(QStyle.SP_DialogOpenButton)), "Open config", self) self.actLoad.triggered.connect(self._execLoad) self.actSave = QAction( QIcon.fromTheme("document-save", style.standardIcon(QStyle.SP_DialogSaveButton)), "Save config", self) self.actSave.triggered.connect(self._execSaveConfig) self.actSaveWithGuiState = QAction( QIcon.fromTheme("document-save", style.standardIcon(QStyle.SP_DialogSaveButton)), "Save config sync gui state", self) self.actSaveWithGuiState.triggered.connect( self._execSaveConfigWithGuiState) self.actNew = QAction( QIcon.fromTheme("document-new", style.standardIcon(QStyle.SP_FileIcon)), "New config", self) self.actNew.triggered.connect(self._execNew) self.actActivate = QAction( QIcon.fromTheme("arrow-up", style.standardIcon(QStyle.SP_ArrowUp)), "Initialize", self) self.actActivate.triggered.connect(self.activate) self.actDeactivate = QAction( QIcon.fromTheme("arrow-down", style.standardIcon(QStyle.SP_ArrowDown)), "Deinitialize", self) self.actDeactivate.triggered.connect(self.deactivate) confMenu.addAction(self.actLoad) confMenu.addAction(self.actSave) confMenu.addAction(self.actSaveWithGuiState) confMenu.addAction(self.actNew) confMenu.addAction(self.actActivate) confMenu.addAction(self.actDeactivate) toolBar.addAction(self.actLoad) toolBar.addAction(self.actSave) toolBar.addAction(self.actNew) toolBar.addAction(self.actActivate) toolBar.addAction(self.actDeactivate) self.recentConfigs = [QAction() for i in range(10)] self.recentConfigs[0].setShortcut(QKeySequence(Qt.CTRL + Qt.Key_R)) confMenu.addSeparator() recentMenu = confMenu.addMenu("Recent") for a in self.recentConfigs: a.setVisible(False) a.triggered.connect(self._openRecent) recentMenu.addAction(a) self.mainWidget = srv.newDockWidget("Configuration", None, Qt.LeftDockWidgetArea) self.treeView = QTreeView(self.mainWidget) self.treeView.setHeaderHidden(False) self.treeView.setSelectionMode(QAbstractItemView.NoSelection) self.treeView.setEditTriggers(self.treeView.EditKeyPressed | self.treeView.AnyKeyPressed) self.treeView.setAllColumnsShowFocus(True) self.treeView.setExpandsOnDoubleClick(False) self.treeView.setDragEnabled(True) self.treeView.setDropIndicatorShown(True) self.treeView.setDragDropMode(QAbstractItemView.DragOnly) self.mainWidget.setWidget(self.treeView) self.treeView.setModel(self.model) self.treeView.header().setStretchLastSection(True) self.treeView.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.treeView.doubleClicked.connect(self._onItemDoubleClicked) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.customContextMenuRequested.connect( self._execTreeViewContextMenu) # expand applications by default self.treeView.setExpanded(self.model.index(1, 0), True) self.delegate = PropertyDelegate(self.model, ITEM_ROLE, ConfigurationModel.PropertyContent, self) self.treeView.setItemDelegate(self.delegate) self.restoreState() srv.aboutToClose.connect(self.saveState) # a list of dock widgets displaying subgraphs self._graphViews = [] # make sure that the graph views are closed when the config is closed self._configuration.subConfigRemoved.connect(self._subConfigRemoved) self._waitForActivated = None self._waitForOpenState = None def _execLoad(self): assertMainThread() if self._checkDirty(): return fn, _ = QFileDialog.getOpenFileName(self.mainWidget, "Load configuration", self.cfgfile, filter="*.json") if fn is not None and fn != "": logger.debug("Loading config file %s", fn) try: self.loadConfig(fn) except Exception as e: # pylint: disable=broad-except logger.exception("Error while loading configuration %s: %s", fn, str(e)) QMessageBox.warning(self.mainWidget, "Error while loading configuration", str(e)) def _openRecent(self): """ Called when the user clicks on a recent config. :return: """ if self._checkDirty(): return action = self.sender() fn = action.data() try: self.loadConfig(fn) except Exception as e: # pylint: disable=broad-except # catching general exception is wanted here. logger.exception("Error while loading configuration %s: %s", fn, str(e)) QMessageBox.warning(self.mainWidget, "Error while loading configuration", str(e)) def _checkDirty(self): if self._configuration.dirty(): ans = QMessageBox.question( None, "Save changes?", "There are unsaved changes. Do you want to save them?", buttons=QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, defaultButton=QMessageBox.Save) if ans == QMessageBox.Save: self.saveConfig() return False if ans == QMessageBox.Cancel: return True return False def _aboutToClose(self, mainWindow): if self._checkDirty(): mainWindow.ignoreCloseEvent() def _execNew(self): assertMainThread() if self._checkDirty(): return fn, _ = QFileDialog.getSaveFileName(self.mainWidget, "New configuration", ".", filter="*.json") if fn is not None and fn != "": logger.debug("Creating config file %s", fn) self.newConfig(fn) def _execSaveConfig(self): if self.configuration().filename() is None: self._execSaveConfigAs() else: self.saveConfig() def _execSaveConfigWithGuiState(self): if self.configuration().filename() is None: self._execSaveConfigAs() else: self.saveConfigWithGuiState() def _execSaveConfigAs(self): """ Opens a file dialog to get the save file name and calls saveConfig. :return: """ assertMainThread() fn, _ = QFileDialog.getSaveFileName(self.mainWidget, "Save configuration as", ".", "*.json") if fn is not None and fn != "": self.saveConfigAs(fn) def _addGraphView(self, subConfig): g = subConfig.getGraph() # remove already deleted graph views from internal list valid_graphViews = [] for gv in self._graphViews: if shiboken2.isValid(gv): # pylint: disable=no-member valid_graphViews.append(gv) self._graphViews = valid_graphViews # check if graph view is already there for gv in self._graphViews: if gv.widget().scene().graph == g: logger.info("Graph view already exists.") return # create new graph view srv = Services.getService("MainWindow") graphDw = srv.newDockWidget("Graph (%s)" % (subConfig.getName()), parent=None, defaultArea=Qt.RightDockWidgetArea, allowedArea=Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea) graphDw.setAttribute(Qt.WA_DeleteOnClose, True) assert isinstance(graphDw, QDockWidget) graphView = GraphEditorView(graphDw) graphView.setScene(GraphScene(subConfig.getGraph(), graphDw)) graphDw.setWidget(graphView) self._graphViews.append(graphDw) graphDw.visibleChanged.connect(self._removeGraphViewFromList) def _subConfigRemoved(self, subConfigName, configType): g = self._configuration.subConfigByNameAndTye(subConfigName, configType).getGraph() for gv in self._graphViews: if gv.widget().scene().graph == g: logger.debug("deleting graph view for subconfig %s", subConfigName) gv.deleteLater() def _removeGraphViewFromList(self, visible): if visible: return gv = self.sender() try: self._graphViews.remove(gv) logger.debug("removed graphview from list") except ValueError: logger.debug("graphview not in list, ignored") def _execTreeViewContextMenu(self, point): index = self.treeView.indexAt(point) item = self.model.data(index, ITEM_ROLE) if isinstance(item, ConfigurationModel.SubConfigContent): m = QMenu() a1 = QAction("Edit graph") m.addAction(a1) a1.triggered.connect(lambda: self._addGraphView(item.subConfig)) if self.model.isApplication(index): a2 = QAction("Select Application") a2.triggered.connect(lambda: self.changeActiveApp( self.model.data(index, Qt.DisplayRole))) a3 = QAction("Init Application") a3.triggered.connect(lambda: self._changeActiveAppAndInit( self.model.data(index, Qt.DisplayRole))) m.addActions([a2, a3]) pbsrv = Services.getService("PlaybackControl") m2 = m.addMenu("Init and load sequence") m3 = m.addMenu("Init, load and play") s1 = [] s2 = [] for a in pbsrv.recentSeqs: assert isinstance(a, QAction) if a.isVisible(): # pylint: disable=cell-var-from-loop # the below statements are tested and work aseq = QAction(a.text()) aseq.triggered.connect(lambda arg1=a.data( ), seq=a.data(): self._changeActiveAppInitAndLoad( self.model.data(index, Qt.DisplayRole), seq, False) ) s1.append(aseq) aseq = QAction(a.text()) aseq.triggered.connect(lambda arg1=a.data( ), seq=a.data(): self._changeActiveAppInitAndLoad( self.model.data(index, Qt.DisplayRole), seq, True)) # pylint: enable=cell-var-from-loop s2.append(aseq) m2.addActions(s1) m3.addActions(s2) m.exec_(self.treeView.mapToGlobal(point)) return if self.model.isSubConfigParent( index) == Configuration.CONFIG_TYPE_APPLICATION: m = QMenu() a = QAction("Add application") m.addAction(a) a = m.exec_(self.treeView.mapToGlobal(point)) if a is not None: self._configuration.addNewApplication() return if self.model.isSubConfigParent( index) == Configuration.CONFIG_TYPE_COMPOSITE: m = QMenu() a = QAction("Add composite filter") m.addAction(a) a = m.exec_(self.treeView.mapToGlobal(point)) if a is not None: self._configuration.addNewCompositeFilter() return def _configNameChanged(self, cfgfile): logger.debug("_configNameChanged: %s", cfgfile) assertMainThread() self.cfgfile = cfgfile self._dirtyChanged(self._configuration.dirty()) foundIdx = None for i, a in enumerate(self.recentConfigs): if a.data() == cfgfile: foundIdx = i if foundIdx is None: foundIdx = len(self.recentConfigs) - 1 for i in range(foundIdx, 0, -1): self.recentConfigs[i].setText(self.recentConfigs[i - 1].text()) self.recentConfigs[i].setData(self.recentConfigs[i - 1].data()) self.recentConfigs[i].setVisible( self.recentConfigs[i - 1].data() is not None) self.recentConfigs[0].setText(cfgfile) self.recentConfigs[0].setData(cfgfile) self.recentConfigs[0].setVisible(True) def _dirtyChanged(self, dirty): srv = Services.getService("MainWindow") if self.cfgfile is None: title = "nexxT: <unnamed>" else: title = "nexxT: " + self.cfgfile if dirty: title += " *" srv.setWindowTitle(title) def _onItemDoubleClicked(self, index): assertMainThread() if self.model.isApplication(index): app = self.model.data(index, Qt.DisplayRole) self.changeActiveApp(app) else: self.treeView.edit(index) def _changeActiveAppAndInit(self, app): """ Call this slot to activate and init an application :param app: can be either an Application instance or the name of an application :return: """ assertMainThread() if isinstance(app, str): app = self.configuration().applicationByName(app) currentApp = Application.activeApplication if currentApp is not None: currentApp = currentApp.getApplication() self._waitForActivated = app self.changeActiveApp(app.getName()) def _changeActiveAppInitAndLoad(self, app, sequence, startPlay): self._waitForOpenState = (app, sequence, startPlay) self._changeActiveAppAndInit(app) def appActivated(self, name, app): # pylint: disable=unused-argument """ Called when the application is activated. :param name: the application name :param app: An ActiveApplication instance. :return: """ assertMainThread() if app is not None: self.activeAppStateChange(app.getState()) app.stateChanged.connect(self.activeAppStateChange) if self._waitForActivated == app.getApplication(): MethodInvoker(self.activate, Qt.QueuedConnection) else: self.actActivate.setEnabled(False) self.actDeactivate.setEnabled(False) self._waitForActivated = None def _disconnectSingleShotPlay(self): assertMainThread() pbsrv = Services.getService("PlaybackControl") try: pbsrv.playbackPaused.disconnect(self._singleShotPlay) except RuntimeError: # we are already disconnected. pass def _singleShotPlay(self): assertMainThread() pbsrv = Services.getService("PlaybackControl") MethodInvoker(pbsrv.startPlayback, Qt.QueuedConnection) self._disconnectSingleShotPlay() def activeAppStateChange(self, newState): """ Called when the active application changes its state. :param newState: the new application's state (see FilterState) :return: """ assertMainThread() if newState == FilterState.CONSTRUCTED: self.actActivate.setEnabled(True) else: self.actActivate.setEnabled(False) if newState == FilterState.ACTIVE: if self._waitForOpenState is not None: app, pbfile, startPlay = self._waitForOpenState self._waitForOpenState = None if app == Application.activeApplication.getApplication( ).getName(): pbsrv = Services.getService("PlaybackControl") if startPlay: pbsrv.playbackPaused.connect(self._singleShotPlay) QTimer.singleShot(2000, self._disconnectSingleShotPlay) MethodInvoker(pbsrv.browser.setActive, Qt.QueuedConnection, pbfile) self.actDeactivate.setEnabled(True) self.actSaveWithGuiState.setEnabled(False) else: self.actDeactivate.setEnabled(False) self.actSaveWithGuiState.setEnabled(True) def restoreState(self): """ Restore the state of the configuration gui service (namely the recently open config files). This is saved in QSettings because it is used across config files. :return: """ logger.debug("restoring config state ...") settings = QSettings() v = settings.value("ConfigurationRecentFiles") if v is not None and isinstance(v, QByteArray): ds = QDataStream(v) recentFiles = ds.readQStringList() idx = 0 for f in recentFiles: if f != "" and f is not None: self.recentConfigs[idx].setData(f) self.recentConfigs[idx].setText(f) self.recentConfigs[idx].setVisible(True) idx += 1 if idx >= len(self.recentConfigs): break logger.debug("restoring config state done") def saveState(self): """ Save the state of the configuration gui service (namely the recently open config files). This is saved in QSettings because it is used across config files. :return: """ logger.debug("saving config state ...") settings = QSettings() b = QByteArray() ds = QDataStream(b, QIODevice.WriteOnly) l = [ rc.data() for rc in self.recentConfigs if rc.isVisible() and rc.data() is not None and rc.data() != "" ] ds.writeQStringList(l) settings.setValue("ConfigurationRecentFiles", b) logger.debug("saving config state done (%s)", l)
class BindiffViewerDialog(QDialog): def __init__(self, bv, match_db, role, primary_be, secondary_be): super(BindiffViewerDialog, self).__init__() self.bv = bv self.primary_be = primary_be self.secondary_be = secondary_be self.role = role # UI self.match_model = BindiffMatchModel(bv, match_db, role, primary_be, secondary_be) self.match_view = QTreeView() self.match_view.setModel(self.match_model) self.match_view.setSelectionMode(QTreeView.ExtendedSelection) self.match_view.setContextMenuPolicy(Qt.CustomContextMenu) self.match_view.customContextMenuRequested.connect(self.match_view_context_menu_requested) self.match_view.doubleClicked.connect(self.match_view_double_clicked) self.match_view.setRootIsDecorated(False) self.match_view.setFont(binaryninjaui.getMonospaceFont(self)) for i in range(len(self.match_model.column_infos)): self.match_view.resizeColumnToContents(i) self.match_view.setSortingEnabled(True) self.match_view.sortByColumn(0, Qt.AscendingOrder) layout = QVBoxLayout() layout.addWidget(self.match_view) self.setLayout(layout) self.setWindowTitle("BinDiff Viewer") self.resize(1000, 640) flags = self.windowFlags() flags |= Qt.WindowMaximizeButtonHint flags &= ~Qt.WindowContextHelpButtonHint self.setWindowFlags(flags) def match_view_double_clicked(self, index): if not index.isValid(): assert(False) return if self.role == None: return entry = self.match_model.entries[index.row()] if self.role == 0: address = entry["address1"] elif self.role == 1: address = entry["address2"] else: assert(False) self.bv.navigate(self.bv.file.view, address) def match_view_context_menu_requested(self, pos): if self.role == None: return selected_indices = self.match_view.selectionModel().selectedIndexes() # This may return each row multiple times, so we uniquify selected = set([i.row() for i in selected_indices]) def action_port_symbols(): for i in selected: self.port_symbols(i) menu = QMenu(self.match_view) menu.addAction("Port symbols", action_port_symbols) menu.exec_(self.match_view.mapToGlobal(pos)) def port_symbols(self, i): if self.role == None: return entry = self.match_model.entries[i] target_index = self.role source_index = 1 if target_index == 0 else 0 source_name = entry["name{}".format(source_index + 1)] target_address = entry["address{}".format(target_index + 1)] old_sym = self.bv.get_symbol_at(target_address) target_name = None if old_sym: target_name = old_sym.name target_text = target_name if target_name else "<unnamed>" if not source_name: bn.log_warn("Port symbols: {} @ {:x} has no source name, skipping".format(target_text, target_address)) return if old_sym and not old_sym.auto: bn.log_warn("Port symbols: {} @ {:x} is already named, skipping".format(target_text, target_address)) return bn.log_info("Port symbols: {} @ {:x} -> {}".format(target_text, target_address, source_name)) new_sym = bn.Symbol(bn.SymbolType.FunctionSymbol, target_address, source_name) self.bv.define_user_symbol(new_sym)
class WTreeEdit(QWidget): """TreeEdit widget is to show and edit all of the pyleecan objects data.""" # Signals dataChanged = Signal() def __init__(self, obj, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) self.class_dict = ClassInfo().get_dict() self.treeDict = None # helper to track changes self.obj = obj # the object self.is_save_needed = False self.model = TreeEditModel(obj) self.setupUi() # === Signals === self.selectionModel.selectionChanged.connect(self.onSelectionChanged) self.treeView.collapsed.connect(self.onItemCollapse) self.treeView.expanded.connect(self.onItemExpand) self.treeView.customContextMenuRequested.connect(self.openContextMenu) self.model.dataChanged.connect(self.onDataChanged) self.dataChanged.connect(self.setSaveNeeded) # === Finalize === # set 'root' the selected item and resize columns self.treeView.setCurrentIndex(self.treeView.model().index(0, 0)) self.treeView.resizeColumnToContents(0) def setupUi(self): """Setup the UI""" # === Widgets === # TreeView self.treeView = QTreeView() # self.treeView.rootNode = model.invisibleRootItem() self.treeView.setModel(self.model) self.treeView.setAlternatingRowColors(False) # self.treeView.setColumnWidth(0, 150) self.treeView.setMinimumWidth(100) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.selectionModel = self.treeView.selectionModel() self.statusBar = QStatusBar() self.statusBar.setSizeGripEnabled(False) self.statusBar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.statusBar.setStyleSheet( "QStatusBar {border: 1px solid rgb(200, 200, 200)}") self.saveLabel = QLabel("unsaved") self.saveLabel.setVisible(False) self.statusBar.addPermanentWidget(self.saveLabel) # Splitters self.leftSplitter = QSplitter() self.leftSplitter.setStretchFactor(0, 0) self.leftSplitter.setStretchFactor(1, 1) # === Layout === # Horizontal Div. self.hLayout = QVBoxLayout() self.hLayout.setContentsMargins(0, 0, 0, 0) self.hLayout.setSpacing(0) # add widgets to layout self.hLayout.addWidget(self.leftSplitter) self.hLayout.addWidget(self.statusBar) # add widgets self.leftSplitter.addWidget(self.treeView) self.setLayout(self.hLayout) def update(self, obj): """Check if object has changed and update tree in case.""" if not obj is self.obj: self.obj = obj self.model = TreeEditModel(obj) self.treeView.setModel(self.model) self.model.dataChanged.connect(self.onDataChanged) self.selectionModel = self.treeView.selectionModel() self.selectionModel.selectionChanged.connect( self.onSelectionChanged) self.treeView.setCurrentIndex(self.treeView.model().index(0, 0)) self.setSaveNeeded(True) def setSaveNeeded(self, state=True): self.is_save_needed = state self.saveLabel.setVisible(state) def openContextMenu(self, point): """Generate and open context the menu at the given point position.""" index = self.treeView.indexAt(point) pos = QtGui.QCursor.pos() if not index.isValid(): return # get the data item = self.model.item(index) obj_info = self.model.get_obj_info(item) # init the menu menu = TreeEditContextMenu(obj_dict=obj_info, parent=self) menu.exec_(pos) self.onSelectionChanged(self.selectionModel.selection()) def onItemCollapse(self, index): """Slot for item collapsed""" # dynamic resize for ii in range(3): self.treeView.resizeColumnToContents(ii) def onItemExpand(self, index): """Slot for item expand""" # dynamic resize for ii in range(3): self.treeView.resizeColumnToContents(ii) def onDataChanged(self, first=None, last=None): """Slot for changed data""" self.dataChanged.emit() self.onSelectionChanged(self.selectionModel.selection()) def onSelectionChanged(self, itemSelection): """Slot for changed item selection""" # get the index if itemSelection.indexes(): index = itemSelection.indexes()[0] else: index = self.treeView.model().index(0, 0) self.treeView.setCurrentIndex(index) return # get the data item = self.model.item(index) obj = item.object() typ = type(obj).__name__ obj_info = self.model.get_obj_info(item) ref_typ = obj_info["ref_typ"] if obj_info else None # set statusbar information on class typ msg = f"{typ} (Ref: {ref_typ})" if ref_typ else f"{typ}" self.statusBar.showMessage(msg) # --- choose the respective widget by class type --- # numpy array -> table editor if typ == "ndarray": widget = WTableData(obj, editable=True) widget.dataChanged.connect(self.dataChanged.emit) elif typ == "MeshSolution": widget = WMeshSolution(obj) # only a view (not editable) # list (no pyleecan type, non empty) -> table editor # TODO add another widget for lists of non 'primitive' types (e.g. DataND) elif isinstance(obj, list) and not self.isListType(ref_typ) and obj: widget = WTableData(obj, editable=True) widget.dataChanged.connect(self.dataChanged.emit) # generic editor else: # widget = SimpleInputWidget().generate(obj) widget = WTableParameterEdit(obj) widget.dataChanged.connect(self.dataChanged.emit) # show the widget if self.leftSplitter.widget(1) is None: self.leftSplitter.addWidget(widget) else: self.leftSplitter.replaceWidget(1, widget) widget.setParent( self.leftSplitter) # workaround for PySide2 replace bug widget.show() pass def isListType(self, typ): if not typ: return False return typ[0] == "[" and typ[-1] == "]" and typ[1:-1] in self.class_dict def isDictType(self, typ): if not typ: return False return typ[0] == "{" and typ[-1] == "}" and typ[1:-1] in self.class_dict
class Ui_FE14MapEditor(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.toolbar = QToolBar() self.toggle_coordinate_type_action = QAction("Toggle Coordinate Type") self.refresh_action = QAction("Refresh") self.refresh_action.setShortcut(QKeySequence("Ctrl+R")) self.copy_spawn_action = QAction("Copy Spawn") self.copy_spawn_action.setShortcut(QKeySequence("Ctrl+C")) self.paste_spawn_action = QAction("Paste Spawn") self.paste_spawn_action.setShortcut(QKeySequence("Ctrl+V")) self.add_spawn_action = QAction("Add Spawn") self.delete_spawn_action = QAction("Delete Spawn") self.add_group_action = QAction("Add Group") self.delete_group_action = QAction("Delete Group") self.add_tile_action = QAction("Add Tile") self.toggle_mode_action = QAction("Toggle Mode") self.undo_action = QAction("Undo") self.undo_action.setShortcut(QKeySequence("Ctrl+Z")) self.redo_action = QAction("Redo") self.redo_action.setShortcut(QKeySequence("Ctrl+Shift+Z")) self.toolbar.addActions( [self.toggle_coordinate_type_action, self.refresh_action]) self.toolbar.addSeparator() self.toolbar.addActions([ self.copy_spawn_action, self.paste_spawn_action, self.add_spawn_action, self.delete_spawn_action, self.add_group_action, self.delete_group_action ]) self.toolbar.addSeparator() self.toolbar.addAction(self.add_tile_action) self.toolbar.addSeparator() self.toolbar.addAction(self.toggle_mode_action) self.toolbar.addSeparator() self.toolbar.addActions([self.undo_action, self.redo_action]) self.addToolBar(self.toolbar) self.model_view = QTreeView() self.model_view.setHeaderHidden(True) self.grid = FE14MapGrid() self.grid_scroll = QScrollArea() self.grid_scroll.setWidgetResizable(True) self.grid_scroll.setWidget(self.grid) self.tile_list = QListView() self.terrain_pane = FE14TerrainEditorPane() self.spawn_pane = FE14SpawnEditorPane() self.model_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.model_view_context_menu = QMenu() self.model_view_context_menu.addActions( [self.toggle_coordinate_type_action, self.refresh_action]) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addActions([ self.copy_spawn_action, self.paste_spawn_action, self.add_spawn_action, self.delete_spawn_action, self.add_group_action, self.delete_group_action ]) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addAction(self.add_tile_action) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addAction(self.toggle_mode_action) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addActions( [self.undo_action, self.redo_action]) self.status_bar = QStatusBar() self.coordinate_type_label = QLabel() self.status_bar.addPermanentWidget(self.coordinate_type_label) self.setStatusBar(self.status_bar) self.main_widget = QSplitter() self.main_widget.setOrientation(QtCore.Qt.Horizontal) self.main_widget.addWidget(self.model_view) self.main_widget.addWidget(self.grid_scroll) self.main_widget.addWidget(self.spawn_pane) self.main_widget.addWidget(self.terrain_pane) self.setCentralWidget(self.main_widget)
class PocetnaStrana(QWidget): def __init__(self, parent=None): super().__init__(parent) self.lista_putanja = [] self.lista_baza = [] self.main_window = QtWidgets.QMainWindow() self.main_window.resize(1040, 680) self.main_window.setWindowTitle("Rukovalac informacionim resursima") icon = QtGui.QIcon("src/ikonice/logo.jpg") self.main_window.setWindowIcon(icon) self.meni_bar = MenuBar(self.main_window, parent=None) self.tool_bar = ToolBar(self.main_window,parent=None) self.tool_bar.dodaj.triggered.connect(self.dodavanje_u_datoteku) self.tool_bar.izmeni_tabelu.triggered.connect(self.izmena_u_datoteci) self.tool_bar.pretrazi.triggered.connect(self.otvori_pretragu) self.tool_bar.ponisti_pretragu.triggered.connect(self.ponisti_pretragu) self.tool_bar.ukloni_iz_tabele.triggered.connect(self.ukloni_iz_tabele) self.tool_bar.spoji_datoteke.triggered.connect(self.spoji_datoteke) # self.tool_bar.podeli_datoteku.triggered.connect(self.podeli_datoteku) status_bar = QtWidgets.QStatusBar() #status_bar.showMessage("Prikazan status bar!") self.main_window.setStatusBar(status_bar) self.central_widget = QtWidgets.QTabWidget(self.main_window) self.central_widget.setTabsClosable(True) self.central_widget.tabCloseRequested.connect(self.delete_tab) self.main_window.setCentralWidget(self.central_widget) self.dock = LeftDock("", parent=None) self.main_window.addDockWidget(Qt.LeftDockWidgetArea,self.dock) self.dock.tree.setSelectionMode(QAbstractItemView.SingleSelection) self.dock.tree.clicked.connect(self.read) self.multi_selekt = [] self.listener = keyboard.Listener(on_press=self.pritisnuto_dugme, on_release=self.pusteno_dugme) self.listener.start() self.main_window.show() def ponisti_pretragu(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return model = self.central_widget.currentWidget().table.model() model = pretraga( [], [], [], self.central_widget.currentWidget().meta_podaci, True, self.central_widget.currentWidget()) self.central_widget.currentWidget().table.setModel(model) self.central_widget.currentWidget().table.selectRow(0) self.central_widget.currentWidget().column_resize() def podeli_datoteku(self): # kopirano od metode pretrage if len(self.multi_selekt) == 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije selektovana za spajanje!") poruka.exec_() return prikaz = PrikazElementa(self.central_widget.currentWidget(),True) prikaz.exec_() if len(prikaz.lista_atr) != 0 and len(prikaz.lista_kriterijuma) != 0: model = self.central_widget.currentWidget().table.model() model = pretraga( prikaz.lista_atr, prikaz.lista_kriterijuma, prikaz.lista_vece_manje, self.central_widget.currentWidget().meta_podaci, False) if len(model.lista_prikaz) == 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Zadata pretraga nije pronasla vrednosti koje odgovaraju zadatim kriterijumima.") poruka.exec_() return self.central_widget.currentWidget().table.setModel(model) else: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Niste zadali ni jedan kriterijum za pretragu, pretraga je prekinuta.") poruka.exec_() return def spoji_datoteke(self): if len(self.multi_selekt) < 2: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nije vise datoteka selektovano za spajanje!") poruka.exec_() return lista = [] self.multi_selekt.sort() brojac = 0 while brojac < len(self.multi_selekt): nadjen = False for j in range(len(lista)): if self.multi_selekt[brojac].row() == lista[j]: nadjen = True break if nadjen: self.multi_selekt.pop(brojac) brojac -= 1 lista.append(self.multi_selekt[brojac].row()) brojac += 1 text, ok = QtWidgets.QInputDialog.getText(None, "Spajanje datoteka", "Unesite ime nove datoteke:", QtWidgets.QLineEdit.Normal, "") ime_nove_datoteke = "podaci/podaci/" if ok: ime_nove_datoteke += str(text) + ".csv" else: return for i in range(0, len(self.multi_selekt)-1, 2): spoji_dve_sekvencijalne_datoteke( self.dock.model.filePath(self.multi_selekt[i]), self.dock.model.filePath(self.multi_selekt[i+1]), self.central_widget.currentWidget().meta_podaci[11].split(","), self.central_widget.currentWidget().meta_podaci[5].split(","), True, ime_nove_datoteke, self) self.multi_selekt = [] def pritisnuto_dugme(self, key): if key == Key.ctrl_l: self.dock.tree.setSelectionMode(QAbstractItemView.MultiSelection) def pusteno_dugme(self, key): if key == Key.ctrl_l: self.dock.tree.setSelectionMode(QAbstractItemView.SingleSelection) self.multi_selekt = self.dock.tree.selectedIndexes() def otvori_tabelu_levi_rodjak(self):... def otvori_tabelu_desni_rodjak(self):... def ukloni_iz_tabele(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return elif not hasattr(self.central_widget.currentWidget().table, "selected_elem"): poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje") poruka.setText("Trenutno nijedan element nije selektovan!") poruka.exec_() return ime_datoteke = self.central_widget.currentWidget().meta_podaci[0] tip_datoteke = self.central_widget.currentWidget().meta_podaci[1] model = self.central_widget.currentWidget().table.model() element_selected = model.get_element(self.central_widget.currentWidget().table.selected_elem) putanja = self.central_widget.currentWidget().meta_podaci[4] lista_kljuceva = self.central_widget.currentWidget().meta_podaci[11].split(",") lista_atributa = self.central_widget.currentWidget().meta_podaci[5].split(",") lista_tip_atributa = self.central_widget.currentWidget().meta_podaci[6].split(",") veze = [] veze = self.central_widget.currentWidget().meta_podaci[9].split(",") #DELETE FROM plan_studijske_grupe WHERE STU_VU_OZNAKA='IR' AND SP_OZNAKA='IT' AND SPB_BLOK=2 AND SPB_POZICIJA=2; if tip_datoteke == "sql": query= " DELETE FROM " + ime_datoteke + " WHERE " brojac = 0 for i in range(len(lista_kljuceva)): if brojac == 0: query+= lista_kljuceva[i] + "=" else: query += " AND " + lista_kljuceva[i] + "=" if lista_tip_atributa[i] == "str": query += "'" + element_selected.__getattribute__(lista_atributa[i]) +"'" else: query += element_selected.__getattribute__(lista_atributa[i]) brojac +=1 query += ";" try: self.csor.execute(query) except mysql.connector.errors.IntegrityError as e: poruka = QtWidgets.QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Ne mozete izbrisati ovaj element!\n"+e.msg) poruka.exec_() return self.connection.commit() query = "SELECT * FROM " + ime_datoteke self.csor.execute(query) self.central_widget.currentWidget().table.model().lista_prikaz = [] for result in self.csor.fetchall(): lista_podataka = [] for i in result: lista_podataka.append(str(i)) self.central_widget.currentWidget().table.model().lista_prikaz.append(GenerickaKlasa(lista_atributa, lista_podataka)) top = QModelIndex() top.child(0,0) self.central_widget.currentWidget().table.model().beginRemoveRows(top, 0, 0) for i in range(len(veze)): #provjaravamo da li ima djecu, ako ima ne smije se obrisati if hasattr(self.central_widget.currentWidget(), "sub_table"+str(i+1)): if len(self.central_widget.currentWidget().__getattribute__("sub_table"+str(i+1)).model.lista_prikaz) != 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Selektovani element ne sme da se obrise zato sto se njegovi podaci koriste u podtabelama, njegovoj deci!") poruka.exec_() return self.central_widget.currentWidget().table.model().lista_prikaz = [] if tip_datoteke != "sql": with open(putanja, 'r',newline='') as csvfile: spamreader = csv.reader(csvfile, delimiter = "\n") counter = 0 prva_linija = True izbrisan = False for row in spamreader: if prva_linija: prva_linija = False continue if len(row) == 0: break objekat = GenerickaKlasa(lista_atributa, row[0].split(",")) nadjen = True for i in range(len(lista_kljuceva)): if objekat.__getattribute__(lista_kljuceva[i]) != element_selected.__getattribute__(lista_kljuceva[i]): nadjen = False if not izbrisan and nadjen: izbrisan = True self.central_widget.currentWidget().table.model().removeRow(counter) #uklanjamo red iz tabele else: self.central_widget.currentWidget().table.model().lista_prikaz.append(objekat) counter += 1 with open(putanja, 'w', newline='') as f: writer = csv.writer(f, delimiter = ",") writer.writerow([self.central_widget.currentWidget().putanja_meta]) for i in range(len(self.central_widget.currentWidget().table.model().lista_prikaz)): tekst = "" for j in range(len(lista_atributa)): tekst += str(self.central_widget.currentWidget().table.model().lista_prikaz[i].__getattribute__(lista_atributa[j])) if j < len(lista_atributa)-1: tekst += "," novi_red = tekst.split(",") writer.writerow(novi_red) else: query = "SELECT * FROM " + ime_datoteke self.csor.execute(query) for result in self.csor.fetchall(): lista_podataka = [] for i in result: lista_podataka.append(str(i)) self.central_widget.currentWidget().table.model().lista_prikaz.append(GenerickaKlasa(lista_atributa, lista_podataka)) self.central_widget.currentWidget().table.model().endRemoveRows() def otvori_tabelu_roditelj(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return elif not hasattr(self.central_widget.currentWidget().table, "selected_elem"): poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedan element nije selektovan!") poruka.exec_() return model = self.central_widget.currentWidget().table.model() element_selected = model.get_element(self.central_widget.currentWidget().table.selected_elem) veze = [] veze = self.central_widget.currentWidget().meta_podaci[9].split(",") meta_podaci = self.central_widget.currentWidget().meta_podaci lista_kljuceva = [] brojac = len(veze)-1 lista_roditelja = [] for i in range(len(veze)): if veze[brojac].find("parent_") == -1: veze.pop(brojac) brojac -= 1 else: lista_roditelja.append(veze[brojac]) brojac -= 1 index = -1 if len(lista_roditelja) == 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Selektovani element nema roditelja!") poruka.exec_() return elif len(lista_roditelja) > 1: list_tuple = () for i in range(len(lista_roditelja)): del1 = lista_roditelja[i].find("_")+1 del2 = lista_roditelja[i].find("(") ime = lista_roditelja[i][del1:del2] list_tuple = list_tuple + (ime,) input = QtWidgets.QInputDialog.getItem( self, "Izbor", "Trenutna tabela ima vise od 1 roditelja\nIzaberite roditelja:", list_tuple, 0, editable=False) if input[1]: for i in range(len(lista_roditelja)): if lista_roditelja[i].find(input[0]) != -1: index = i break else: return elif len(lista_roditelja) == 1: index = 0 if index == -1: return del1 = lista_roditelja[index].find("_")+1 lista_roditelja[index] = lista_roditelja[index][del1:len(lista_roditelja[index])] del1 = lista_roditelja[index].find("(") ime_roditelja = lista_roditelja[index][0:del1] nova_putanja = ime_roditelja[0].lower() for s in range(1, len(ime_roditelja)): if ime_roditelja[s].isupper(): nova_putanja += "_" + ime_roditelja[s].lower() else: nova_putanja += ime_roditelja[s] nova_putanja = meta_podaci[2] + "\\" + nova_putanja if meta_podaci[1] == "serijska": nova_putanja += "_ser." elif meta_podaci[1] == "sekvencijalna": nova_putanja += "_sek." elif meta_podaci[1] == "sql": nova_putanja += "_meta_podaci_sql." nova_putanja += meta_podaci[3] del1 = lista_roditelja[index].find("(") + 1 del2 = lista_roditelja[index].find(")") lista_kljuceva.append(lista_roditelja[index][del1:del2].split("#")) if self.central_widget.currentWidget().is_baza: tab = Tab(parent=self.central_widget) tab.pocetna_strana = self tab.naziv = ime_roditelja indeks = 0 for i in range(len(self.imena_tabela)): if self.imena_tabela[i] == ime_roditelja: indeks = i break for i in range(len(self.lista_baza)): if self.lista_baza[i] == self.central_widget.currentWidget().indeks: self.lista_baza.pop(i) break tab.indeks = indeks tab.read(nova_putanja) else: tab = Tab(nova_putanja, self.central_widget) tab.pocetna_strana = self tab.read() indeks_roditelja = -1 for j in range(len(tab.table.model().lista_prikaz)): pronadjen = True for m in range(len(lista_kljuceva[len(lista_kljuceva)-1])): kljucevi = lista_kljuceva[len(lista_kljuceva)-1][m].split("=") if len(kljucevi) == 1: if element_selected.__getattribute__(kljucevi[0]) != tab.table.model().lista_prikaz[j].__getattribute__(kljucevi[0]): pronadjen = False elif len(kljucevi) == 2: if element_selected.__getattribute__(kljucevi[0]) != tab.table.model().lista_prikaz[j].__getattribute__(kljucevi[1]): pronadjen = False else: print("pocetna_strana.py, 124 linija, eror u len(klucevi):", len(kljucevi), "// ", kljucevi) if pronadjen: indeks_roditelja = j break if indeks_roditelja == -1: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Selektovani element nema roditelja sa istim kljucem kao kod selektovanog!") poruka.exec_() return tab.table.selectRow(indeks_roditelja) top = tab.table.currentIndex() tab.element_selected(top) # tab.table.setModel(tab.table.model()) tab.btn_down.clicked.connect(self.otvori_tabelu_dete) tab.btn_up.clicked.connect(self.otvori_tabelu_roditelj) # tab.btn_left.clicked.connect(self.otvori_tabelu_levi_rodjak) # tab.btn_right.clicked.connect(self.otvori_tabelu_desni_rodjak) self.central_widget.removeTab(self.central_widget.currentIndex()) self.central_widget.addTab(tab, ime_roditelja) meta = "" for s in range(len(self.central_widget.currentWidget().meta_podaci[0])): if self.central_widget.currentWidget().meta_podaci[0][s].isupper(): meta += "_" + self.central_widget.currentWidget().meta_podaci[0][s].lower() else: meta += self.central_widget.currentWidget().meta_podaci[0][s] meta = meta[1:len(meta)] meta = self.central_widget.currentWidget().meta_podaci[2] + "\\" + meta if self.central_widget.currentWidget().meta_podaci[1] == "serijska": meta += "_ser." elif self.central_widget.currentWidget().meta_podaci[1] == "sekvencijalna": meta += "_sek." elif self.central_widget.currentWidget().meta_podaci[1] == "sql": meta += "_meta_podaci_sql." meta += self.central_widget.currentWidget().meta_podaci[3] self.lista_putanja.append(meta) self.lista_putanja.remove(self.lista_putanja[self.central_widget.currentIndex()]) def otvori_tabelu_dete(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return elif not hasattr(self.central_widget.currentWidget().table, "selected_elem"): poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedan element nije selektovan!") poruka.exec_() return elif self.central_widget.currentWidget().tab_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Selektovani element nema podtabele!") poruka.exec_() return elif len(self.central_widget.currentWidget().tab_widget.currentWidget().model.lista_prikaz) == 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Selektovani element nema decu u selektovanoj podtabeli!") poruka.exec_() return child = self.central_widget.currentWidget().tab_widget.currentWidget() if self.central_widget.currentWidget().is_baza: tab = Tab(parent=self.central_widget) tab.pocetna_strana = self tab.naziv = child.naziv indeks = 0 for i in range(len(self.imena_tabela)): if self.imena_tabela[i] == child.naziv: indeks = i break for i in range(len(self.lista_baza)): if self.lista_baza[i] == self.central_widget.currentWidget().indeks: self.lista_baza.pop(i) break tab.indeks = indeks # self.lista_baza.append(indeks) tab.read(child.putanja) else: tab = Tab(child.putanja, self.central_widget) tab.pocetna_strana = self tab.read() tab.table.model().lista_prikaz = child.model.lista_prikaz tab.btn_down.clicked.connect(self.otvori_tabelu_dete) tab.btn_up.clicked.connect(self.otvori_tabelu_roditelj) self.central_widget.removeTab(self.central_widget.currentIndex()) self.central_widget.addTab(tab, child.meta_podaci[0]) meta = "" for s in range(len(child.meta_podaci[0])): if child.meta_podaci[0][s].isupper(): meta += "_" + child.meta_podaci[0][s].lower() else: meta += child.meta_podaci[0][s] meta = meta[1:len(meta)] meta = child.meta_podaci[2] + "\\" + meta if child.meta_podaci[1] == "serijska": meta += "_ser." elif child.meta_podaci[1] == "sekvencijalna": meta += "_sek." elif child.meta_podaci[1] == "sql": meta += "_meta_podaci_sql." meta += child.meta_podaci[3] self.lista_putanja.append(meta) self.lista_putanja.remove(self.lista_putanja[self.central_widget.currentIndex()]) def izmena_u_datoteci(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return elif not hasattr(self.central_widget.currentWidget().table, "selected_elem"): poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedan element nije selektovan!") poruka.exec_() return model = self.central_widget.currentWidget().table.model() selektovani_element = model.get_element(self.central_widget.currentWidget().table.selected_elem) prikaz = PrikazElementa(self.central_widget.currentWidget(), False, selektovani_element) prikaz.exec_() self.central_widget.currentWidget().column_resize() def dodavanje_u_datoteku(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return prikaz = PrikazElementa(self.central_widget.currentWidget()) prikaz.exec_() self.central_widget.currentWidget().column_resize() def otvori_pretragu(self): if self.central_widget.currentWidget() == None: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Trenutno nijedna datoteka nije otvorena!") poruka.exec_() return prikaz = PrikazElementa(self.central_widget.currentWidget(),True) prikaz.exec_() if len(prikaz.lista_atr) != 0 and len(prikaz.lista_kriterijuma) != 0: model = self.central_widget.currentWidget().table.model() model = pretraga( prikaz.lista_atr, prikaz.lista_kriterijuma, prikaz.lista_vece_manje, self.central_widget.currentWidget().meta_podaci, False, self.central_widget.currentWidget()) if len(model.lista_prikaz) == 0: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Zadata pretraga nije pronasla vrednosti koje odgovaraju zadatim kriterijumima.") poruka.exec_() return self.central_widget.currentWidget().table.setModel(model) self.central_widget.currentWidget().table.selectRow(0) else: poruka = QMessageBox() icon = QtGui.QIcon("src/ikonice/logo.jpg") poruka.setWindowIcon(icon) poruka.setWindowTitle("Upozorenje!") poruka.setText("Niste zadali ni jedan kriterijum za pretragu, pretraga je prekinuta.") poruka.exec_() return self.central_widget.currentWidget().column_resize() def delete_tab(self, index): self.central_widget.setCurrentIndex(index) tab = self.central_widget.currentWidget() if tab.is_baza: for i in range(len(self.lista_baza)): if self.lista_baza[i] == tab.indeks: self.lista_baza.pop(i) break self.central_widget.removeTab(index) return if hasattr(tab, "sortirano") and len(tab.table.model().lista_prikaz) > 1: if tab.meta_podaci[1] == "serijska": while True: izabrano = -1 list_tuple = () lista = ["Samo stare podatke", "Samo nove podatke", "Ili i stare i nove podatke"] for i in range(len(lista)): list_tuple = list_tuple + (lista[i],) input = QtWidgets.QInputDialog.getItem( tab, "Izbor", "Posto ste sortirali tabelu\nIzaberite da li zelite da sacuvate:", list_tuple, 0, editable=False) if input[1]: for i in range(len(lista)): if lista[i].find(input[0]) != -1: izabrano = i break break putanja = tab.meta_podaci[4] if izabrano == 2: i = 0 while True: del1 = tab.meta_podaci[4].rfind(".") deo = tab.meta_podaci[4][0:del1] nastavak = tab.meta_podaci[4][del1:len(tab.meta_podaci[4])] if not os.path.exists(deo + "_new"+str(i+1) + nastavak): putanja = deo + "_new"+str(i+1) + nastavak break i += 1 if izabrano != 0: with open(putanja, 'w', newline='') as f: writer = csv.writer(f, delimiter = ",") writer.writerow([tab.putanja_meta]) for i in range(len(tab.table.model().lista_prikaz)): tekst = "" for j in range(len(tab.table.model().nazivi_atributa)): tekst += str(tab.table.model().lista_prikaz[i].__getattribute__(tab.table.model().nazivi_atributa[j])) if j < len(tab.table.model().nazivi_atributa)-1: tekst += "," novi_red = tekst.split(",") writer.writerow(novi_red) self.central_widget.removeTab(index) self.lista_putanja.remove(self.lista_putanja[index]) def read(self, index): putanja = self.dock.model.filePath(index) if os.path.isdir(putanja): return ista_putanja = False for i in range(len(self.lista_putanja)): if putanja == self.lista_putanja[i]: ista_putanja = True return if not ista_putanja: self.lista_putanja.append(putanja) if putanja.find(".sql") != -1: self.connection = mysql.connector.connect(user="******", password="******", host="127.0.0.1", database="projekat") self.csor = self.connection.cursor() putanja = "podaci\metaPodaci\projekat_meta_podaci.csv" meta_podaci = citanje_meta_podataka(putanja, True) self.imena_tabela = meta_podaci[4].split(",") self.treeView = QTreeView() self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.customContextMenuRequested.connect(self.dugme_baza) model = QStandardItemModel(parent=self.dock.tree.sub_layout) item = QStandardItem("zatvori") item.setEditable(False) model.appendRow(item) for text in self.imena_tabela: item = QStandardItem(text) item.setEditable(False) model.appendRow(item) self.treeView.setModel(model) self.treeView.clicked.connect(self.dugme_baza) self.treeView.PositionAtBottom si = self.dock.tree.sub_layout.sizeHint() si.setWidth(self.dock.width()) si.setHeight(200) self.treeView.setFixedSize(si.width(), si.height()) self.treeView.setHeaderHidden(True) self.dock.tree.sub_layout.addWidget(self.treeView) self.dock.tree.sub_layout.setAlignment(self.treeView, QtCore.Qt.AlignBottom) return tab = Tab(putanja, parent=self.central_widget) tab.pocetna_strana = self if putanja != "": tab.read() else: tab.read(putanja) tab.btn_down.clicked.connect(self.otvori_tabelu_dete) tab.btn_up.clicked.connect(self.otvori_tabelu_roditelj) tab.naziv = tab.meta_podaci[0] self.central_widget.addTab(tab, tab.naziv) self.central_widget.setCurrentIndex(self.central_widget.currentIndex()+1) def dugme_baza(self, model_indeks): indeks = model_indeks.row() if indeks == 0: self.treeView.close() for i in range(len(self.lista_putanja)): if self.lista_putanja[i].find(".sql") != 1: self.lista_putanja.pop(i) break self.central_widget.setCurrentIndex(indeks) brojac = 0 while len(self.lista_baza) != 0: tab = self.central_widget.currentWidget() if tab.is_baza: for i in range(brojac, len(self.lista_baza)): if self.lista_baza[brojac] == tab.indeks: self.lista_baza.pop(brojac) self.central_widget.removeTab(indeks) break else: brojac += 1 else: indeks += 1 self.central_widget.setCurrentIndex(indeks) self.csor.close() self.connection.close() return else: indeks -= 1 for i in range(len(self.lista_baza)): if self.lista_baza[i] == indeks: return self.lista_baza.append(indeks) tab = Tab(parent=self.central_widget) tab.pocetna_strana = self tab.indeks = indeks tab.naziv = self.imena_tabela[indeks] nova_putanja = "podaci\\metaPodaci\\" nova_putanja += self.imena_tabela[indeks][0].lower() for s in range(1, len(self.imena_tabela[indeks])): if self.imena_tabela[indeks][s].isupper(): nova_putanja += "_" + self.imena_tabela[indeks][s].lower() else: nova_putanja += self.imena_tabela[indeks][s] nova_putanja += "_meta_podaci_sql.csv" tab.read(nova_putanja) tab.btn_down.clicked.connect(self.otvori_tabelu_dete) tab.btn_up.clicked.connect(self.otvori_tabelu_roditelj) self.central_widget.addTab(tab, tab.naziv) self.central_widget.setCurrentIndex(self.central_widget.currentIndex()+1)
class ClassTreeWidget(QDialog): """ TreeView widget to show pyleecan classes structured by their inheritance together with the selected class description. """ def __init__(self, keys=None, expand=True): super(ClassTreeWidget, self).__init__() self.setupUi() self.expandAll = expand self.setMinimumHeight(600) # === default variables === self.classDict = ClassInfo().get_dict() self.keys = keys or ClassInfo().get_base_classes() # TODO all classes self.selectionModel = self.treeView.selectionModel() # === Signals === self.selectionModel.selectionChanged.connect(self.onSelectionChanged) self.treeView.doubleClicked.connect(self.onClassSelected) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) # === Generate content === self.generate() def onClassSelected(self, index): """Method to accept the selection if a class was double clicked.""" if index.isValid(): self.accept() def onSelectionChanged(self, itSelection): """ """ index = itSelection.indexes()[0] desc = index.model().itemFromIndex(index).data() self.text.setText(desc) def getSelectedClass(self): """Get the currently selected class by its name.""" index = self.selectionModel.selectedIndexes()[0] return index.model().itemFromIndex(index).text() def setupUi(self): """Init. the UI.""" self.setWindowIcon(QIcon(ICON)) # === Widgets === # TreeView model = QtGui.QStandardItemModel(0, 1) model.setHorizontalHeaderLabels(["Class"]) self.treeView = QTreeView() self.treeView.rootNode = model.invisibleRootItem() self.treeView.setModel(model) self.treeView.setAlternatingRowColors(False) # size options # setting min. width in self.generate to fit content self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) # Hide Debug Columns # self.treeView.hideColumn(1) # text output self.text = QLabel() self.text.setAlignment(Qt.AlignTop) self.text.setWordWrap(True) self.text.setMinimumWidth(300) # Splitters self.splitter = QSplitter(self) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.addWidget(self.treeView) self.splitter.addWidget(self.text) # dialog buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) # window to create confirmation and cancellation buttons # === Layout === # Horizontal Div. layout = QVBoxLayout() # layout.setContentsMargins(0, 0, 0, 0) # layout.setSpacing(0) layout.addWidget(self.splitter) layout.addWidget(self.buttons) self.setLayout(layout) def generate(self): """Method to (recursively) build the tree (view) of the data object.""" self.treeDict = dict() for key in self.keys: self.genTreeDict(key, self.treeDict) self.genTreeView(self.treeDict) # set first row active & expand all branches index = self.treeView.model().index(0, 0) self.treeView.setCurrentIndex(index) self.treeView.expandAll() wHint = self.treeView.sizeHintForColumn(0) self.treeView.setMinimumWidth(wHint) self.treeView.setColumnWidth(0, wHint) if not self.expandAll: self.treeView.collapseAll() def genTreeDict(self, key, parent): """Generate a dict structure of the classes recursively on the parent dict.""" parent[key] = dict() for typ in self.classDict[key]["daughters"]: if key == self.classDict[typ]["mother"]: self.genTreeDict(typ, parent[key]) def genTreeView(self, tree, parent=None): """Generate the view item structure on the parent item.""" # init if root if parent is None: parent = self.treeView.rootNode self.treeView.rootNode.removeRows( 0, self.treeView.rootNode.rowCount()) for key, item in tree.items(): desc = ( f"Class: {key} \nPackage: {self.classDict[key]['package']}" + f"\nDescription: {self.classDict[key]['desc']}") row = self.addRow(parent, key, desc) if item: self.genTreeView(item, parent=row) def addRow(self, parent, name="", desc=""): """Add a new row to the parent item.""" item = QtGui.QStandardItem(name) item.setEditable(False) item.setData(desc) parent.appendRow([item]) return item