class FilenamePrompt(_BasePrompt): """A prompt for a filename.""" def __init__(self, question, parent=None): super().__init__(question, parent) self._init_texts(question) self._init_fileview() self._set_fileview_root(question.default) self._lineedit = LineEdit(self) if question.default: self._lineedit.setText(question.default) self._lineedit.textEdited.connect(self._set_fileview_root) self._vbox.addWidget(self._lineedit) self.setFocusProxy(self._lineedit) self._init_key_label() if config.get('ui', 'prompt-filebrowser'): self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) @pyqtSlot(str) def _set_fileview_root(self, path, *, tabbed=False): """Set the root path for the file display.""" separators = os.sep if os.altsep is not None: separators += os.altsep dirname = os.path.dirname(path) try: if not path: pass elif path in separators and os.path.isdir(path): # Input "/" -> don't strip anything pass elif path[-1] in separators and os.path.isdir(path): # Input like /foo/bar/ -> show /foo/bar/ contents path = path.rstrip(separators) elif os.path.isdir(dirname) and not tabbed: # Input like /foo/ba -> show /foo contents path = dirname else: return except OSError: log.prompt.exception("Failed to get directory information") return root = self._file_model.setRootPath(path) self._file_view.setRootIndex(root) @pyqtSlot(QModelIndex) def _insert_path(self, index, *, clicked=True): """Handle an element selection. Args: index: The QModelIndex of the selected element. clicked: Whether the element was clicked. """ path = os.path.normpath(self._file_model.filePath(index)) if clicked: path += os.sep else: # On Windows, when we have C:\foo and tab over .., we get C:\ path = path.rstrip(os.sep) log.prompt.debug('Inserting path {}'.format(path)) self._lineedit.setText(path) self._lineedit.setFocus() self._set_fileview_root(path, tabbed=True) if clicked: # Avoid having a ..-subtree highlighted self._file_view.setCurrentIndex(QModelIndex()) def _init_fileview(self): self._file_view = QTreeView(self) self._file_model = QFileSystemModel(self) self._file_view.setModel(self._file_model) self._file_view.clicked.connect(self._insert_path) if config.get('ui', 'prompt-filebrowser'): self._vbox.addWidget(self._file_view) else: self._file_view.hide() # Only show name self._file_view.setHeaderHidden(True) for col in range(1, 4): self._file_view.setColumnHidden(col, True) # Nothing selected initially self._file_view.setCurrentIndex(QModelIndex()) # The model needs to be sorted so we get the correct first/last index self._file_model.directoryLoaded.connect( lambda: self._file_model.sort(0)) def accept(self, value=None): text = value if value is not None else self._lineedit.text() text = downloads.transform_path(text) if text is None: message.error("Invalid filename") return False self.question.answer = text return True def item_focus(self, which): # This duplicates some completion code, but I don't see a nicer way... assert which in ['prev', 'next'], which selmodel = self._file_view.selectionModel() parent = self._file_view.rootIndex() first_index = self._file_model.index(0, 0, parent) row = self._file_model.rowCount(parent) - 1 last_index = self._file_model.index(row, 0, parent) if not first_index.isValid(): # No entries return assert last_index.isValid() idx = selmodel.currentIndex() if not idx.isValid(): # No item selected yet idx = last_index if which == 'prev' else first_index elif which == 'prev': idx = self._file_view.indexAbove(idx) else: assert which == 'next', which idx = self._file_view.indexBelow(idx) # wrap around if we arrived at beginning/end if not idx.isValid(): idx = last_index if which == 'prev' else first_index selmodel.setCurrentIndex( idx, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) self._insert_path(idx, clicked=False) def _allowed_commands(self): return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
class App(QWidget): def __init__(self): super().__init__() self.title = 'PyQt5 file system view - pythonspot.com' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.initUI() def tree_cilcked(self, Qmodelidx): print(self.model.filePath(Qmodelidx)) print(self.model.fileName(Qmodelidx)) print(self.model.fileInfo(Qmodelidx)) def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # 这里得到目录结构 self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) # 这里过滤,只显示 py 文件 mf = self.model.setNameFilters(['*.py']) self.model.setNameFilterDisables(False) # 这里做展示 self.tree = QTreeView() self.tree.setModel(self.model) # self.tree.setRootIndex(self.model.index(QDir.currentPath())) self.tree.setRootIndex(self.model.index('g:\l')) self.tree.doubleClicked.connect(self.tree_cilcked) # 这里隐藏了目录信息展示 for i in [1, 2, 3]: self.tree.setColumnHidden(i, True) # 缩进 self.tree.setIndentation(10) self.tree.setWindowTitle("Dir View") self.tree.resize(640, 480) windowLayout = QVBoxLayout() windowLayout.addWidget(self.tree) self.setLayout(windowLayout) self.show()
class Explorer(QWidget): def __init__(self, rootdir=QDir.rootPath()): QWidget.__init__(self) self.treeview = QTreeView() self.listview = QListView() self.path = rootdir self.filename = '' self.filepath = rootdir self.canvas = None self.col_selector = None self.header = '' self.xcol = [1] self.ycol = [1] self.ncols = 0 self.dirModel = QFileSystemModel() self.dirModel.setRootPath(self.path) self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.fileModel = QFileSystemModel() self.fileModel.setRootPath(self.filepath) self.fileModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.fileModel.setNameFilters(['*.txt']) self.fileModel.setNameFilterDisables(0) self.treeview.setModel(self.dirModel) self.listview.setModel(self.fileModel) for i in [1, 2, 3]: self.treeview.setColumnHidden(i, True) self.treeview.setHeaderHidden(True) self.treeview.setRootIndex(self.dirModel.index(self.path)) self.listview.setRootIndex(self.fileModel.index(self.path)) self.treeview.clicked.connect(self.on_clicked) self.listview.selectionModel().currentChanged.connect(self.file_selected) self.listview.selectionModel().currentChanged.connect(lambda: self.canvas.update_plot(self)) self.listview.selectionModel().currentChanged.connect(lambda: self.col_selector.update_range(self.ncols)) def on_clicked(self, index): self.path = self.dirModel.fileInfo(index).absoluteFilePath() self.listview.setRootIndex(self.fileModel.setRootPath(self.path)) def file_selected(self, index): self.filename = self.fileModel.fileName(index) self.filepath = self.fileModel.filePath(index) self.load_file() def load_file(self): try: if self.filepath.endswith('.txt'): with open(self.filepath, 'r') as file: self.header, self.xcol, self.ycol = '', [], [] for ln in file: if ln.startswith('#'): self.header += ln[2:] else: cols = ln.split('\t') self.xcol.append(float(cols[0])) self.ycol.append(float(cols[self.col_selector.sp.value()])) self.ncols = len(cols) self.col_selector.update_range(self.ncols) except: self.header, self.xcol, self.ycol = '', [0], [0] def update_rootdir(self, rootdir): self.path = rootdir self.treeview.setRootIndex(self.dirModel.index(self.path)) self.listview.setRootIndex(self.fileModel.index(self.path))
class OperacaoLogistica(QDialog): #TODO: Acertar formatação na listagem de items por SIMAFIC def __init__(self, parent=None): super().__init__(parent) self.setWindowFlags(Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint) self.setWindowTitle('Operação Logística') self.setMinimumSize(QSize(h_size, v_size)) self.setWindowIcon(QIcon(main_icon)) verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) #Pedido Input Field self.proxy_list_result_id = QSortFilterProxyModel() self.numero_pedido = QLineEdit(self) self.numero_pedido.setPlaceholderText("Insira o Número do Pedido") self.numero_pedido.textChanged.connect( lambda wildcard: self.proxy_list_result_id.setFilterWildcard( wildcard)) #Voltar Btn self.voltar_btn = QPushButton(self) #self.voltar_btn.setStyleSheet('background-color: rgb(0,0,255); color: #fff') self.voltar_btn.setText('Voltar') self.voltar_btn.clicked.connect(self.goMainWindow) self.close() #Adicionar Cores no StyleSheet colors = ['##393318', ' ##fff'] self.pedidos = services.get_all_pedidos() self.item_result = None self.item_escolhido = None self.id_pedido_list = QListView() self.simafics_do_id = QListWidget() #self.simafics_do_id.setHidden(True) self.createPedidoIdList() self.id_pedido_list.clicked.connect( lambda id_pedido: self.createListaSimafics(id_pedido)) self.simafics_do_id.itemDoubleClicked.connect( lambda pedido: self.simaficSelecionado(pedido)) self.pedidos_label = QLabel() self.pedidos_label.setBuddy(self.id_pedido_list) self.simafic_label = QLabel() self.simafic_label.setBuddy(self.simafics_do_id) self.itensTree = PedidoItensTree() self.treeItensTV = QTreeView() self.treeItensTV.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeItensTV.setAlternatingRowColors(True) self.treeItensTV.setRootIsDecorated(True) self.treeItensTV.doubleClicked.connect(self.simaficSelecionado) self.treeItensTV.setColumnHidden(8, True) if len(self.pedidos) <= 0: self.pedidos_label.setText( "É necessário adicionar um pedido na tela de cadastro.") self.pedidos_label.setStyleSheet("QLabel { color: red; }") else: self.pedidos_label.setText("Listagem de Pedidos:") self.pedidos_label.setStyleSheet("QLabel { color: black; }") self.simafic_label.setText( "Selecione um pedido para ver a listagem de Itens por SIMAFIC:" ) self.simafic_label.setStyleSheet("QLabel { color: red; }") layout = QGridLayout() layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 4) layout.addWidget(self.numero_pedido, 0, 0) layout.addWidget(self.voltar_btn, 0, 1) layout.addWidget(self.pedidos_label, 1, 0) layout.addWidget(self.simafic_label, 1, 1) layout.addWidget(self.id_pedido_list, 2, 0) layout.addWidget(self.treeItensTV, 2, 1) #layout.addWidget(self.simafics_do_id, 2,1) self.setLayout(layout) def createPedidoIdList(self): print('def createPedidoIdList(self):') onlyids = set() pedidosbyid = [] pedidosCompletos = [] self.proxy_list_result_id = QSortFilterProxyModel() for obj in self.pedidos: if obj.id_pedido not in onlyids: pedidosbyid.append(obj) onlyids.add(obj.id_pedido) self.pedidoId_model = QStringListModel(onlyids, self) self.proxy_list_result_id.setSourceModel(self.pedidoId_model) self.id_pedido_list.setModel(self.proxy_list_result_id) self.id_pedido_list.setAlternatingRowColors(True) self.id_pedido_list.setEditTriggers(QAbstractItemView.NoEditTriggers) def createListaSimafics(self, id_pedido): pedido = id_pedido.data() self.pedidosModel = self.itensTree.createPedidosModel(self.itensTree) self.treeItensTV.setModel(self.pedidosModel) print('def listaSimafics(self, id_pedido): {id_pedido}'.format( id_pedido=pedido)) self.item_result = None self.item_result = [x for x in self.pedidos if x.id_pedido == pedido] self.simafics_do_id.clear() self.pedidosModel.beginResetModel self.pedidosModel.modelReset self.pedidosModel.endResetModel for idx, item in enumerate(self.item_result): print(item) self.itensTree.addItens( self.pedidosModel, item.cod_simafic, item.desc, item.qty_scanneada, item.qty_total, item.nome_responsavel, item.id_caixa, item.time_updated.strftime("%d/%m/%y %H:%M:%S"), item.id_pedido, item) self.simafic_label.setText( "Listagem de Itens do pedido {} por SIMAFIC:".format(pedido)) self.simafic_label.setStyleSheet("QLabel { color: black; }") #self.simafics_do_id.setHidden(False) def simaficSelecionado(self, item): print(item.column(), item.row()) simafic_escolhido = self.treeItensTV.model().index(item.row(), 0).data() id_pedido = self.treeItensTV.model().index(item.row(), 7).data() self.item_escolhido = [ x for x in self.item_result if x.cod_simafic == simafic_escolhido and x.id_pedido == id_pedido ] self.cams = ItemScanner(self.item_escolhido[0]) self.cams.show() self.close() def goMainWindow(self): self.cams = mainView self.cams.show() self.close() def goScan(self): self.cams = ItemScanner("Eu sou o Pedido", "Eu sou o Simafic", "Eu sou a Descrição", "300") self.cams.show() self.close()
class Navigation(QWidget): """ Navigation class definition. Provide a combobox to switch on each opened directories and display it into a tree view Provide 2 useful function (to use in alter module): - add_action(name, shortcut, callback) - callback take 2 arguments : file_info and parent - add_separator() """ SETTINGS_DIRECTORIES = 'navigation_dirs' SETTINGS_CURRENT_DIR = 'navigation_current_dir' onFileItemActivated = pyqtSignal(QFileInfo, name="onFileItemActivated") onDirItemActivated = pyqtSignal(QFileInfo, name="onDirItemActivated") def __init__(self, parent=None): super(Navigation, self).__init__(parent) self.setObjectName("Navigation") self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0,0,0,0) self.menu_button = QPushButton('Select directory', self) self.menu_button.setFlat(True) # self.menu_button.clicked.connect(self.on_menu_button_clicked) self.menu = QMenu(self) self.menu_button.setMenu(self.menu) self.menu_directories = QMenu(self) self.menu_directories.setTitle('Directories') self.menu_add_action( 'Open directory', self.open_directory, None, QKeySequence.Open) self.menu_add_separator() self.menu_add_action('Refresh', self.reset, None, QKeySequence.Refresh) # @TODO invoke_all self.menu_add_separator() self.menu.addMenu(self.menu_directories) self.tree = QTreeView(self) self.model = FileSystemModel(self) self.tree.setModel(self.model) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.tree.setHeaderHidden(True) # only to expand directory or activated with one click self.tree.clicked.connect(self.on_item_clicked) # else, for file use activated signal self.tree.activated.connect(self.on_item_activated) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self.on_context_menu) self.widgets = collections.OrderedDict() self.widgets['menu_button'] = self.menu_button self.widgets['tree'] = self.tree # @ToDo: Alter.invoke_all('add_widget', self.widgets) for name, widget in self.widgets.items(): if name == 'menu_button': self.layout.addWidget(widget, 0, Qt.AlignLeft) else: self.layout.addWidget(widget) self.context_menu = QMenu(self) self.add_action('New file', QKeySequence.New, FileSystemHelper.new_file) self.add_action('New Directory', '', FileSystemHelper.new_directory) self.add_separator() self.add_action('Rename', '', FileSystemHelper.rename) self.add_action('Copy', QKeySequence.Copy, FileSystemHelper.copy) self.add_action('Cut', QKeySequence.Cut, FileSystemHelper.cut) self.add_action('Paste', QKeySequence.Paste, FileSystemHelper.paste) self.add_separator() self.add_action('Delete', QKeySequence.Delete, FileSystemHelper.delete) # @ToDo Alter.invoke_all('navigation_add_action', self) #restore previous session and data dirs = ModuleManager.core['settings'].Settings.value( self.SETTINGS_DIRECTORIES, None, True) for directory_path in dirs: name = os.path.basename(directory_path) self.menu_add_directory(name, directory_path) current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() self.menu_button.setFocusPolicy(Qt.NoFocus) self.menu_button.setFocusProxy(self.tree) def reset(self, file_info): self.model.beginResetModel() current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() def on_menu_button_clicked(self): pos = self.mapToGlobal(self.menu_button.pos()) menu_width = self.menu.sizeHint().width() pos.setY(pos.y() + self.menu_button.height()) # pos.setX(pos.x() + self.menu_button.width() - menu_width) if len(self.menu.actions()) > 0: self.menu.exec(pos) def menu_add_action(self, name, callback, data=None, shortcut=None, icon=None): action = QAction(name, self) if icon: action.setIcon(icon) if shortcut: action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) if data: action.setData(data) action.triggered.connect(callback) self.addAction(action) self.menu.addAction(action) def menu_add_directory(self, name, data): action = QAction(name, self) action.setData(data) action.triggered.connect(self.on_menu_action_triggered) self.menu_directories.addAction(action) return action def menu_add_separator(self): self.menu.addSeparator() def add_action(self, name, shortcut, callback, icon = None): """ Ajoute une action au context menu et au widget navigation lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(name, self) if icon: action.setIcon(icon) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.context_menu.addAction(action) def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.context_menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ action = self.sender() file_info = action.data() if not file_info: indexes = self.tree.selectedIndexes() if indexes: model_index = indexes[0] file_info = self.model.fileInfo(model_index) callback(file_info, self) elif action.shortcut() == QKeySequence.New: file_info = self.model.fileInfo(self.tree.rootIndex()) callback(file_info, self) else: callback(file_info, self) action.setData(None) return __new_function def question(self, text, informative_text = None): message_box = QMessageBox(self) message_box.setText(text) if informative_text: message_box.setInformativeText(informative_text) message_box.setStandardButtons( QMessageBox.No | QMessageBox.Yes) message_box.setDefaultButton(QMessageBox.No) return message_box.exec() def on_context_menu(self, point): model_index = self.tree.indexAt(point) file_info = self.model.fileInfo(model_index) # pour chaque action on met a jour les data (file_info) # puis on altère les actions (ex enabled) for action in self.context_menu.actions(): if not action.isSeparator(): action.setData(file_info) action.setEnabled(model_index.isValid()) if action.shortcut() == QKeySequence.New: action.setEnabled(True) if not model_index.isValid(): file_info = self.model.fileInfo(self.tree.rootIndex()) action.setData(file_info) if action.shortcut() == QKeySequence.Paste: enable = FileSystemHelper.ready() and model_index.isValid() action.setEnabled(enable) if action.shortcut() == QKeySequence.Delete: # remove directory only if is an empty directory if model_index.isValid() and file_info.isDir(): path = file_info.absoluteFilePath() # QDir(path).count() always contains '.' and '..' action.setEnabled(QDir(path).count() == 2) # @ToDo #Alter.invoke_all( # 'navigation_on_menu_action', # model_index, file_info, action, self) if len(self.context_menu.actions()) > 0: self.context_menu.exec(self.tree.mapToGlobal(point)) # reset action data, sinon y a des problèmes dans _new_function for action in self.context_menu.actions(): action.setData(None) def on_item_activated(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) else: self.onFileItemActivated.emit(qFileInfo) def on_item_clicked(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) self.tree.setExpanded(index, not self.tree.isExpanded(index)) else: self.onFileItemActivated.emit(qFileInfo) def open_directory(self): project = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') path = QFileDialog.getExistingDirectory(self, "Open Directory", project) if path: name = os.path.basename(path) action = self.menu_add_directory(name, path) self.save_directories_path() action.trigger() def on_menu_action_triggered(self): action = self.sender() path = action.data() if path: self.model.setRootPath(path) self.tree.setRootIndex(self.model.index(path)) self.menu_button.setText(os.path.basename(path)) self.save_current_dir(path) def save_directories_path(self): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_DIRECTORIES, [action.data() for action in self.menu_directories.actions()] ) def save_current_dir(self, path): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_CURRENT_DIR, path )
class Watch(QWidget): def __init__(self, parent=None): super(QWidget, self).__init__(parent) self.initUI() self.initVariables() def initUI(self): mainlayout = QFormLayout() self.model = CheckableDirModel() #self.model = QFileSystemModel() self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setAnimated(False) self.tree.setIndentation(20) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.tree.setSortingEnabled(False) self.tree.setHeaderHidden(True) self.model.updateCheckBoxSignal.connect(self.updateCheckBoxes) buttonLayout = QHBoxLayout() self.applyButton = QPushButton("Apply", self) self.applyButton.clicked.connect(self.apply) self.applyButton.setEnabled(False) self.resetButton = QPushButton("Reset", self) hspacer = QWidget() hspacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) buttonLayout.addWidget(hspacer) buttonLayout.addWidget(self.applyButton) buttonLayout.addWidget(self.resetButton) vspacer = QWidget() vspacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Add to layout mainlayout.addRow(self.tree) mainlayout.addRow(vspacer) mainlayout.addRow(buttonLayout) self.setLayout(mainlayout) def initVariables(self): settings = readSettingItems(['Watched']) if 'Watched' in settings.keys(): if len(settings['Watched']): self.watchList = settings['Watched'] if len(self.watchList): for watchItem in self.watchList: tempPath = watchItem[0] tempIndex = self.model.index(tempPath, 0) retData = self.model.filePath(tempIndex) # Set checkbox if len(retData): self.model.setData(tempIndex, watchItem[1], Qt.CheckStateRole) # Expand path while tempIndex.parent().isValid(): tempIndex = tempIndex.parent() self.tree.expand(tempIndex) else: self.watchList = [] def updateCheckBoxes(self, index, value): changeFlag = False fullpath = self.model.filePath(index) newWatchMission = [fullpath, value] if newWatchMission in self.watchList: pass else: if len(self.watchList): tempList = list(filter(lambda x: fullpath in x, self.watchList)) if len(tempList) == 1: tempMissionIndex = self.watchList.index(tempList[0]) if value == 0: self.watchList.pop(tempMissionIndex) else: self.watchList[tempMissionIndex] = newWatchMission elif len(tempList) == 0: if value != 0: self.watchList.append(newWatchMission) changeFlag = True self.applyButton.setEnabled(changeFlag) # to do: update checkboxes states: 0, 1, 2. def apply(self): data = {'Watched': self.watchList } writeSettingItems(data) self.applyButton.setEnabled(False)
class mainWindow(QMainWindow):# || def __init__(self):# || QMainWindow.__init__(self)# || pxcfg = here+'/gui.yaml' self.config = monk.stone(pxcfg). self.setAttribute(Qt.WA_DeleteOnClose)# || self.setWindowTitle("Pyffice 0.0.0.0.0.0")# || self.setStyleSheet(open(qss, "r").read())# || self.setAutoFillBackground(True)# || self.loadMenu()# || self.setLayout()# || self.loadApp()# || def buildMenu(): pass def desktopMenu(self, application, cfg=None): #dynamically build menu from config file dtmcfg = self.config['menu'] for item in cfg.keys(): self.menu = QMenu(dtmcfg[item]['name'], application) def loadMenu(self):# || menu = self.desktopMenu(self)# this sends the desktop object (self) to the menu object for mu in menu.__dir__():# ||dynamically add obj = getattr(menu, mu)# ||menu items to the if isinstance(obj, QMenu):# ||layout self.menuBar().addMenu(obj)# || def setLayout(self):# || self.main_widget = QWidget(self) self.l = QHBoxLayout(self.main_widget) # tbar = docAddBar() # l.addWidget(tbar.toolbar) def loadApp(self):# || '' app = alpr.App() self.formulaBar() self.createLayout() self.l.addWidget(app) self.main_widget.setFocus() self.setCentralWidget(self.main_widget) windowLayout = QBoxLayout(QBoxLayout.LeftToRight) self.treeview.setFixedWidth=200 windowLayout.addWidget(self.treeview) windowLayout.addWidget(self.tabwidget) self.setLayout(windowLayout) self.show() return self self.functionBar = QToolBar() self.addToolBar(self.functionBar) self.functionInput = QLineEdit() self.functionBar.addWidget(self.functionInput) self.formulaBar = QToolBar() self.addToolBar(self.formulaBar) self.formulaInput = QLineEdit() self.formulaBar.addWidget(self.formulaInput) self.statusBar().showMessage('Pyffice is about to Live') def fileQuit(self): self.close() def closeEvent(self, ce): self.fileQuit() def treeView(self,): self.treeview = QTreeView() self.treeview.setModel(model) self.treeview.setRootIndex(model.index(QDir.homePath())) self.treeview.setColumnWidth(0,50) self.treeview.setColumnHidden(1, True) self.treeview.setColumnHidden(2, True) self.treeview.setColumnHidden(3, True) self.treeview.setFixedWidth(200) self.treeview.setAnimated(False) self.treeview.setIndentation(20) self.treeview.setSortingEnabled(True) return self def setupContextMenu(self): 'I believe this should setup the right click menu' self.addAction(self.cell_addAction) self.addAction(self.cell_subAction) self.addAction(self.cell_mulAction) self.addAction(self.cell_divAction) self.addAction(self.cell_sumAction) self.addAction(self.firstSeparator) self.addAction(self.colorAction) self.addAction(self.fontAction) self.addAction(self.secondSeparator) self.addAction(self.clearAction) self.setContextMenuPolicy(Qt.ActionsContextMenu) return self def formulaBar(self): return self def functionBar(self): return self
class YuToolsNoteViewer(QWidget): def __init__(self): super(YuToolsNoteViewer, self).__init__() self.tv_notes = QTreeView(self) self.tv_notes.setGeometry(10, 40, 311, 630) self.tv_notes.setExpandsOnDoubleClick(False) self.tv_notes.clicked.connect(self.click_tv_item) self.tv_notes.doubleClicked.connect(self.doubleclick_tv_item) self.te_note = QTextEdit(self) font_default = QFont() font_default.setPointSize(12) self.te_note.setFont(font_default) self.te_note.setGeometry(330, 40, 451, 630) self.btn_add_root = QPushButton(self) self.btn_add_root.setText('Add Root') self.btn_add_root.setGeometry(10, 10, 75, 23) self.btn_add_root.clicked.connect(self.btn_click) self.btn_add_sub = QPushButton(self) self.btn_add_sub.setText('Add Sub') self.btn_add_sub.setDisabled(True) self.btn_add_sub.setGeometry(100, 10, 75, 23) self.btn_add_sub.clicked.connect(self.btn_click) self.btn_add_note = QPushButton(self) self.btn_add_note.setText('Add Note') self.btn_add_note.setDisabled(True) self.btn_add_note.setGeometry(190, 10, 75, 23) self.btn_add_note.clicked.connect(self.btn_click) self.rb_fonts_small = QRadioButton(self) self.rb_fonts_small.setText('Small') self.rb_fonts_small.setGeometry(350, 10, 60, 23) self.rb_fonts_small.clicked.connect(self.change_font_size) self.rb_fonts_normal = QRadioButton(self) self.rb_fonts_normal.setText('Normal') self.rb_fonts_normal.setGeometry(420, 10, 60, 23) self.rb_fonts_normal.clicked.connect(self.change_font_size) self.rb_fonts_normal.setChecked(True) self.rb_fonts_big = QRadioButton(self) self.rb_fonts_big.setText('Big') self.rb_fonts_big.setGeometry(490, 10, 60, 23) self.rb_fonts_big.clicked.connect(self.change_font_size) self.rb_fonts_bigger = QRadioButton(self) self.rb_fonts_bigger.setText('Bigger') self.rb_fonts_bigger.setGeometry(560, 10, 60, 23) self.rb_fonts_bigger.clicked.connect(self.change_font_size) self.rb_fonts_biggest = QRadioButton(self) self.rb_fonts_biggest.setText('Biggest') self.rb_fonts_biggest.setGeometry(630, 10, 60, 23) self.rb_fonts_biggest.clicked.connect(self.change_font_size) self.btn_save_note = QPushButton(self) self.btn_save_note.setText('Save') self.btn_save_note.setDisabled(True) self.btn_save_note.setGeometry(710, 10, 75, 23) self.btn_save_note.clicked.connect(self.btn_click) self.select_path = None self.init_tree() def init_tree(self): model = QFileSystemModel() path = os.path.dirname(os.path.realpath(__file__)) + os.path.sep + 'notes' model.setRootPath(path) self.tv_notes.setModel(model) self.tv_notes.setRootIndex(model.index(path)) self.tv_notes.setHeaderHidden(True) self.tv_notes.resizeColumnToContents(0) self.tv_notes.setColumnHidden(1, True) self.tv_notes.setColumnHidden(2, True) self.tv_notes.setColumnHidden(3, True) def click_tv_item(self, index): is_dir = index.model().isDir(index) self.select_path = index.model().filePath(index) if is_dir: self.btn_add_sub.setDisabled(False) self.btn_add_note.setDisabled(False) self.btn_save_note.setDisabled(True) self.te_note.clear() self.te_note.setDisabled(True) else: self.te_note.clear() self.btn_add_sub.setDisabled(True) self.btn_add_note.setDisabled(True) self.btn_save_note.setDisabled(False) self.te_note.setDisabled(False) file = open(self.select_path, mode='r', encoding='utf-8') for line in file.readlines(): self.te_note.append(line.strip('\n')) file.close() def doubleclick_tv_item(self, index): is_dir = index.model().isDir(index) self.select_path = index.model().filePath(index) path, ordinary_filename = os.path.split(self.select_path) file_name, success = QInputDialog.getText(self, "Title", "File Name:", QLineEdit.Normal, ordinary_filename.split('.')[0]) if success: if file_name.strip(' ') == '': return if is_dir: os.rename(self.select_path, path + os.path.sep + file_name.strip(' ')) else: os.rename(self.select_path, path + os.path.sep + file_name.strip(' ') + '.txt') def btn_click(self): btn = self.sender() if btn == self.btn_save_note: content = self.te_note.toPlainText() lines = content.split('\n') file = open(self.select_path, mode='w+', encoding='utf-8') for line in lines: file.write(line + '\n') file.close() else: file_name, success = QInputDialog.getText(self, "Title", "File Name:", QLineEdit.Normal, '') if success: if file_name.strip(' ') == '': return if btn == self.btn_add_root: path = os.path.dirname( os.path.realpath(__file__)) + os.path.sep + 'notes' + os.path.sep + file_name.strip(' ') if not os.path.exists(path): os.mkdir(path) elif btn == self.btn_add_sub: path = self.select_path + os.path.sep + file_name.strip(' ') if not os.path.exists(path): os.mkdir(path) elif btn == self.btn_add_note: path = self.select_path + os.path.sep + file_name.strip(' ') + '.txt' if not os.path.exists(path): open(path, mode='w', encoding='utf-8') def change_font_size(self): rb = self.sender() font = QFont() if rb == self.rb_fonts_small: font.setPointSize(10) elif rb == self.rb_fonts_normal: font.setPointSize(12) elif rb == self.rb_fonts_big: font.setPointSize(14) elif rb == self.rb_fonts_bigger: font.setPointSize(18) elif rb == self.rb_fonts_biggest: font.setPointSize(20) self.te_note.setFont(font)
print('Directory') # Directory 출력 else: path = model.filePath(index) label.setPixmap(QPixmap(path)) if __name__ == '__main__': app = QApplication(sys.argv) tree_view = QTreeView() tree_view.show() model = QFileSystemModel() # 파일 창 띄우기 tree_view.setModel(model) root_path = "../" # 파일 경로 model.setRootPath(root_path) tree_view.setRootIndex(model.index(root_path)) tree_view.setColumnWidth(0, 400) tree_view.resize(700, 500) tree_view.setColumnHidden(1, True) # 두번째 컬럼 숨기기 tree_view.setColumnHidden(2, True) # 세번째 컬럼 숨기기 tree_view.setColumnHidden(3, True) # 네번째 컬럼 숨기기 tree_view.doubleClicked.connect(double_click_event) # 트리 창 더블클릭하면 함수 double_click_event수행 label = QLabel("label") # label 창 띄우기 label.resize(600, 400) # label 창 크기 정하기 label.show() # label 창 보여주기 app.exec_()
class MainWindowClass(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.interface_lng_val = 'Russian' if self.interface_lng_val == 'Russian': self.setWindowTitle("Графический интерфейс программы OpenFOAM") elif self.interface_lng_val == 'English': self.setWindowTitle("OpenFOAM_decompose_GUI") # Базовые переменные self.full_dir = '' self.prj_name = '' self.con = '' self.lock_bool = False self.application = '' self.object_edit_txt = '' # ---------------------------Панель управления подготовкой задачи МСС----------------------------- # self.proj_open = QAction(self) self.proj_open.setEnabled(True) proj_ico = self.style().standardIcon(QStyle.SP_ArrowUp) self.proj_open.setIcon(proj_ico) if self.interface_lng_val == 'Russian': self.proj_open.setToolTip('Открыть проект') elif self.interface_lng_val == 'English': self.proj_open.setToolTip('Open the project') self.lng_chs = QAction(self) self.lng_chs.setEnabled(True) lng_chs_ico = self.style().standardIcon( QStyle.SP_FileDialogDetailedView) self.lng_chs.setIcon(lng_chs_ico) if self.interface_lng_val == 'Russian': self.lng_chs.setToolTip('Выбрать язык интерфейса программы') elif self.interface_lng_val == 'English': self.lng_chs.setToolTip('Select the interface language') self.file_open = QAction(self) self.file_open.setEnabled(False) file_open_ico = self.style().standardIcon(QStyle.SP_FileIcon) self.file_open.setIcon(file_open_ico) if self.interface_lng_val == 'Russian': self.file_open.setToolTip( 'Открыть форму создания служебного файла для директории 0') elif self.interface_lng_val == 'English': self.file_open.setToolTip( 'Open the form for creating the service file for the directory 0' ) self.toolBar_1 = QToolBar("MyToolBar") self.toolBar_1.addAction(self.proj_open) self.toolBar_1.addAction(self.lng_chs) self.toolBar_1.addAction(self.file_open) self.proj_open.triggered.connect( lambda: first_toolbar_functions_class.on_proj_open(self)) self.lng_chs.triggered.connect( lambda: first_toolbar_functions_class.on_lng_chs(self)) self.file_open.triggered.connect( lambda: first_toolbar_functions_class.on_0_files_window_chs(self)) self.addToolBar(self.toolBar_1) ###----------------------Панель управления подготовкой РС--------------------------### self.msh_open = QAction(self) self.msh_open.setEnabled(False) msh_ico = self.style().standardIcon(QStyle.SP_FileDialogNewFolder) self.msh_open.setIcon(msh_ico) if self.interface_lng_val == 'Russian': self.msh_open.setToolTip('Открыть форму выбора расчетной сетки') elif self.interface_lng_val == 'English': self.msh_open.setToolTip('Open the mesh selection form') self.msh_run = QAction(self) self.msh_run.setEnabled(False) msh_ico = self.style().standardIcon(QStyle.SP_ArrowRight) self.msh_run.setIcon(msh_ico) if self.interface_lng_val == 'Russian': self.msh_run.setToolTip('Выполнить генерацию расчетной сетки') elif self.interface_lng_val == 'English': self.msh_run.setToolTip('Make the mesh generation') self.msh_visual = QAction(self) self.msh_visual.setEnabled(False) msh_visual_ico = self.style().standardIcon(QStyle.SP_MediaSeekForward) self.msh_visual.setIcon(msh_visual_ico) if self.interface_lng_val == 'Russian': self.msh_visual.setToolTip( 'Выполнить визуализацию расчетной сетки') elif self.interface_lng_val == 'English': self.msh_visual.setToolTip('Make the mesh visualization') self.toolBar_2 = QToolBar() self.toolBar_2.addAction(self.msh_open) self.toolBar_2.addAction(self.msh_run) self.toolBar_2.addAction(self.msh_visual) self.msh_open.triggered.connect( lambda: second_toolbar_functions_class.on_msh_open(self)) self.msh_run.triggered.connect( lambda: second_toolbar_functions_class.on_msh_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.msh_visual.triggered.connect( lambda: second_toolbar_functions_class.on_visual_msh_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.addToolBar(self.toolBar_2) self.insertToolBarBreak(self.toolBar_2) ###----------------------Панель управления решением задачи МСС--------------------------### self.solv_run = QAction(self) self.solv_run.setEnabled(False) solv_run_ico = self.style().standardIcon(QStyle.SP_DialogNoButton) self.solv_run.setIcon(solv_run_ico) if self.interface_lng_val == 'Russian': self.solv_run.setToolTip('Выполнить решение') elif self.interface_lng_val == 'English': self.solv_run.setToolTip('Run solution') self.solv_stop = QAction(self) self.solv_stop.setEnabled(False) close_ico = self.style().standardIcon(QStyle.SP_DockWidgetCloseButton) self.solv_stop.setIcon(close_ico) if self.interface_lng_val == 'Russian': self.solv_stop.setToolTip('Остановить процесс решения') elif self.interface_lng_val == 'English': self.solv_stop.setToolTip('Stop the solution process') self.solv_run_vis = QAction(self) self.solv_run_vis.setEnabled(False) solv_run_vis_ico = self.style().standardIcon(QStyle.SP_CommandLink) self.solv_run_vis.setIcon(solv_run_vis_ico) if self.interface_lng_val == 'Russian': self.solv_run_vis.setToolTip( 'Выполнить визуализацию результатов решения') elif self.interface_lng_val == 'English': self.solv_run_vis.setToolTip('Visualize the solution results') self.toolBar_3 = QToolBar() self.toolBar_3.addAction(self.solv_run) self.toolBar_3.addAction(self.solv_stop) self.toolBar_3.addAction(self.solv_run_vis) self.solv_run.triggered.connect( lambda: second_toolbar_functions_class.on_solv_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.solv_stop.triggered.connect( lambda: second_toolbar_functions_class.on_solv_stop( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.solv_run_vis.triggered.connect( lambda: second_toolbar_functions_class.on_solv_vis( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.addToolBar(self.toolBar_3) self.insertToolBarBreak(self.toolBar_3) ###----------------Верхний виджет с полным путем до файла сетки----------------### self.tdw = QDockWidget() self.tdw.setFixedSize(1400, 65) self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures) self.tdw_grid = QGridLayout() self.tdw_grid.setColumnStretch(2, 1) self.tdw_frame = QFrame() self.tdw_frame.setStyleSheet("background-color: ghostwhite;" "border-width: 0.5px;" "border-style: solid;" "border-color: silver;") self.tdw_frame.setLayout(self.tdw_grid) self.tdw.setWidget(self.tdw_frame) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.tdw) ###-----------------Левый виджет с файловой системой проекта---------------------### self.fsw = QDockWidget() self.fsw.setFeatures(self.fsw.NoDockWidgetFeatures) self.fsw_label = QLabel() self.fsw_label.setAlignment(QtCore.Qt.AlignCenter) self.fsw_grid = QGridLayout() self.fsw_grid.addWidget(self.fsw_label, 0, 0) self.fsw_frame = QFrame() self.fsw_frame.setFixedSize(200, 35) self.fsw_frame.setStyleSheet("background-color: honeydew;" "border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;") self.fsw_frame.setLayout(self.fsw_grid) if self.interface_lng_val == 'Russian': fs_lbl = "Файловая Cтруктура Проекта" elif self.interface_lng_val == 'English': fs_lbl = "File Structure of the Project" self.fsw_label.setText("<font color='SeaGreen'>" + fs_lbl + "</font>") self.fsw_label.setStyleSheet("border-style: none;" "font-size: 10pt;") self.fsw.setTitleBarWidget(self.fsw_frame) self.treeview = QTreeView() self.treeview.setFixedSize(200, 520) self.treeview.model = QtGui.QStandardItemModel() self.treeview.setModel(self.treeview.model) self.treeview.setColumnWidth(0, 100) self.treeview.setColumnHidden(1, True) self.treeview.setColumnHidden(2, True) self.treeview.setColumnHidden(3, True) self.treeview.header().hide() self.treeview.setItemsExpandable(False) self.treeview.clicked.connect(self.on_treeview_clicked) self.fsw.setWidget(self.treeview) ###-----------Правый виджет с формой вывода результатов генерации файлов-----------### self.cdw = QDockWidget() self.cdw.setFeatures(self.cdw.NoDockWidgetFeatures) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw) self.cdw_grid = QGridLayout() self.cdw_frame = QFrame() self.cdw_frame.setFixedSize(495, 35) self.cdw_frame.setStyleSheet("border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;" "background-color: honeydew;") self.cdw_frame.setLayout(self.cdw_grid) self.outf_lbl = QLabel() self.outf_lbl.setAlignment(QtCore.Qt.AlignCenter) self.outf_lbl.setStyleSheet("border-style: none;" "font-size: 9pt;") self.cdw_grid.addWidget(self.outf_lbl, 0, 0) self.outf_edit = QTextEdit() self.outf_scroll = QScrollArea() self.outf_scroll.setWidgetResizable(True) self.outf_scroll.setWidget(self.outf_edit) self.outf_scroll.setFixedSize(495, 520) ###-----------------Центральный виджет с формой параметров---------------------### self.ffw = QDockWidget() self.ffw.setFeatures(self.ffw.NoDockWidgetFeatures) self.ffw_label = QLabel() self.ffw_label.setAlignment(QtCore.Qt.AlignCenter) self.ffw_grid = QGridLayout() self.ffw_grid.addWidget(self.ffw_label, 0, 0) self.ffw_frame = QFrame() self.ffw_frame.setFixedSize(693, 44) self.ffw_frame.setStyleSheet("border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;" "background-color: honeydew;") self.ffw_frame.setLayout(self.ffw_grid) ###------------------Нижний виджет со служебными сообщениями------------------### if self.interface_lng_val == 'Russian': self.serv_mes = QDockWidget("Служебные сообщения") elif self.interface_lng_val == 'English': self.serv_mes = QDockWidget("Service messages") self.serv_mes.setFixedSize(1400, 160) self.serv_mes.setFeatures(self.serv_mes.NoDockWidgetFeatures) self.listWidget = QListWidget() self.serv_mes.setWidget(self.listWidget) ###---------------------Функции, связанные с работой главного окна------------------------### # ...........................Функция клика по файлу из дерева......................... ###........................Функция открытия окна выбора интерфейса программы...................### # ...........................Функция клика по файлу из дерева......................... def on_treeview_clicked(self, index): global fileName indexItem = self.treeview.model.index(index.row(), 0, index.parent()) self.lock_bool = True self.file_name = self.treeview.model.itemFromIndex(indexItem).text() file_form_class.inp_file_form_func(self, self.file_name, self.con) file_name_title = file_form_class.out_file_name_func() self.clear_label = QLabel() if file_name_title != None: if file_name_title != 'md': #self.cdw.setWidget(self.clear_label) #self.cdw.setTitleBarWidget if os.path.exists(self.full_dir + '/system/' + file_name_title): outf = open(self.full_dir + '/system/' + file_name_title) data = outf.read() self.outf_edit.setText(data) outf.close() elif os.path.exists(self.full_dir + '/constant/' + file_name_title): outf = open(self.full_dir + '/constant/' + file_name_title) data = outf.read() self.outf_edit.setText(data) outf.close() elif os.path.exists(self.full_dir + '/0/' + file_name_title): outf = open(self.full_dir + '/0/' + file_name_title) data = outf.read() self.outf_edit.setText(data) outf.close() self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw) self.cdw.setWidget(self.outf_scroll) #data = outf.read() if self.interface_lng_val == 'Russian': self.outf_lbl.setText("Файл " + "<font color='peru'>" + file_name_title + "</font>") elif self.interface_lng_val == 'English': self.outf_lbl.setText("<font color='peru'>" + file_name_title + "</font>" + " file") #self.outf_edit.setText(data) self.cdw.setTitleBarWidget(self.cdw_frame) #outf.close() self.setCentralWidget(self.ffw) file_form = file_form_class.out_file_form_func() self.ffw.setWidget(file_form) self.ffw.setTitleBarWidget(self.ffw_frame) if self.interface_lng_val == 'Russian': self.ffw_label.setText("Форма параметров файла: " + "<font color='peru'>" + file_name_title + "</font>") elif self.interface_lng_val == 'English': self.ffw_label.setText("<font color='peru'>" + file_name_title + "</font>" + " file parameters form") self.ffw_label.setStyleSheet("border-style: none;" "font-size: 9pt;") elif file_name_title == 'md': if self.interface_lng_val == 'Russian': msg_lbl = QLabel( '<span style="color:blue">Для создания расчетной сетки воспользуйтесь панелью инструментов</span>' ) elif self.interface_lng_val == 'English': msg_lbl = QLabel( '<span style="color:blue">To create a mesh use the toolbar.</span>' ) self.listWidget.clear() self.item = QListWidgetItem() self.listWidget.addItem(self.item) self.listWidget.setItemWidget(self.item, msg_lbl) else: self.ffw.setTitleBarWidget(self.clear_label) self.ffw.setWidget(self.clear_label) self.cdw.setWidget(self.clear_label) self.cdw.setTitleBarWidget(self.clear_label) # .........................Функция получения языка интерфейса.......................... def on_lng_get(self, interface_lng): global interface_lng_val self.interface_lng_val = interface_lng if self.interface_lng_val == 'Russian': self.setWindowTitle("Графический интерфейс программы OpenFOAM") self.proj_open.setToolTip('Открыть проект') self.msh_run.setToolTip('Выполнить генерацию расчетной сетки') self.msh_visual.setToolTip( 'Выполнить визуализацию расчетной сетки') self.lng_chs.setToolTip('Выбрать язык интерфейса программы') self.file_open.setToolTip( 'Открыть форму создания служебного файла для директории 0') self.msh_open.setToolTip('Открыть форму выбора расчетной сетки') self.solv_run.setToolTip('Выполнить решение') self.solv_stop.setToolTip('Остановить процесс решения') self.solv_run_vis.setToolTip( 'Выполнить визуализацию результатов решения') elif self.interface_lng_val == 'English': self.setWindowTitle("OpenFOAM_decompose_GUI") self.proj_open.setToolTip('Open the project') self.msh_run.setToolTip('Run mesh generation') self.msh_visual.setToolTip('Run mesh visualization') self.lng_chs.setToolTip( 'Select the interface language for the program') self.file_open.setToolTip( 'Open the form for creating the service file for the directory 0' ) self.msh_open.setToolTip('Open the mesh selection form') self.solv_run.setToolTip('Run solution') self.solv_stop.setToolTip('Stop the solution process') self.solv_run_vis.setToolTip('Visualize the solution results') # .........................Функция получения пути до директории.......................... def on_prj_path_get(self, prj_path, mesh_name_txt): global prj_path_val global mesh_name_txt_val global pp_dir prj_path_val = prj_path mesh_name_txt_val = mesh_name_txt pp_dir, pp_sys = os.path.split(prj_path_val) # .............................Функция получения типа сетки.............................. def on_mesh_type_get(self, pd_2): global msh_type msh_type = pd_2
class ReTextWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.resize(950, 700) screenRect = QDesktopWidget().screenGeometry() if globalSettings.windowGeometry: self.restoreGeometry(globalSettings.windowGeometry) else: self.move((screenRect.width() - self.width()) // 2, (screenRect.height() - self.height()) // 2) if not screenRect.contains(self.geometry()): self.showMaximized() if sys.platform.startswith('darwin'): # https://github.com/retext-project/retext/issues/198 searchPaths = QIcon.themeSearchPaths() searchPaths.append('/opt/local/share/icons') searchPaths.append('/usr/local/share/icons') QIcon.setThemeSearchPaths(searchPaths) setIconThemeFromSettings() if QFile.exists(getBundledIcon('retext')): self.setWindowIcon(QIcon(getBundledIcon('retext'))) elif QFile.exists('/usr/share/pixmaps/retext.png'): self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png')) else: self.setWindowIcon(QIcon.fromTheme('retext', QIcon.fromTheme('accessories-text-editor'))) self.splitter = QSplitter(self) self.treeView = QTreeView(self.splitter) self.treeView.doubleClicked.connect(self.treeItemSelected) self.tabWidget = QTabWidget(self.splitter) self.initTabWidget() self.splitter.setSizes([self.width() / 5, self.width() * 4 / 5]) self.initDirectoryTree(globalSettings.showDirectoryTree, globalSettings.directoryPath) self.setCentralWidget(self.splitter) self.tabWidget.currentChanged.connect(self.changeIndex) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.toolBar = QToolBar(self.tr('File toolbar'), self) self.addToolBar(Qt.TopToolBarArea, self.toolBar) self.editBar = QToolBar(self.tr('Edit toolbar'), self) self.addToolBar(Qt.TopToolBarArea, self.editBar) self.searchBar = QToolBar(self.tr('Search toolbar'), self) self.addToolBar(Qt.BottomToolBarArea, self.searchBar) self.toolBar.setVisible(not globalSettings.hideToolBar) self.editBar.setVisible(not globalSettings.hideToolBar) self.actionNew = self.act(self.tr('New'), 'document-new', self.createNew, shct=QKeySequence.New) self.actionNew.setPriority(QAction.LowPriority) self.actionOpen = self.act(self.tr('Open'), 'document-open', self.openFile, shct=QKeySequence.Open) self.actionOpen.setPriority(QAction.LowPriority) self.actionSetEncoding = self.act(self.tr('Set encoding'), trig=self.showEncodingDialog) self.actionSetEncoding.setEnabled(False) self.actionReload = self.act(self.tr('Reload'), 'view-refresh', lambda: self.currentTab.readTextFromFile()) self.actionReload.setEnabled(False) self.actionSave = self.act(self.tr('Save'), 'document-save', self.saveFile, shct=QKeySequence.Save) self.actionSave.setEnabled(False) self.actionSave.setPriority(QAction.LowPriority) self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as', self.saveFileAs, shct=QKeySequence.SaveAs) self.actionNextTab = self.act(self.tr('Next tab'), 'go-next', lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown) self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous', lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp) self.actionCloseCurrentTab = self.act(self.tr('Close tab'), 'window-close', lambda: self.closeTab(self.ind), shct=QKeySequence.Close) self.actionPrint = self.act(self.tr('Print'), 'document-print', self.printFile, shct=QKeySequence.Print) self.actionPrint.setPriority(QAction.LowPriority) self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview', self.printPreview) self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml) self.actionChangeEditorFont = self.act(self.tr('Change editor font'), trig=self.changeEditorFont) self.actionChangePreviewFont = self.act(self.tr('Change preview font'), trig=self.changePreviewFont) self.actionSearch = self.act(self.tr('Find text'), 'edit-find', self.search, shct=QKeySequence.Find) self.actionGoToLine = self.act(self.tr('Go to line'), trig=self.goToLine, shct=Qt.CTRL+Qt.Key_G) self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged) self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E, trigbool=self.preview) if QIcon.hasThemeIcon('document-preview'): self.actionPreview.setIcon(QIcon.fromTheme('document-preview')) elif QIcon.hasThemeIcon('preview-file'): self.actionPreview.setIcon(QIcon.fromTheme('preview-file')) elif QIcon.hasThemeIcon('x-office-document'): self.actionPreview.setIcon(QIcon.fromTheme('x-office-document')) else: self.actionPreview.setIcon(QIcon(getBundledIcon('document-preview'))) self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L, trigbool=self.enableLivePreview) menuPreview = QMenu() menuPreview.addAction(self.actionLivePreview) self.actionPreview.setMenu(menuPreview) self.actionInsertTable = self.act(self.tr('Insert table'), trig=lambda: self.insertFormatting('table')) self.actionTableMode = self.act(self.tr('Table editing mode'), shct=Qt.CTRL+Qt.Key_T, trigbool=lambda x: self.currentTab.editBox.enableTableMode(x)) self.actionInsertImages = self.act(self.tr('Insert images by file path'), trig=lambda: self.insertImages()) if ReTextFakeVimHandler: self.actionFakeVimMode = self.act(self.tr('FakeVim mode'), shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode) if globalSettings.useFakeVim: self.actionFakeVimMode.setChecked(True) self.enableFakeVimMode(True) self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen', shct=Qt.Key_F11, trigbool=self.enableFullScreen) self.actionFullScreen.setChecked(self.isFullScreen()) self.actionFullScreen.setPriority(QAction.LowPriority) self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system', trig=self.openConfigDialog) self.actionConfig.setMenuRole(QAction.PreferencesRole) self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml) self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf) self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf) self.getExportExtensionsList() self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit) self.actionQuit.setMenuRole(QAction.QuitRole) self.actionQuit.triggered.connect(self.close) self.actionUndo = self.act(self.tr('Undo'), 'edit-undo', lambda: self.currentTab.editBox.undo(), shct=QKeySequence.Undo) self.actionRedo = self.act(self.tr('Redo'), 'edit-redo', lambda: self.currentTab.editBox.redo(), shct=QKeySequence.Redo) self.actionCopy = self.act(self.tr('Copy'), 'edit-copy', lambda: self.currentTab.editBox.copy(), shct=QKeySequence.Copy) self.actionCut = self.act(self.tr('Cut'), 'edit-cut', lambda: self.currentTab.editBox.cut(), shct=QKeySequence.Cut) self.actionPaste = self.act(self.tr('Paste'), 'edit-paste', lambda: self.currentTab.editBox.paste(), shct=QKeySequence.Paste) self.actionPasteImage = self.act(self.tr('Paste image'), 'edit-paste', lambda: self.currentTab.editBox.pasteImage(), shct=Qt.CTRL+Qt.SHIFT+Qt.Key_V) self.actionMoveUp = self.act(self.tr('Move line up'), 'go-up', lambda: self.currentTab.editBox.moveLineUp(), shct=Qt.ALT+Qt.Key_Up) self.actionMoveDown = self.act(self.tr('Move line down'), 'go-down', lambda: self.currentTab.editBox.moveLineDown(), shct=Qt.ALT+Qt.Key_Down) self.actionUndo.setEnabled(False) self.actionRedo.setEnabled(False) self.actionCopy.setEnabled(False) self.actionCut.setEnabled(False) qApp = QApplication.instance() qApp.clipboard().dataChanged.connect(self.clipboardDataChanged) self.clipboardDataChanged() if enchant is not None: self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck) self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale) self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit) if ReTextWebKitPreview is None: globalSettings.useWebKit = False self.actionWebKit.setEnabled(False) self.actionWebKit.setChecked(globalSettings.useWebKit) self.actionWebEngine = self.act(self.tr('Use WebEngine (Chromium) renderer'), trigbool=self.enableWebEngine) if ReTextWebEnginePreview is None: globalSettings.useWebEngine = False self.actionWebEngine.setChecked(globalSettings.useWebEngine) self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir) self.actionFind = self.act(self.tr('Next'), 'go-next', self.find, shct=QKeySequence.FindNext) self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous', lambda: self.find(back=True), shct=QKeySequence.FindPrevious) self.actionReplace = self.act(self.tr('Replace'), 'edit-find-replace', lambda: self.find(replace=True)) self.actionReplaceAll = self.act(self.tr('Replace all'), trig=self.replaceAll) menuReplace = QMenu() menuReplace.addAction(self.actionReplaceAll) self.actionReplace.setMenu(menuReplace) self.actionCloseSearch = self.act(self.tr('Close'), 'window-close', lambda: self.searchBar.setVisible(False), shct=QKeySequence.Cancel) self.actionCloseSearch.setPriority(QAction.LowPriority) self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp) self.aboutWindowTitle = self.tr('About ReText') self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog) self.actionAbout.setMenuRole(QAction.AboutRole) self.actionAboutQt = self.act(self.tr('About Qt')) self.actionAboutQt.setMenuRole(QAction.AboutQtRole) self.actionAboutQt.triggered.connect(qApp.aboutQt) availableMarkups = markups.get_available_markups() if not availableMarkups: print('Warning: no markups are available!') if len(availableMarkups) > 1: self.chooseGroup = QActionGroup(self) markupActions = [] for markup in availableMarkups: markupAction = self.act(markup.name, trigbool=self.markupFunction(markup)) if markup.name == globalSettings.defaultMarkup: markupAction.setChecked(True) self.chooseGroup.addAction(markupAction) markupActions.append(markupAction) self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold, trig=lambda: self.insertFormatting('bold')) self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic, trig=lambda: self.insertFormatting('italic')) self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline, trig=lambda: self.insertFormatting('underline')) self.usefulTags = ('header', 'italic', 'bold', 'underline', 'numbering', 'bullets', 'image', 'link', 'inline code', 'code block', 'blockquote', 'table') self.usefulChars = ('deg', 'divide', 'euro', 'hellip', 'laquo', 'larr', 'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo', 'rarr', 'rsquo', 'times') self.formattingBox = QComboBox(self.editBar) self.formattingBox.addItem(self.tr('Formatting')) self.formattingBox.addItems(self.usefulTags) self.formattingBox.activated[str].connect(self.insertFormatting) self.symbolBox = QComboBox(self.editBar) self.symbolBox.addItem(self.tr('Symbols')) self.symbolBox.addItems(self.usefulChars) self.symbolBox.activated.connect(self.insertSymbol) self.updateStyleSheet() menubar = self.menuBar() menuFile = menubar.addMenu(self.tr('&File')) menuEdit = menubar.addMenu(self.tr('&Edit')) menuHelp = menubar.addMenu(self.tr('&Help')) menuFile.addAction(self.actionNew) menuFile.addAction(self.actionOpen) self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent')) self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles) menuFile.addAction(self.actionShow) menuFile.addAction(self.actionSetEncoding) menuFile.addAction(self.actionReload) menuFile.addSeparator() menuFile.addAction(self.actionSave) menuFile.addAction(self.actionSaveAs) menuFile.addSeparator() menuFile.addAction(self.actionNextTab) menuFile.addAction(self.actionPrevTab) menuFile.addAction(self.actionCloseCurrentTab) menuFile.addSeparator() menuExport = menuFile.addMenu(self.tr('Export')) menuExport.addAction(self.actionSaveHtml) menuExport.addAction(self.actionOdf) menuExport.addAction(self.actionPdf) if self.extensionActions: menuExport.addSeparator() for action, mimetype in self.extensionActions: menuExport.addAction(action) menuExport.aboutToShow.connect(self.updateExtensionsVisibility) menuFile.addAction(self.actionPrint) menuFile.addAction(self.actionPrintPreview) menuFile.addSeparator() menuFile.addAction(self.actionQuit) menuEdit.addAction(self.actionUndo) menuEdit.addAction(self.actionRedo) menuEdit.addSeparator() menuEdit.addAction(self.actionCut) menuEdit.addAction(self.actionCopy) menuEdit.addAction(self.actionPaste) menuEdit.addAction(self.actionPasteImage) menuEdit.addSeparator() menuEdit.addAction(self.actionMoveUp) menuEdit.addAction(self.actionMoveDown) menuEdit.addSeparator() if enchant is not None: menuSC = menuEdit.addMenu(self.tr('Spell check')) menuSC.addAction(self.actionEnableSC) menuSC.addAction(self.actionSetLocale) menuEdit.addAction(self.actionSearch) menuEdit.addAction(self.actionGoToLine) menuEdit.addAction(self.actionChangeEditorFont) menuEdit.addAction(self.actionChangePreviewFont) menuEdit.addSeparator() if len(availableMarkups) > 1: self.menuMode = menuEdit.addMenu(self.tr('Default markup')) for markupAction in markupActions: self.menuMode.addAction(markupAction) menuFormat = menuEdit.addMenu(self.tr('Formatting')) menuFormat.addAction(self.actionBold) menuFormat.addAction(self.actionItalic) menuFormat.addAction(self.actionUnderline) if ReTextWebKitPreview is not None or ReTextWebEnginePreview is None: menuEdit.addAction(self.actionWebKit) else: menuEdit.addAction(self.actionWebEngine) menuEdit.addSeparator() menuEdit.addAction(self.actionViewHtml) menuEdit.addAction(self.actionPreview) menuEdit.addAction(self.actionInsertTable) menuEdit.addAction(self.actionTableMode) menuEdit.addAction(self.actionInsertImages) if ReTextFakeVimHandler: menuEdit.addAction(self.actionFakeVimMode) menuEdit.addSeparator() menuEdit.addAction(self.actionFullScreen) menuEdit.addAction(self.actionConfig) menuHelp.addAction(self.actionHelp) menuHelp.addSeparator() menuHelp.addAction(self.actionAbout) menuHelp.addAction(self.actionAboutQt) self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toolBar.addAction(self.actionNew) self.toolBar.addSeparator() self.toolBar.addAction(self.actionOpen) self.toolBar.addAction(self.actionSave) self.toolBar.addAction(self.actionPrint) self.toolBar.addSeparator() self.toolBar.addAction(self.actionPreview) self.toolBar.addAction(self.actionFullScreen) self.editBar.addAction(self.actionUndo) self.editBar.addAction(self.actionRedo) self.editBar.addSeparator() self.editBar.addAction(self.actionCut) self.editBar.addAction(self.actionCopy) self.editBar.addAction(self.actionPaste) self.editBar.addSeparator() self.editBar.addWidget(self.formattingBox) self.editBar.addWidget(self.symbolBox) self.searchEdit = QLineEdit(self.searchBar) self.searchEdit.setPlaceholderText(self.tr('Search')) self.searchEdit.returnPressed.connect(self.find) self.replaceEdit = QLineEdit(self.searchBar) self.replaceEdit.setPlaceholderText(self.tr('Replace with')) self.replaceEdit.returnPressed.connect(self.find) self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar) self.searchBar.addWidget(self.searchEdit) self.searchBar.addWidget(self.replaceEdit) self.searchBar.addSeparator() self.searchBar.addWidget(self.csBox) self.searchBar.addAction(self.actionFindPrev) self.searchBar.addAction(self.actionFind) self.searchBar.addAction(self.actionReplace) self.searchBar.addAction(self.actionCloseSearch) self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.searchBar.setVisible(False) self.autoSaveEnabled = globalSettings.autoSave if self.autoSaveEnabled: timer = QTimer(self) timer.start(60000) timer.timeout.connect(self.saveAll) self.ind = None if enchant is not None: self.sl = globalSettings.spellCheckLocale try: enchant.Dict(self.sl or None) except enchant.errors.Error as e: warnings.warn(str(e), RuntimeWarning) globalSettings.spellCheck = False if globalSettings.spellCheck: self.actionEnableSC.setChecked(True) self.fileSystemWatcher = QFileSystemWatcher() self.fileSystemWatcher.fileChanged.connect(self.fileChanged) def restoreLastOpenedFiles(self): for file in readListFromSettings("lastFileList"): self.openFileWrapper(file) # Show the tab of last opened file lastTabIndex = globalSettings.lastTabIndex if lastTabIndex >= 0 and lastTabIndex < self.tabWidget.count(): self.tabWidget.setCurrentIndex(lastTabIndex) def iterateTabs(self): for i in range(self.tabWidget.count()): yield self.tabWidget.widget(i) def updateStyleSheet(self): self.ss = None if globalSettings.styleSheet: sheetfile = QFile(globalSettings.styleSheet) sheetfile.open(QIODevice.ReadOnly) self.ss = QTextStream(sheetfile).readAll() sheetfile.close() def initTabWidget(self): def dragEnterEvent(e): e.acceptProposedAction() def dropEvent(e): fn = bytes(e.mimeData().data('text/plain')).decode().rstrip() if fn.startswith('file:'): fn = QUrl(fn).toLocalFile() self.openFileWrapper(fn) self.tabWidget.setTabsClosable(True) self.tabWidget.setAcceptDrops(True) self.tabWidget.setMovable(True) self.tabWidget.dragEnterEvent = dragEnterEvent self.tabWidget.dropEvent = dropEvent self.tabWidget.setTabBarAutoHide(globalSettings.tabBarAutoHide) def initDirectoryTree(self, visible, path): if visible: self.fileSystemModel = QFileSystemModel(self.treeView) self.fileSystemModel.setRootPath(path) supportedExtensions = ['.txt'] for markup in markups.get_all_markups(): supportedExtensions += markup.file_extensions filters = ["*" + s for s in supportedExtensions] self.fileSystemModel.setNameFilters(filters) self.fileSystemModel.setNameFilterDisables(False) self.treeView.setModel(self.fileSystemModel) self.treeView.setRootIndex(self.fileSystemModel.index(path)) self.treeView.setColumnHidden(1, True) self.treeView.setColumnHidden(2, True) self.treeView.setColumnHidden(3, True) self.treeView.setHeaderHidden(True) self.treeView.setVisible(visible) def treeItemSelected(self, signal): file_path = self.fileSystemModel.filePath(signal) if os.path.isdir(file_path): return self.openFileWrapper(file_path) def act(self, name, icon=None, trig=None, trigbool=None, shct=None): if not isinstance(shct, QKeySequence): shct = QKeySequence(shct) if icon: action = QAction(self.actIcon(icon), name, self) else: action = QAction(name, self) if trig: action.triggered.connect(trig) elif trigbool: action.setCheckable(True) action.triggered[bool].connect(trigbool) if shct: action.setShortcut(shct) return action def actIcon(self, name): return QIcon.fromTheme(name, QIcon(getBundledIcon(name))) def printError(self): import traceback print('Exception occurred while parsing document:', file=sys.stderr) traceback.print_exc() def updateTabTitle(self, ind, tab): changed = tab.editBox.document().isModified() if changed and not self.autoSaveActive(tab): title = tab.getBaseName() + '*' else: title = tab.getBaseName() self.tabWidget.setTabText(ind, title) def tabFileNameChanged(self, tab): ''' Perform all UI state changes that need to be done when the filename of the current tab has changed. ''' if tab == self.currentTab: if tab.fileName: self.setWindowTitle("") if globalSettings.windowTitleFullPath: self.setWindowTitle(tab.fileName + '[*]') self.setWindowFilePath(tab.fileName) self.updateTabTitle(self.ind, tab) self.tabWidget.setTabToolTip(self.ind, tab.fileName) QDir.setCurrent(QFileInfo(tab.fileName).dir().path()) else: self.setWindowFilePath('') self.setWindowTitle(self.tr('New document') + '[*]') canReload = bool(tab.fileName) and not self.autoSaveActive(tab) self.actionSetEncoding.setEnabled(canReload) self.actionReload.setEnabled(canReload) def tabActiveMarkupChanged(self, tab): ''' Perform all UI state changes that need to be done when the active markup class of the current tab has changed. ''' if tab == self.currentTab: markupClass = tab.getActiveMarkupClass() dtMarkdown = (markupClass == markups.MarkdownMarkup) dtMkdOrReST = dtMarkdown or (markupClass == markups.ReStructuredTextMarkup) self.formattingBox.setEnabled(dtMarkdown) self.symbolBox.setEnabled(dtMarkdown) self.actionUnderline.setEnabled(dtMarkdown) self.actionBold.setEnabled(dtMkdOrReST) self.actionItalic.setEnabled(dtMkdOrReST) def tabModificationStateChanged(self, tab): ''' Perform all UI state changes that need to be done when the modification state of the current tab has changed. ''' if tab == self.currentTab: changed = tab.editBox.document().isModified() if self.autoSaveActive(tab): changed = False self.actionSave.setEnabled(changed) self.updateTabTitle(self.ind, tab) self.setWindowModified(changed) def createTab(self, fileName): previewStatesByName = { 'editor': PreviewDisabled, 'normal-preview': PreviewNormal, 'live-preview': PreviewLive, } previewState = previewStatesByName.get(globalSettings.defaultPreviewState, PreviewDisabled) if previewState == PreviewNormal and not fileName: previewState = PreviewDisabled # Opening empty document in preview mode makes no sense self.currentTab = ReTextTab(self, fileName, previewState) self.currentTab.fileNameChanged.connect(lambda: self.tabFileNameChanged(self.currentTab)) self.currentTab.modificationStateChanged.connect(lambda: self.tabModificationStateChanged(self.currentTab)) self.currentTab.activeMarkupChanged.connect(lambda: self.tabActiveMarkupChanged(self.currentTab)) self.tabWidget.addTab(self.currentTab, self.tr("New document")) self.currentTab.updateBoxesVisibility() if previewState > 0: QTimer.singleShot(500, self.currentTab.triggerPreviewUpdate) def closeTab(self, ind): if self.maybeSave(ind): if self.tabWidget.count() == 1: self.createTab("") closedTab = self.tabWidget.widget(ind) if closedTab.fileName: self.fileSystemWatcher.removePath(closedTab.fileName) self.tabWidget.removeTab(ind) closedTab.deleteLater() def changeIndex(self, ind): ''' This function is called when a different tab is selected. It changes the state of the window to mirror the current state of the newly selected tab. Future changes to this state will be done in response to signals emitted by the tab, to which the window was subscribed when the tab was created. The window is subscribed to all tabs like this, but only the active tab will logically generate these signals. Aside from the above this function also calls the handlers for the other changes that are implied by a tab switch: filename change, modification state change and active markup change. ''' self.currentTab = self.tabWidget.currentWidget() editBox = self.currentTab.editBox previewState = self.currentTab.previewState self.actionUndo.setEnabled(editBox.document().isUndoAvailable()) self.actionRedo.setEnabled(editBox.document().isRedoAvailable()) self.actionCopy.setEnabled(editBox.textCursor().hasSelection()) self.actionCut.setEnabled(editBox.textCursor().hasSelection()) self.actionPreview.setChecked(previewState >= PreviewLive) self.actionLivePreview.setChecked(previewState == PreviewLive) self.actionTableMode.setChecked(editBox.tableModeEnabled) self.editBar.setEnabled(previewState < PreviewNormal) self.ind = ind editBox.setFocus(Qt.OtherFocusReason) self.tabFileNameChanged(self.currentTab) self.tabModificationStateChanged(self.currentTab) self.tabActiveMarkupChanged(self.currentTab) def changeEditorFont(self): font, ok = QFontDialog.getFont(globalSettings.editorFont, self) if ok: self.setEditorFont(font) def setEditorFont(self, font): globalSettings.editorFont = font for tab in self.iterateTabs(): tab.editBox.updateFont() def changePreviewFont(self): font, ok = QFontDialog.getFont(globalSettings.font, self) if ok: self.setPreviewFont(font) def setPreviewFont(self, font): globalSettings.font = font for tab in self.iterateTabs(): tab.triggerPreviewUpdate() def preview(self, viewmode): self.currentTab.previewState = viewmode * 2 self.actionLivePreview.setChecked(False) self.editBar.setDisabled(viewmode) self.currentTab.updateBoxesVisibility() self.currentTab.triggerPreviewUpdate() def enableLivePreview(self, livemode): self.currentTab.previewState = int(livemode) self.actionPreview.setChecked(livemode) self.editBar.setEnabled(True) self.currentTab.updateBoxesVisibility() self.currentTab.triggerPreviewUpdate() def enableWebKit(self, enable): globalSettings.useWebKit = enable globalSettings.useWebEngine = False for tab in self.iterateTabs(): tab.rebuildPreviewBox() def enableWebEngine(self, enable): globalSettings.useWebKit = False globalSettings.useWebEngine = enable for tab in self.iterateTabs(): tab.rebuildPreviewBox() def enableCopy(self, copymode): self.actionCopy.setEnabled(copymode) self.actionCut.setEnabled(copymode) def enableFullScreen(self, yes): if yes: self.showFullScreen() else: self.showNormal() def openConfigDialog(self): dlg = ConfigDialog(self) dlg.setWindowTitle(self.tr('Preferences')) dlg.show() def enableFakeVimMode(self, yes): globalSettings.useFakeVim = yes if yes: FakeVimMode.init(self) for tab in self.iterateTabs(): tab.editBox.installFakeVimHandler() else: FakeVimMode.exit(self) def enableSpellCheck(self, yes): try: dict = enchant.Dict(self.sl or None) except enchant.errors.Error as e: QMessageBox.warning(self, '', str(e)) self.actionEnableSC.setChecked(False) yes = False self.setAllDictionaries(dict if yes else None) globalSettings.spellCheck = yes def setAllDictionaries(self, dictionary): for tab in self.iterateTabs(): hl = tab.highlighter hl.dictionary = dictionary hl.rehighlight() def changeLocale(self): localedlg = LocaleDialog(self, defaultText=self.sl) if localedlg.exec() != QDialog.Accepted: return sl = localedlg.localeEdit.text() try: enchant.Dict(sl or None) except enchant.errors.Error as e: QMessageBox.warning(self, '', str(e)) else: self.sl = sl or None self.enableSpellCheck(self.actionEnableSC.isChecked()) if localedlg.checkBox.isChecked(): globalSettings.spellCheckLocale = sl def search(self): self.searchBar.setVisible(True) self.searchEdit.setFocus(Qt.ShortcutFocusReason) def goToLine(self): line, ok = QInputDialog.getInt(self, self.tr("Go to line"), self.tr("Type the line number")) if ok: self.currentTab.goToLine(line-1) def searchBarVisibilityChanged(self, visible): if visible: self.searchEdit.setFocus(Qt.ShortcutFocusReason) def find(self, back=False, replace=False): flags = QTextDocument.FindFlags() if back: flags |= QTextDocument.FindBackward if self.csBox.isChecked(): flags |= QTextDocument.FindCaseSensitively text = self.searchEdit.text() replaceText = self.replaceEdit.text() if replace else None found = self.currentTab.find(text, flags, replaceText=replaceText) self.setSearchEditColor(found) def replaceAll(self): text = self.searchEdit.text() replaceText = self.replaceEdit.text() found = self.currentTab.replaceAll(text, replaceText) self.setSearchEditColor(found) def setSearchEditColor(self, found): palette = self.searchEdit.palette() palette.setColor(QPalette.Active, QPalette.Base, Qt.white if found else QColor(255, 102, 102)) self.searchEdit.setPalette(palette) def showInDir(self): if self.currentTab.fileName: path = QFileInfo(self.currentTab.fileName).path() QDesktopServices.openUrl(QUrl.fromLocalFile(path)) else: QMessageBox.warning(self, '', self.tr("Please, save the file somewhere.")) def moveToTopOfRecentFileList(self, fileName): if fileName: files = readListFromSettings("recentFileList") if fileName in files: files.remove(fileName) files.insert(0, fileName) recentCount = globalSettings.recentDocumentsCount if len(files) > recentCount: del files[recentCount:] writeListToSettings("recentFileList", files) def createNew(self, text=None): self.createTab("") self.ind = self.tabWidget.count()-1 self.tabWidget.setCurrentIndex(self.ind) if text: self.currentTab.editBox.textCursor().insertText(text) def switchTab(self, shift=1): self.tabWidget.setCurrentIndex((self.ind + shift) % self.tabWidget.count()) def updateRecentFiles(self): self.menuRecentFiles.clear() self.recentFilesActions = [] filesOld = readListFromSettings("recentFileList") files = [] for f in filesOld: if QFile.exists(f): files.append(f) self.recentFilesActions.append(self.act(f, trig=self.openFunction(f))) writeListToSettings("recentFileList", files) for action in self.recentFilesActions: self.menuRecentFiles.addAction(action) def markupFunction(self, markup): return lambda: self.setDefaultMarkup(markup) def openFunction(self, fileName): return lambda: self.openFileWrapper(fileName) def extensionFunction(self, data): return lambda: \ self.runExtensionCommand(data['Exec'], data['FileFilter'], data['DefaultExtension']) def getExportExtensionsList(self): extensions = [] for extsprefix in datadirs: extsdir = QDir(extsprefix+'/export-extensions/') if extsdir.exists(): for fileInfo in extsdir.entryInfoList(['*.desktop', '*.ini'], QDir.Files | QDir.Readable): extensions.append(self.readExtension(fileInfo.filePath())) locale = QLocale.system().name() self.extensionActions = [] for extension in extensions: try: if ('Name[%s]' % locale) in extension: name = extension['Name[%s]' % locale] elif ('Name[%s]' % locale.split('_')[0]) in extension: name = extension['Name[%s]' % locale.split('_')[0]] else: name = extension['Name'] data = {} for prop in ('FileFilter', 'DefaultExtension', 'Exec'): if 'X-ReText-'+prop in extension: data[prop] = extension['X-ReText-'+prop] elif prop in extension: data[prop] = extension[prop] else: data[prop] = '' action = self.act(name, trig=self.extensionFunction(data)) if 'Icon' in extension: action.setIcon(self.actIcon(extension['Icon'])) mimetype = extension['MimeType'] if 'MimeType' in extension else None except KeyError: print('Failed to parse extension: Name is required', file=sys.stderr) else: self.extensionActions.append((action, mimetype)) def updateExtensionsVisibility(self): markupClass = self.currentTab.getActiveMarkupClass() for action in self.extensionActions: if markupClass is None: action[0].setEnabled(False) continue mimetype = action[1] if mimetype is None: enabled = True elif markupClass == markups.MarkdownMarkup: enabled = (mimetype in ("text/x-retext-markdown", "text/x-markdown", "text/markdown")) elif markupClass == markups.ReStructuredTextMarkup: enabled = (mimetype in ("text/x-retext-rst", "text/x-rst")) else: enabled = False action[0].setEnabled(enabled) def readExtension(self, fileName): extFile = QFile(fileName) extFile.open(QIODevice.ReadOnly) extension = {} stream = QTextStream(extFile) while not stream.atEnd(): line = stream.readLine() if '=' in line: index = line.index('=') extension[line[:index].rstrip()] = line[index+1:].lstrip() extFile.close() return extension def openFile(self): supportedExtensions = ['.txt'] for markup in markups.get_all_markups(): supportedExtensions += markup.file_extensions fileFilter = ' (' + str.join(' ', ['*'+ext for ext in supportedExtensions]) + ');;' fileNames = QFileDialog.getOpenFileNames(self, self.tr("Select one or several files to open"), QDir.currentPath(), self.tr("Supported files") + fileFilter + self.tr("All files (*)")) for fileName in fileNames[0]: self.openFileWrapper(fileName) @pyqtSlot(str) def openFileWrapper(self, fileName): if not fileName: return fileName = QFileInfo(fileName).canonicalFilePath() exists = False for i, tab in enumerate(self.iterateTabs()): if tab.fileName == fileName: exists = True ex = i if exists: self.tabWidget.setCurrentIndex(ex) elif QFile.exists(fileName): noEmptyTab = ( (self.ind is None) or self.currentTab.fileName or self.currentTab.editBox.toPlainText() or self.currentTab.editBox.document().isModified() ) if noEmptyTab: self.createTab(fileName) self.ind = self.tabWidget.count()-1 self.tabWidget.setCurrentIndex(self.ind) if fileName: self.fileSystemWatcher.addPath(fileName) self.currentTab.readTextFromFile(fileName) self.moveToTopOfRecentFileList(self.currentTab.fileName) def showEncodingDialog(self): if not self.maybeSave(self.ind): return codecsSet = set(bytes(QTextCodec.codecForName(alias).name()) for alias in QTextCodec.availableCodecs()) encoding, ok = QInputDialog.getItem(self, '', self.tr('Select file encoding from the list:'), [bytes(b).decode() for b in sorted(codecsSet)], 0, False) if ok: self.currentTab.readTextFromFile(None, encoding) def saveFileAs(self): self.saveFile(dlg=True) def saveAll(self): for tab in self.iterateTabs(): if (tab.fileName and tab.editBox.document().isModified() and QFileInfo(tab.fileName).isWritable()): tab.saveTextToFile() def saveFile(self, dlg=False): fileNameToSave = self.currentTab.fileName if (not fileNameToSave) or dlg: proposedFileName = "" markupClass = self.currentTab.getActiveMarkupClass() if (markupClass is None) or not hasattr(markupClass, 'default_extension'): defaultExt = self.tr("Plain text (*.txt)") ext = ".txt" else: defaultExt = self.tr('%s files', 'Example of final string: Markdown files') \ % markupClass.name + ' (' + str.join(' ', ('*'+extension for extension in markupClass.file_extensions)) + ')' if markupClass == markups.MarkdownMarkup: ext = globalSettings.markdownDefaultFileExtension elif markupClass == markups.ReStructuredTextMarkup: ext = globalSettings.restDefaultFileExtension else: ext = markupClass.default_extension if fileNameToSave is not None: proposedFileName = fileNameToSave fileNameToSave = QFileDialog.getSaveFileName(self, self.tr("Save file"), proposedFileName, defaultExt)[0] if fileNameToSave: if not QFileInfo(fileNameToSave).suffix(): fileNameToSave += ext # Make sure we don't overwrite a file opened in other tab for tab in self.iterateTabs(): if tab is not self.currentTab and tab.fileName == fileNameToSave: QMessageBox.warning(self, "", self.tr("Cannot save to file which is open in another tab!")) return False self.actionSetEncoding.setDisabled(self.autoSaveActive()) if fileNameToSave: if self.currentTab.saveTextToFile(fileNameToSave): self.moveToTopOfRecentFileList(self.currentTab.fileName) return True else: QMessageBox.warning(self, '', self.tr("Cannot save to file because it is read-only!")) return False def saveHtml(self, fileName): if not QFileInfo(fileName).suffix(): fileName += ".html" try: _, htmltext, _ = self.currentTab.getDocumentForExport(webenv=True) except Exception: return self.printError() htmlFile = QFile(fileName) result = htmlFile.open(QIODevice.WriteOnly) if not result: QMessageBox.warning(self, '', self.tr("Cannot save to file because it is read-only!")) return html = QTextStream(htmlFile) if globalSettings.defaultCodec: html.setCodec(globalSettings.defaultCodec) html << htmltext htmlFile.close() def textDocument(self, title, htmltext): td = QTextDocument() td.setMetaInformation(QTextDocument.DocumentTitle, title) td.setHtml(htmltext) td.setDefaultFont(globalSettings.font) return td def saveOdf(self): title, htmltext, _ = self.currentTab.getDocumentForExport() try: document = self.textDocument(title, htmltext) except Exception: return self.printError() fileName = QFileDialog.getSaveFileName(self, self.tr("Export document to ODT"), self.currentTab.getBaseName() + ".odt", self.tr("OpenDocument text files (*.odt)"))[0] if not QFileInfo(fileName).suffix(): fileName += ".odt" writer = QTextDocumentWriter(fileName) writer.setFormat(b"odf") writer.write(document) def saveFileHtml(self): fileName = QFileDialog.getSaveFileName(self, self.tr("Save file"), self.currentTab.getBaseName() + ".html", self.tr("HTML files (*.html *.htm)"))[0] if fileName: self.saveHtml(fileName) def getDocumentForPrint(self, title, htmltext, preview): if globalSettings.useWebKit: return preview try: return self.textDocument(title, htmltext) except Exception: self.printError() def standardPrinter(self, title): printer = QPrinter(QPrinter.HighResolution) printer.setDocName(title) printer.setCreator('ReText %s' % app_version) if globalSettings.paperSize: pageSize = self.getPageSizeByName(globalSettings.paperSize) if pageSize is not None: printer.setPaperSize(pageSize) else: QMessageBox.warning(self, '', self.tr('Unrecognized paperSize setting "%s".') % globalSettings.paperSize) return printer def getPageSizeByName(self, pageSizeName): """ Returns a validated PageSize instance corresponding to the given name. Returns None if the name is not a valid PageSize. """ pageSize = None lowerCaseNames = {pageSize.lower(): pageSize for pageSize in self.availablePageSizes()} if pageSizeName.lower() in lowerCaseNames: pageSize = getattr(QPagedPaintDevice, lowerCaseNames[pageSizeName.lower()]) return pageSize def availablePageSizes(self): """ List available page sizes. """ sizes = [x for x in dir(QPagedPaintDevice) if type(getattr(QPagedPaintDevice, x)) == QPagedPaintDevice.PageSize] return sizes def savePdf(self): fileName = QFileDialog.getSaveFileName(self, self.tr("Export document to PDF"), self.currentTab.getBaseName() + ".pdf", self.tr("PDF files (*.pdf)"))[0] if fileName: if not QFileInfo(fileName).suffix(): fileName += ".pdf" title, htmltext, preview = self.currentTab.getDocumentForExport() if globalSettings.useWebEngine and hasattr(preview.page(), "printToPdf"): pageSize = self.getPageSizeByName(globalSettings.paperSize) if pageSize is None: pageSize = QPageSize(QPageSize.A4) margins = QMarginsF(20, 20, 13, 20) # left, top, right, bottom (in millimeters) layout = QPageLayout(pageSize, QPageLayout.Portrait, margins, QPageLayout.Millimeter) preview.page().printToPdf(fileName, layout) # Available since Qt 5.7 return printer = self.standardPrinter(title) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(fileName) document = self.getDocumentForPrint(title, htmltext, preview) if document != None: document.print(printer) def printFile(self): title, htmltext, preview = self.currentTab.getDocumentForExport() printer = self.standardPrinter(title) dlg = QPrintDialog(printer, self) dlg.setWindowTitle(self.tr("Print document")) if (dlg.exec() == QDialog.Accepted): document = self.getDocumentForPrint(title, htmltext, preview) if document != None: document.print(printer) def printPreview(self): title, htmltext, preview = self.currentTab.getDocumentForExport() document = self.getDocumentForPrint(title, htmltext, preview) if document is None: return printer = self.standardPrinter(title) preview = QPrintPreviewDialog(printer, self) preview.paintRequested.connect(document.print) preview.exec() def runExtensionCommand(self, command, filefilter, defaultext): import shlex of = ('%of' in command) html = ('%html' in command) if of: if defaultext and not filefilter: filefilter = '*'+defaultext fileName = QFileDialog.getSaveFileName(self, self.tr('Export document'), '', filefilter)[0] if not fileName: return if defaultext and not QFileInfo(fileName).suffix(): fileName += defaultext else: fileName = 'out' + defaultext basename = '.%s.retext-temp' % self.currentTab.getBaseName() if html: tmpname = basename+'.html' self.saveHtml(tmpname) else: tmpname = basename + self.currentTab.getActiveMarkupClass().default_extension self.currentTab.writeTextToFile(tmpname) command = command.replace('%of', shlex.quote(fileName)) command = command.replace('%html' if html else '%if', shlex.quote(tmpname)) try: Popen(str(command), shell=True).wait() except Exception as error: errorstr = str(error) QMessageBox.warning(self, '', self.tr('Failed to execute the command:') + '\n' + errorstr) QFile(tmpname).remove() def autoSaveActive(self, tab=None): tab = tab if tab else self.currentTab return bool(self.autoSaveEnabled and tab.fileName and QFileInfo(tab.fileName).isWritable()) def clipboardDataChanged(self): mimeData = QApplication.instance().clipboard().mimeData() if mimeData is not None: self.actionPaste.setEnabled(mimeData.hasText()) self.actionPasteImage.setEnabled(mimeData.hasImage()) def insertFormatting(self, formatting): if formatting == 'table': dialog = InsertTableDialog(self) dialog.show() self.formattingBox.setCurrentIndex(0) return cursor = self.currentTab.editBox.textCursor() text = cursor.selectedText() moveCursorTo = None def c(cursor): nonlocal moveCursorTo moveCursorTo = cursor.position() def ensurenl(cursor): if not cursor.atBlockStart(): cursor.insertText('\n\n') toinsert = { 'header': (ensurenl, '# ', text), 'italic': ('*', text, c, '*'), 'bold': ('**', text, c, '**'), 'underline': ('<u>', text, c, '</u>'), 'numbering': (ensurenl, ' 1. ', text), 'bullets': (ensurenl, ' * ', text), 'image': ('![', text or self.tr('Alt text'), c, '](', self.tr('URL'), ')'), 'link': ('[', text or self.tr('Link text'), c, '](', self.tr('URL'), ')'), 'inline code': ('`', text, c, '`'), 'code block': (ensurenl, ' ', text), 'blockquote': (ensurenl, '> ', text), } if formatting not in toinsert: return cursor.beginEditBlock() for token in toinsert[formatting]: if callable(token): token(cursor) else: cursor.insertText(token) cursor.endEditBlock() self.formattingBox.setCurrentIndex(0) # Bring back the focus on the editor self.currentTab.editBox.setFocus(Qt.OtherFocusReason) if moveCursorTo: cursor.setPosition(moveCursorTo) self.currentTab.editBox.setTextCursor(cursor) def insertSymbol(self, num): if num: self.currentTab.editBox.insertPlainText('&'+self.usefulChars[num-1]+';') self.symbolBox.setCurrentIndex(0) def fileChanged(self, fileName): tab = None for testtab in self.iterateTabs(): if testtab.fileName == fileName: tab = testtab if tab is None: self.fileSystemWatcher.removePath(fileName) return if not QFile.exists(fileName): self.tabWidget.setCurrentWidget(tab) tab.editBox.document().setModified(True) QMessageBox.warning(self, '', self.tr( 'This file has been deleted by other application.\n' 'Please make sure you save the file before exit.')) elif not tab.editBox.document().isModified(): # File was not modified in ReText, reload silently tab.readTextFromFile() else: self.tabWidget.setCurrentWidget(tab) text = self.tr( 'This document has been modified by other application.\n' 'Do you want to reload the file (this will discard all ' 'your changes)?\n') if self.autoSaveEnabled: text += self.tr( 'If you choose to not reload the file, auto save mode will ' 'be disabled for this session to prevent data loss.') messageBox = QMessageBox(QMessageBox.Warning, '', text) reloadButton = messageBox.addButton(self.tr('Reload'), QMessageBox.YesRole) messageBox.addButton(QMessageBox.Cancel) messageBox.exec() if messageBox.clickedButton() is reloadButton: tab.readTextFromFile() else: self.autoSaveEnabled = False tab.editBox.document().setModified(True) if fileName not in self.fileSystemWatcher.files(): # https://github.com/retext-project/retext/issues/137 self.fileSystemWatcher.addPath(fileName) def maybeSave(self, ind): tab = self.tabWidget.widget(ind) if self.autoSaveActive(tab): tab.saveTextToFile() return True if not tab.editBox.document().isModified(): return True self.tabWidget.setCurrentIndex(ind) ret = QMessageBox.warning(self, '', self.tr("The document has been modified.\nDo you want to save your changes?"), QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) if ret == QMessageBox.Save: return self.saveFile(False) elif ret == QMessageBox.Cancel: return False return True def closeEvent(self, closeevent): for ind in range(self.tabWidget.count()): if not self.maybeSave(ind): return closeevent.ignore() if globalSettings.saveWindowGeometry: globalSettings.windowGeometry = self.saveGeometry() if globalSettings.openLastFilesOnStartup: files = [tab.fileName for tab in self.iterateTabs()] writeListToSettings("lastFileList", files) globalSettings.lastTabIndex = self.tabWidget.currentIndex() closeevent.accept() def viewHtml(self): htmlDlg = HtmlDialog(self) try: _, htmltext, _ = self.currentTab.getDocumentForExport(includeStyleSheet=False) except Exception: return self.printError() winTitle = self.currentTab.getBaseName() htmlDlg.setWindowTitle(winTitle+" ("+self.tr("HTML code")+")") htmlDlg.textEdit.setPlainText(htmltext.rstrip()) htmlDlg.hl.rehighlight() htmlDlg.show() htmlDlg.raise_() htmlDlg.activateWindow() def insertImages(self): supportedExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp'] fileFilter = ' (%s);;' % ' '.join('*' + ext for ext in supportedExtensions) fileNames, _selectedFilter = QFileDialog.getOpenFileNames(self, self.tr("Select one or several images to open"), QDir.currentPath(), self.tr("Supported files") + fileFilter + self.tr("All files (*)")) cursor = self.currentTab.editBox.textCursor() imagesMarkup = '\n'.join( self.currentTab.editBox.getImageMarkup(fileName) for fileName in fileNames) cursor.insertText(imagesMarkup) self.formattingBox.setCurrentIndex(0) self.currentTab.editBox.setFocus(Qt.OtherFocusReason) def openHelp(self): QDesktopServices.openUrl(QUrl('https://github.com/retext-project/retext/wiki')) def aboutDialog(self): QMessageBox.about(self, self.aboutWindowTitle, '<p><b>' + (self.tr('ReText %s (using PyMarkups %s)') % (app_version, markups.__version__)) +'</b></p>' + self.tr('Simple but powerful editor' ' for Markdown and reStructuredText') +'</p><p>'+self.tr('Author: Dmitry Shachnev, 2011').replace('2011', '2011–2020') +'<br><a href="https://github.com/retext-project/retext">'+self.tr('Website') +'</a> | <a href="http://daringfireball.net/projects/markdown/syntax">' +self.tr('Markdown syntax') +'</a> | <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">' +self.tr('reStructuredText syntax')+'</a></p>') def setDefaultMarkup(self, markupClass): globalSettings.defaultMarkup = markupClass.name for tab in self.iterateTabs(): if not tab.fileName: tab.updateActiveMarkupClass()
def __init__(self): # self.tbl_info_model = QStandardItemModel() # self.tbl_info_model.setItem(self.DB_NAME_INDEX, QStandardItem()) # self.tbl_info_model.setItem(self.TBL_NAME_INDEX, QStandardItem()) # self.model = MysqlModel(host='zhongdian.hanson365.com', user='******', password='******') self.model = MysqlModel(host='127.0.0.1', user='******', password='******') super(QWidget, self).__init__() hbox = QHBoxLayout() operate_space_layout = QVBoxLayout() operate_space_layout.addWidget(QTextEdit()) data_view_space = QTableView() data_view_space.setModel(self.model.data_model) self.filter_editor = QLineEdit() self.filter_editor.setMinimumHeight(40) filter_apply_btn = QPushButton("apply") filter_apply_btn.setMinimumHeight(40) filter_apply_btn.clicked.connect(partial(self.filter_click)) filter_layout = QHBoxLayout() filter_layout.addWidget(self.filter_editor) filter_layout.addWidget(filter_apply_btn) # tbl_name_label = QLabel() # tbl_name_label tbl_info_tab_layout = QGridLayout() data_view_tab_layout = QVBoxLayout() data_view_tab_layout.addLayout(filter_layout) data_view_tab_layout.addWidget(data_view_space) query_splitter = QSplitter() query_splitter.addWidget(QTextEdit()) query_splitter.addWidget(QTableView()) query_view_tab_layout = QHBoxLayout() query_view_tab_layout.addWidget(query_splitter) tbl_info_tab = QWidget() data_view_tab = QWidget() query_view_tab = QWidget() query_view_tab.setLayout(query_view_tab_layout) tbl_info_tab.setLayout(tbl_info_tab_layout) data_view_tab.setLayout(data_view_tab_layout) self.operate_tab = QTabWidget() self.operate_tab.addTab(tbl_info_tab, 'INFO') self.operate_tab.addTab(data_view_tab, 'DATA') self.operate_tab.addTab(query_view_tab, 'QUERY') nav_space = QTreeView() nav_space.setColumnHidden(0, True) nav_space.setHeaderHidden(True) nav_space.setModel(self.model.schema_model) nav_space.clicked.connect(self.show_click) splitter = QSplitter() splitter.addWidget(nav_space) splitter.addWidget(self.operate_tab) splitter.setStretchFactor(1, 1) splitter.setSizes([250, 550]) hbox.addWidget(splitter) hbox.setContentsMargins(0, 0, 0, 0) self.setLayout(hbox) self.clipboard = QGuiApplication.clipboard() self.clipboard.changed.connect(self.show_clipboard) self.setStyleSheet(''' # QHeaderView::section { # background-color:#333; # color: white; # border:none; # border-left: 1px solid #aaa; # border-bottom: 1px solid #aaa; # } # QTreeView{ # color: #fff; # border:none; # background-color: #333; # } # QTableView{ # border:none; # color: #fff; # background-color: #333; # } ''')
class RedditScraperWindow(QWidget): """The main window of the program.""" ########### Setup ################################## def __init__(self): super().__init__() self.read_user_config() self.load_assets() self.initialize_ui() def load_assets(self): script_folder = os.path.dirname( os.path.dirname(os.path.abspath(__file__))) asset_folder = os.path.join(script_folder, "assets") if os.path.isdir(asset_folder): self.download_icon = QIcon( os.path.join(asset_folder, 'download_icon.png')) self.stop_icon = QIcon(os.path.join(asset_folder, 'stop_icon.png')) self.reddit_icon = QIcon( os.path.join(asset_folder, 'reddit_icon.png')) else: self.download_icon = QIcon( os.path.join("assets", 'download_icon.png')) self.stop_icon = QIcon(os.path.join("assets", 'stop_icon.png')) self.reddit_icon = QIcon(os.path.join("assets", 'reddit_icon.png')) def initialize_ui(self): """sets up the user interface, connects all the signals and shows the window. """ self.init_components() self.read_settings_config() self.connect_signals() self.setGeometry(100, 100, 1000, 800) self.setWindowTitle('Reddit Image Scraper') self.setWindowIcon(self.reddit_icon) self.show() def init_components(self): """initializes all components and sets up the layout""" internalWidgetInput = QWidget() internalWidgetTree = QWidget() ############ define components #################### self.subredditInput = QComboBox() self.subredditInput.setEditable(True) self.subredditInput.addItems(self.get_downloaded_subreddits()) self.numInput = QLineEdit() self.onlyInt = QIntValidator() self.numInput.setValidator(self.onlyInt) subredditLabel = QLabel('subreddit') numLabel = QLabel('number of images') self.dirLabel = QLabel('choose a directory') scale_label = QLabel("Scale images?") self.imgView = QLabel() self.outputText = QTextEdit('') self.outputText.setReadOnly(True) self.scale_cb = QCheckBox() self.sortingCb = QComboBox() self.sortingCb.addItems([ "Hot", "Top all time", "Top this month", "Top past year", "New", "Controversial" ]) sortingLabel = QLabel('sorting method') self.runButton = QPushButton('Download') self.runButton.setIcon(self.download_icon) self.chooseDirButton = QPushButton('Save dir') self.stopButton = QPushButton('Stop') self.stopButton.setIcon(self.stop_icon) self.fileModel = QFileSystemModel() self.tree = QTreeView() self.tree.setModel(self.fileModel) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) ############## Menu stuff ################### menu_bar = QMenuBar() file_menu = menu_bar.addMenu('File') help_menu = menu_bar.addMenu('Help') self.exit_action = QAction('Exit', self) file_menu.addAction(self.exit_action) self.help_action = QAction('Help', self) help_menu.addAction(self.help_action) menu_bar.setFixedHeight(30) ############# Setup the grid layout############################### grid = QGridLayout() # grid.addWidget(menu_bar, 1, 0, 1, 4) grid.setSpacing(4) grid.addWidget(subredditLabel, 1, 0) grid.addWidget(self.subredditInput, 1, 1) grid.addWidget(numLabel, 2, 0) grid.addWidget(self.numInput, 2, 1) grid.addWidget(sortingLabel, 3, 0) grid.addWidget(self.sortingCb, 3, 1) grid.addWidget(self.chooseDirButton, 4, 0) grid.addWidget(self.dirLabel, 4, 1) grid.addWidget(self.stopButton, 5, 0) grid.addWidget(self.runButton, 5, 1) grid.addWidget(self.outputText, 7, 0, 7, 2) # grid.addWidget(self.tree,1,2, 11,7) grid.addWidget(scale_label, 6, 0) grid.addWidget(self.scale_cb, 6, 1) hboxTree = QVBoxLayout() hboxTree.addWidget(self.tree) #the image viewer, setting how it behaves under resizing. self.imgView.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) self.imgView.setMaximumHeight(MAX_IMAGE_HEIGHT) self.imgView.setAlignment(Qt.AlignmentFlag.AlignCenter) img_scroll_area = QScrollArea() img_scroll_area.setMinimumHeight(MAX_IMAGE_HEIGHT) img_scroll_area.setMinimumWidth(MAX_IMAGE_HEIGHT) img_scroll_area.setWidget(self.imgView) internalWidgetInput.setLayout(grid) # internalWidgetInput.setMinimumWidth(300) internalWidgetInput.setFixedWidth(300) internalWidgetInput.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)) internalWidgetTree.setLayout(hboxTree) internalWidgetTree.setFixedWidth(360) internalWidgetTree.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)) #construct layout of main window. hbox = QHBoxLayout() hbox.setSpacing(0) hbox.setContentsMargins(0, 0, 0, 0) hbox.setMenuBar(menu_bar) hbox.addWidget(internalWidgetInput) hbox.addWidget(internalWidgetTree) hbox.addWidget(img_scroll_area) self.setLayout(hbox) def connect_signals(self): """connects all the signals to the right functions""" self.chooseDirButton.clicked.connect(self.show_dir_dialog) self.runButton.clicked.connect(self.run_download_threaded) self.tree.clicked.connect(self.on_treeView_clicked) self.stopButton.clicked.connect(self.stop_download) self.scale_cb.clicked.connect(self.refresh_image) self.exit_action.triggered.connect(exit) #self.edit_login_action.triggered.connect(self.edit_login_info) self.help_action.triggered.connect(self.show_help) self.tree.selectionModel().selectionChanged.connect( self.on_selection_change) def read_user_config(self): """reads in the users username and password from the config file, or if there is no config file, shows an input dialog. Also tests so that only valid login information gets saved to the config file. """ config = configparser.ConfigParser() self.redditScraper = redditScraper() if os.path.exists('redditScraper.ini'): config.read('redditScraper.ini') if 'DIR' in config: self.folder = config['DIR']['root_folder'] else: config['REDDIT'] = { 'subreddit': "wallpapers", 'num': 10, 'sorting': "Hot", 'downloaded_subreddits': "" } with open('redditScraper.ini', 'w') as configfile: config.write(configfile) self.config = config def read_settings_config(self): """reads the saved settings from the config file, if they're there.""" if 'DIR' in self.config: self.folder = self.config['DIR']['root_folder'] idx = self.fileModel.setRootPath(str(self.folder)) self.tree.setRootIndex(idx) self.dirLabel.setText(self.folder) if 'REDDIT' in self.config: self.subredditInput.setCurrentText( self.config['REDDIT']['subreddit']) self.numInput.setText(self.config['REDDIT']['num']) self.sortingCb.setCurrentText(self.config['REDDIT']['sorting']) ################### Actions: ################## @pyqtSlot(QModelIndex) def on_treeView_clicked(self, index): """triggers when the user clicks on a file item shown in the treeView, and shows that file in the picture viewer.""" index = self.fileModel.index(index.row(), 0, index.parent()) self.show_image(index) def on_selection_change(self, selected: QItemSelection, deselected: QItemSelection): """ Triggers when the selected item in the treeview changes, and updates the shown picture. """ self.refresh_image() def refresh_image(self): selected_image_index = self.tree.selectedIndexes()[0] self.show_image(selected_image_index) def show_image(self, index: QModelIndex): filePath = self.fileModel.filePath(index) if os.path.isfile(filePath) and filePath.split(".")[-1] in [ "jpg", "gif", "png", "jpeg" ]: pixmap = QPixmap(filePath) if self.scale_cb.isChecked(): self.imgView.setFixedHeight(MAX_IMAGE_HEIGHT) scaled_img = pixmap.scaledToHeight(MAX_IMAGE_HEIGHT) self.imgView.setFixedWidth(scaled_img.width()) self.imgView.setPixmap(scaled_img) else: self.imgView.setFixedHeight(pixmap.height()) self.imgView.setFixedWidth(pixmap.width()) self.imgView.setPixmap(pixmap) def show_dir_dialog(self): """lets the user select the root folder, and saves the choice to the config file.""" self.folder = QFileDialog.getExistingDirectory( self, 'Choose base directory', '/home') self.dirLabel.setText(self.folder) self.config['DIR'] = {'root_folder': self.folder} with open('redditScraper.ini', 'w') as configfile: self.config.write(configfile) idx = self.fileModel.setRootPath(self.folder) self.tree.setRootIndex(idx) return self.folder @pyqtSlot(str) def update_output_text(self, message: str): """updates the output text area, to show progress on downloads.""" self.outputText.setText(message + self.outputText.toPlainText()) def save_subreddit(self, subreddit: str, num: int, sorting: str): """helper function to save the current settings to the config file.""" downloaded_subreddits = self.get_downloaded_subreddits() if subreddit not in downloaded_subreddits: downloaded_subreddits.append(subreddit) self.subredditInput.addItem(subreddit) downloaded_subreddits = ','.join(downloaded_subreddits) self.config['REDDIT'] = { 'subreddit': subreddit, 'num': str(num), 'sorting': sorting, 'downloaded_subreddits': downloaded_subreddits } with open('redditScraper.ini', 'w') as configfile: self.config.write(configfile) def get_downloaded_subreddits(self) -> list: if 'downloaded_subreddits' in self.config['REDDIT'].keys(): subreddits = self.config['REDDIT']['downloaded_subreddits'].split( ',') return subreddits return [] def run_download_threaded(self): """downloads the pictures. Runs in a QThread, so that the program does not freeze. Also checks whether the specified subreddit exists. """ subreddit = self.subredditInput.currentText() num = int(self.numInput.text()) sorting = self.sortingCb.currentText() if self.redditScraper.sub_exists(subreddit): if not hasattr(self, "folder"): msgBox = QMessageBox() msgBox.setText('You need to set a download folder!') msgBox.setWindowTitle("Pick a download folder") msgBox.exec_() return self.save_subreddit(subreddit, num, sorting) self.get_thread = RedditDownloadThread( self.redditScraper, subreddit, num, num * LOOKUP_LIMIT_MULTIPLIER, sorting, self.folder) self.get_thread.changeText.connect(self.update_output_text) self.get_thread.start() else: msgBox = QMessageBox() msgBox.setText('That subreddit does not exist, please try again') msgBox.setWindowTitle("Invalid subreddit") msgBox.exec_() pass def stop_download(self): """Stops the download thread and prints a message to the output.""" try: if self.get_thread.isRunning(): self.get_thread.terminate() self.outputText.setText(self.outputText.toPlainText() + ' Aborted!\n') except Exception: pass ############### Menu actions: ############### def show_help(self): msgBox = QMessageBox() msgBox.setWindowIcon(self.reddit_icon) msgBox.setText( 'This program downloads images posted to reddit.com, or more specifically, to subreddits' + '(i.e. sub-forums). To use it, one needs a valid reddit account, which one can sign up for ' + 'on reddit.com. One also needs to know some names of subreddits. \n Some suggestions for subreddits: ' + 'wallpapers , earthporn , nature , and pics . \n \n ' + "This program will download up to the specified number of images. It can handle png, jpg and gif," + "so links to gyf-files, videos or anything else will be ignored. Therefore the number of images actually " + "downloaded will usually be less than the specified number. So if you want a lot of images, just put" + " a large limit.\n The images will be placed in a subfolder of the chosen base folder, named after the subreddit. This folder will be created if it does not exist.\n \n " + "To view the images, click on them in the tree-view, and they will appear on the right" ) msgBox.setWindowTitle("Help") msgBox.exec_()
class App(QWidget): def __init__(self): super().__init__() self.left = 100 self.top = 100 self.width = 1200 self.height = 720 self.setWindowTitle('Mammogram Prediction') self.setGeometry(self.left, self.top, self.width, self.height) self.initUI() def initUI(self): # Widget for showing picture. The QLabel gets a Pixmap added to it to show picture self.picture_name_label = QLabel(currently_selected_picture) self.picture_label = QLabel() self.prediction_text = QTextEdit() self.prediction_text.setReadOnly(True) self.model_label = QLabel() self.init_picture_and_predictions() self.resized_picture = self.picture.scaled(299, 299, Qt.KeepAspectRatio, Qt.FastTransformation) self.picture_label.setPixmap(self.resized_picture) self.picture_label.setMinimumWidth(299) self.picture_label.setMinimumHeight(299) self.picture_label.setContentsMargins(0, 19, 0, 0) # Tree and List view for file directory overview of pictures self.picture_directory_label = QLabel('Select a Picture:') picture_dir_path = 'pictures\\' picture_file_path = 'pictures\\' self.treeview_picture = QTreeView() self.listview_picture = QListView() self.dirModel_picture = QFileSystemModel() self.dirModel_picture.setRootPath(picture_dir_path) self.dirModel_picture.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.fileModel_picture = QFileSystemModel() self.fileModel_picture.setRootPath(picture_file_path) # self.fileModel_picture.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.treeview_picture.setModel(self.dirModel_picture) self.listview_picture.setModel(self.fileModel_picture) self.treeview_picture.setRootIndex( self.dirModel_picture.index(picture_dir_path)) self.listview_picture.setRootIndex( self.fileModel_picture.index(picture_file_path)) # self.treeview_picture.setCurrentIndex( self.dirModel_picture.index(0, 0)) self.treeview_picture.clicked.connect( self.on_picture_treeview_clicked) self.listview_picture.clicked.connect( self.on_picture_listview_clicked) self.treeview_picture.setColumnHidden(1, True) self.treeview_picture.setColumnWidth(0, 275) self.treeview_picture.setMinimumWidth(500) self.listview_picture.setMinimumWidth(500) # List view for file directory overview of five label models self.model_directory_label = QLabel('Select a Five Label Model:') model_path = 'trained_five_Models\\' self.listview_model = QListView() self.dirModel_model = QFileSystemModel() self.dirModel_model.setRootPath(model_path) self.dirModel_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.listview_model.setModel(self.dirModel_model) self.listview_model.setRootIndex( self.dirModel_model.index(model_path)) self.listview_model.clicked.connect(self.on_model_listview_clicked) # List view for file directory overview of binary models self.model_binary_directory_label = QLabel( 'Select a Binary Model:') model_binary_path = 'trained_binary_Models\\' self.listview_model_binary = QListView() self.dirModel_model_binary = QFileSystemModel() self.dirModel_model_binary.setRootPath(model_binary_path) self.dirModel_model_binary.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.listview_model_binary.setModel(self.dirModel_model_binary) self.listview_model_binary.setRootIndex( self.dirModel_model_binary.index(model_binary_path)) self.listview_model_binary.setSelectionMode( QAbstractItemView.MultiSelection) self.listview_model_binary.clicked.connect( self.on_model_binary_listview_clicked) # Layout handling. # self.gridlayout = QGridLayout() # self.gridlayout.addWidget(self.model_directory_label, 0, 0) # self.gridlayout.setColumnStretch(-15, -11) # self.gridlayout.addWidget(self.listview_model, 1, 0) # self.gridlayout.addWidget(self.picture_directory_label, 2, 0) # self.gridlayout.addWidget(self.treeview_picture, 3, 0) # # self.gridlayout.addWidget(self.model_binary_directory_label, 0, 1) # self.gridlayout.addWidget(self.listview_model_binary, 1, 1) # self.gridlayout.addWidget(self.listview_picture, 3, 1) # # self.gridlayout.addWidget(self.picture_label, 0, 2) # self.gridlayout.addWidget(self.picture_name_label, 1, 2) # self.gridlayout.addWidget(self.prediction_text, 3, 2) self.vbox = QVBoxLayout() self.vbox_left = QVBoxLayout() self.vbox_right = QVBoxLayout() self.hbox_outer = QHBoxLayout() self.hbox_top = QHBoxLayout() self.hbox_buttom = QHBoxLayout() self.vbox_five_label = QVBoxLayout() self.vbox_binary = QVBoxLayout() self.vbox.addLayout(self.hbox_outer) self.hbox_outer.addLayout(self.vbox_left) self.hbox_outer.addLayout(self.vbox_right) self.vbox_left.addLayout(self.hbox_top) self.hbox_top.addLayout(self.vbox_five_label) self.hbox_top.addLayout(self.vbox_binary) self.vbox_five_label.addWidget(self.model_directory_label) self.vbox_five_label.addWidget(self.listview_model) self.vbox_binary.addWidget(self.model_binary_directory_label) self.vbox_binary.addWidget(self.listview_model_binary) self.vbox_left.addWidget(self.picture_directory_label) self.vbox_left.addLayout(self.hbox_buttom) self.hbox_buttom.addWidget(self.treeview_picture) self.hbox_buttom.addWidget(self.listview_picture) self.vbox_right.addWidget(self.picture_label, alignment=Qt.AlignHCenter) self.vbox_right.addWidget(self.picture_name_label, alignment=Qt.AlignHCenter) self.vbox_right.addWidget(self.model_label, alignment=Qt.AlignHCenter) self.vbox_right.addWidget(self.prediction_text) self.vbox_right.setAlignment(Qt.AlignCenter) self.setLayout(self.vbox) self.sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) self.setSizePolicy(self.sizePolicy) self.show() def init_picture_and_predictions(self): if currently_selected_picture == 'Currently No Image Selected': self.picture = QtGui.QPixmap('GUI/no_image_selected.png') self.prediction_text.setText('') def on_picture_treeview_clicked(self, index): pathof_selected_dir = self.dirModel_picture.fileInfo( index).absoluteFilePath() self.listview_picture.setRootIndex( self.fileModel_picture.setRootPath(pathof_selected_dir)) def on_picture_listview_clicked(self, index): global currently_selected_model global currently_selected_model_name global currently_selected_picture currently_selected_picture = self.fileModel_picture.fileInfo( index).absoluteFilePath() try: Image.open(currently_selected_picture) self.picture_name_label.setText(currently_selected_picture) self.picture_label.setPixmap( QtGui.QPixmap(currently_selected_picture)) except IOError: print('Exception: Chosen file is not a picture') # Checks if the selected picture has size 299 image_in = cv2.imread(currently_selected_picture) size = image_in.shape[:2] if size[0] == 299: if currently_selected_model is not None: for model in currently_selected_model: new_prediction = self.makePrediction( model, self.convertPictureToNumpy( currently_selected_picture)) split = currently_selected_model_name.split('_') if split[4] in ('neg', 'bc', 'bm', 'mc', 'mm'): self.show_binary_prediction( new_prediction, split[4]) else: self.show_five_prediction(new_prediction) else: self.prediction_text.setText( 'No Model is Chosen for Prediction. Choose one to the left.' ) # If the selected picture is not size 299 it will be padded and cropped else: cropped_images = resize_image_padding( currently_selected_picture) self.listview_picture.setRootIndex( self.fileModel_picture.setRootPath('pictures/cropped/%s' % cropped_images)) def on_model_listview_clicked(self, index): global currently_selected_model global currently_selected_picture currently_selected_model = [] selected_model_path = self.dirModel_model.fileInfo( index).absoluteFilePath() currently_selected_model.append(self.getModel(selected_model_path)) self.model_label.setText(currently_selected_model_name[0]) if currently_selected_picture != 'Currently No Image Selected': for model in currently_selected_model: new_prediction = self.makePrediction( model, self.convertPictureToNumpy(currently_selected_picture)) self.show_five_prediction(new_prediction) def on_model_binary_listview_clicked(self): global currently_selected_model global currently_selected_picture currently_selected_model = [] self.prediction_text.setText('') self.model_label.setText('') for x in self.listview_model_binary.selectedIndexes(): selected_model_path = self.dirModel_model_binary.fileInfo( x).absoluteFilePath() currently_selected_model.append( self.getModel(selected_model_path)) # if not currently_selected_model_name: # self.model_label.setText(currently_selected_model_name) if currently_selected_picture != 'Currently No Image Selected': for y in currently_selected_model: new_prediction = self.makePrediction( y, self.convertPictureToNumpy(currently_selected_picture)) self.show_binary_prediction(new_prediction, y.category) def getModel(self, model_path): global currently_selected_model_name currently_selected_model_name = [] split = os.path.split(model_path)[1].split('_') model_version = split[0] + '_' + split[1] + '_' + split[ 2] + '_' + split[3] currently_selected_model_name.append(os.path.split(model_path)[1]) model = getattr(sys.modules[__name__], model_version)() checkpoint_path = model_path + '/cp.ckpt' model.load_weights(checkpoint_path) return model def makePrediction(self, input_model, input_picture): image = tf.reshape(input_picture, [-1, 299, 299, 1]) image = tf.cast(image, tf.float32) image = image / 255.0 return input_model.predict(image) def convertPictureToNumpy(self, filename): img = Image.open(filename) np_array = np.array(img, dtype='uint8') return np_array def show_five_prediction(self, prediction): self.prediction_text.setText( "Probability of Negative: %s" % prediction[0, 0] + "\n\nProbability of Benign Calcification: %s" % prediction[0, 1] + "\n\nProbability of Benign Mass: %s" % prediction[0, 2] + "\n\nProbability of Malignant Calcification: %s" % prediction[0, 3] + "\n\nProbability of Malignant Mass: %s" % prediction[0, 4]) def show_binary_prediction(self, prediction, category): if category == 'neg': self.prediction_text.append( "Probability of Negative: %s %s \n" % (prediction[0, 0], prediction[0, 1])) elif category == 'bc': self.prediction_text.append( "Probability of Benign Calcification: %s %s \n" % (prediction[0, 0], prediction[0, 1])) elif category == 'bm': self.prediction_text.append( "Probability of Benign Mass: %s %s \n" % (prediction[0, 0], prediction[0, 1])) elif category == 'mc': self.prediction_text.append( "Probability of Malignant Calcification: %s %s \n" % (prediction[0, 0], prediction[0, 1])) elif category == 'mm': self.prediction_text.append( "Probability of Malignant Mass: %s %s \n" % (prediction[0, 0], prediction[0, 1])) else: self.prediction_text.append( "Probability of ????: %s %s \n" % (prediction[0, 0], prediction[0, 1])) def openFileDialog(self): fileName, _ = QFileDialog.getOpenFileName( self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)") if fileName: return fileName def is_png(data): return data[:8] == '\x89PNG\x0d\x0a\x1a\x0a'
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(970, 650) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) self.horizontalLayout.setObjectName("horizontalLayout") self.splitter = QtWidgets.QSplitter(self.centralwidget) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setHandleWidth(1) self.splitter.setObjectName("splitter") self.horizontalLayout.addWidget(self.splitter) MainWindow.setCentralWidget(self.centralwidget) # 文件树形目录浏览器 self.tree = QTreeView() self.model = QtWidgets.QFileSystemModel() self.model.setRootPath('') self.nameFile = ["*.png", "*.jpg", "*.jpeg"] self.model.setNameFilterDisables(False) self.model.setNameFilters(self.nameFile) self.tree.setModel(self.model) self.tree.setAnimated(False) self.tree.setIndentation(20) self.tree.setWindowTitle("Dir View") self.tree.setSortingEnabled(True) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.tree.doubleClicked.connect(self.openFileFromTreeList) # 图库管理器 self.tree_2 = QTreeWidget() self.tree_2.setColumnCount(1) # 设置表头信息:隐藏表头 self.tree_2.setHeaderHidden(1) # 设置root和root2为self.tree的子树,所以root和root2就是跟节点 root = QTreeWidgetItem(self.tree_2) root2 = QTreeWidgetItem(self.tree_2) # 设置根节点的名称 root.setText(0, '第一节点') root2.setText(0, '第二节点') # 为root节点设置子结点 child1 = QTreeWidgetItem(root) child1.setText(0, 'child1') child1.setText(1, 'name1') child2 = QTreeWidgetItem(root) # 设置child2节点的图片 child2.setText(0, 'child2') child2.setText(1, 'name2') # 实例化QToolBox self.toolBox = QToolBox() # 设置左侧导航栏 toolBox 在左右拉拽时的最小宽度 self.toolBox.setMinimumWidth(100) # 给QToolBox添加两个子项目 self.toolBox.addItem(self.tree, "文件资源") self.toolBox.addItem(self.tree_2, "图库") # 给QSplitter添加第一个窗体(QToolBox) self.splitter.addWidget(self.toolBox) #菜单栏 self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(10, 10, 820, 30)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.menu1_file = QtWidgets.QMenu(self.menubar) self.menu1_file.setObjectName("menu1_file") self.menu2_edit = QtWidgets.QMenu(self.menubar) self.menu2_edit.setObjectName("menu2_edit") self.menu3_imageLib = QtWidgets.QMenu(self.menubar) self.menu3_imageLib.setObjectName("menu3_imageLib") self.menu4_image = QtWidgets.QMenu(self.menubar) self.menu4_image.setObjectName("menu4_image") self.menu6_user = QtWidgets.QMenu(self.menubar) self.menu6_user.setObjectName("menu6_user") self.menu5_help = QtWidgets.QMenu(self.menubar) self.menu5_help.setObjectName("menu5_help") MainWindow.setMenuBar(self.menubar) #menu Action #################action1###################### self.action_1_1 = QtWidgets.QAction(MainWindow) self.action_1_1.setObjectName("action_1_1") #打开 self.action_1_1.triggered.connect(self.openfile) self.action_1_2 = QtWidgets.QAction(MainWindow) self.action_1_2.setObjectName("action_1_2") #保存 self.action_1_3 = QtWidgets.QAction(MainWindow) self.action_1_3.setObjectName("action_1_3") #退出 #################action2###################### self.action_2_1 = QtWidgets.QAction(MainWindow) self.action_2_1.setObjectName("action_2_1") #图片编辑 self.action_2_1.triggered.connect(self.openChildWindow) #################action3###################### self.action_3_1 = QtWidgets.QAction(MainWindow) self.action_3_1.setObjectName("action_3_1") #图库管理器 self.action_3_1.triggered.connect(self.imageLibUi) #################action4###################### self.action_4_1 = QtWidgets.QAction(MainWindow) self.action_4_1.setObjectName("action_4_1") # 添加图片 self.action_4_2 = QtWidgets.QAction(MainWindow) self.action_4_2.setObjectName("action_4_2") # 删除图片 self.action_4_3 = QtWidgets.QAction(MainWindow) self.action_4_3.setObjectName("action_4_3") # 重命名 #################action5###################### self.action_5 = QtWidgets.QAction(MainWindow) self.action_5.setObjectName("action_5") #帮助 #################action6###################### self.action_6 = QtWidgets.QAction(MainWindow) self.action_6.setObjectName("action_6") #用户管理 self.action_6.triggered.connect(self.userManager) #给menu添加Action self.menu1_file.addAction(self.action_1_1) #打开 self.menu1_file.addAction(self.action_1_2) #保存 self.menu1_file.addAction(self.action_1_3) #退出 self.menu2_edit.addAction(self.action_2_1) #图片编辑 self.menu3_imageLib.addAction(self.action_3_1) #图库管理器 self.menu4_image.addAction(self.action_4_1) #添加图片 self.menu4_image.addAction(self.action_4_2) #删除图片 self.menu4_image.addAction(self.action_4_3) #重命名 self.menu6_user.addAction(self.action_6) #用户管理 self.menu5_help.addAction(self.action_5) #帮助 self.menubar.addAction(self.menu1_file.menuAction()) self.menubar.addAction(self.menu2_edit.menuAction()) self.menubar.addAction(self.menu3_imageLib.menuAction()) self.menubar.addAction(self.menu4_image.menuAction()) self.menubar.addAction(self.menu5_help.menuAction()) self.menubar.addAction(self.menu6_user.menuAction()) #Icon icon = QtGui.QIcon() icon2 = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("Icon/openfile.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon2.addPixmap(QtGui.QPixmap("Icon/edit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action_1_1.setIcon(icon) self.action_2_1.setIcon(icon2) #工具栏 self.toolBar = QtWidgets.QToolBar(MainWindow) self.toolBar.setInputMethodHints(QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhSensitiveData) self.toolBar.setObjectName("toolBar") MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.toolBar.addAction(self.action_1_1) self.toolBar.addAction(self.action_2_1) #状态栏 self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) #初始化默认窗体 #初始化默认窗体(图片显示窗体) self.imageView = ImageView() # 在主窗口里添加子窗口 self.splitter.addWidget(self.imageView) #是普通用户还是管理员 self self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # 创建默认存放文件的文件夹: cur_dir = "C:" folder_name = 'InfraredImage' if os.path.isdir("C:/InfraredImage"): print("Already exist!") else: os.mkdir(os.path.join(cur_dir, folder_name)) os.mkdir("C:/InfraredImage/TmpImg") def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "红外图像质量客观评价系统V1.0")) #导航栏名字 self.menu1_file.setTitle(_translate("MainWindow", "文件")) self.menu3_imageLib.setTitle(_translate("MainWindow", "图库管理")) self.menu4_image.setTitle(_translate("MainWindow", "图片管理")) self.menu2_edit.setTitle(_translate("MainWindow", "编辑")) self.menu6_user.setTitle(_translate("MainWindow", "用户管理")) self.menu5_help.setTitle(_translate("MainWindow", "帮助")) #action名字 self.action_1_1.setText(_translate("MainWindow", "打开")) self.action_1_1.setShortcut(_translate("MainWindow", "Ctrl+O")) self.action_1_2.setText(_translate("MainWindow", "保存")) self.action_1_2.setShortcut(_translate("MainWindow", "Ctrl+S")) self.action_1_3.setText(_translate("MainWindow", "退出")) self.action_1_3.setShortcut(_translate("MainWindow", "Ctrl+E")) self.action_2_1.setText(_translate("MainWindow", "编辑图片")) self.action_3_1.setText(_translate("MainWindow", "图库管理器")) self.action_4_1.setText(_translate("MainWindow", "添加图片")) self.action_4_2.setText(_translate("MainWindow", "删除图片")) self.action_4_3.setText(_translate("MainWindow", "重命名")) self.action_5.setText(_translate("MainWindow", "Help ?")) self.action_6.setText(_translate("MainWindow", "用户管理器")) self.statusbar.showMessage("Ready") ##########################功能函数区############################### def openfile(self): # 设置文件扩展名过滤,注意用双分号间隔 fileName1, filetype = QFileDialog.getOpenFileName( None, "选取文件", "C:/", "All Files (*);;Image (*.png *.jpg *.jpeg)") #显示图片,并初始化图片基本信息 self.openImage(fileName1) # 从文件资源目录树打开图片 def openFileFromTreeList(self, Qmodelidx): filePath = self.model.filePath(Qmodelidx) self.openImage(filePath) # 打开图片,并初始化图片基本信息 def openImage(self, filePath): self.action_2_1.setEnabled(True) self.splitter.widget(1).setParent(None) self.splitter.insertWidget(1, self.imageView) img = QtGui.QPixmap(filePath).scaled( self.imageView.graphicsView.width(), self.imageView.graphicsView.height()) self.imageView.graphicsView.setPixmap(img) self.newPic = Image.open(filePath) self.statusbar.showMessage("打开图片") self.imageView.listWidget.item(1).setText("大小: " + str(self.newPic.size)) self.imageView.listWidget.item(2).setText("色彩通道: " + self.newPic.mode) self.imageView.listWidget.item(3).setText("格式: " + self.newPic.format) self.imageView.listWidget.item(4).setText( "像素: " + str(self.newPic.getextrema())) self.imageView.listWidget.item(5).setText("文件: " + str(filePath)) # # 要把新打开的图片,和所有修改过的图片,都存进tempPic.jpg里面,作为一个中间变量。 self.newPic.save("C:/InfraredImage/TmpImg/tempPic.png") self.newPic = "C:/InfraredImage/TmpImg/tempPic.png" # 打开图片处理子窗口函 def openChildWindow(self): childUi = childWindow() if childUi.exec_() == QtWidgets.QDialog.Accepted: pass #打开图库管理窗口 def imageLibUi(self): self.imageLibUi = ImageLibUi() # 把QSplitter的指定位置的窗体从QSplitter中剥离 self.splitter.widget(1).setParent(None) # 在QSplitter的指定位置载入新窗体 self.splitter.insertWidget(1, self.imageLibUi) # 打开图库管理窗口时将图片编辑器设为不可用 self.action_2_1.setEnabled(False) #用户管理 def userManager(self): self.userWindow = UserManagerUi() # 把QSplitter的指定位置的窗体从QSplitter中剥离 self.splitter.widget(1).setParent(None) # 在QSplitter的指定位置载入新窗体 self.splitter.insertWidget(1, self.userWindow) # 打开图库管理窗口时将图片编辑器设为不可用 self.action_2_1.setEnabled(False)
class Navigation(QWidget): """ Navigation class definition. Provide a combobox to switch on each opened directories and display it into a tree view Provide 2 useful function (to use in alter module): - add_action(name, shortcut, callback) - callback take 2 arguments : file_info and parent - add_separator() """ SETTINGS_DIRECTORIES = 'navigation_dirs' SETTINGS_CURRENT_DIR = 'navigation_current_dir' onFileItemActivated = pyqtSignal(QFileInfo, name="onFileItemActivated") onDirItemActivated = pyqtSignal(QFileInfo, name="onDirItemActivated") def __init__(self, parent=None): super(Navigation, self).__init__(parent) self.setObjectName("Navigation") self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.menu_button = QPushButton('Select directory', self) self.menu_button.setFlat(True) # self.menu_button.clicked.connect(self.on_menu_button_clicked) self.menu = QMenu(self) self.menu_button.setMenu(self.menu) self.menu_directories = QMenu(self) self.menu_directories.setTitle('Directories') self.menu_add_action('Open directory', self.open_directory, None, QKeySequence.Open) self.menu_add_separator() self.menu_add_action('Refresh', self.reset, None, QKeySequence.Refresh) # @TODO invoke_all self.menu_add_separator() self.menu.addMenu(self.menu_directories) self.tree = QTreeView(self) self.model = FileSystemModel(self) self.tree.setModel(self.model) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) self.tree.setColumnHidden(3, True) self.tree.setHeaderHidden(True) # only to expand directory or activated with one click self.tree.clicked.connect(self.on_item_clicked) # else, for file use activated signal self.tree.activated.connect(self.on_item_activated) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self.on_context_menu) self.widgets = collections.OrderedDict() self.widgets['menu_button'] = self.menu_button self.widgets['tree'] = self.tree # @ToDo: Alter.invoke_all('add_widget', self.widgets) for name, widget in self.widgets.items(): if name == 'menu_button': self.layout.addWidget(widget, 0, Qt.AlignLeft) else: self.layout.addWidget(widget) self.context_menu = QMenu(self) self.add_action('New file', QKeySequence.New, FileSystemHelper.new_file) self.add_separator() self.add_action('Copy', QKeySequence.Copy, FileSystemHelper.copy) self.add_action('Cut', QKeySequence.Cut, FileSystemHelper.cut) self.add_action('Paste', QKeySequence.Paste, FileSystemHelper.paste) self.add_separator() self.add_action('Delete', QKeySequence.Delete, FileSystemHelper.delete) # @ToDo Alter.invoke_all('navigation_add_action', self) #restore previous session and data dirs = ModuleManager.core['settings'].Settings.value( self.SETTINGS_DIRECTORIES, None, True) for directory_path in dirs: name = os.path.basename(directory_path) self.menu_add_directory(name, directory_path) current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() self.menu_button.setFocusPolicy(Qt.NoFocus) self.menu_button.setFocusProxy(self.tree) def reset(self, file_info): self.model.beginResetModel() current_dir = ModuleManager.core['settings'].Settings.value( self.SETTINGS_CURRENT_DIR, '') if current_dir: for action in self.menu_directories.actions(): if action.data() == current_dir: action.trigger() def on_menu_button_clicked(self): pos = self.mapToGlobal(self.menu_button.pos()) menu_width = self.menu.sizeHint().width() pos.setY(pos.y() + self.menu_button.height()) # pos.setX(pos.x() + self.menu_button.width() - menu_width) if len(self.menu.actions()) > 0: self.menu.exec(pos) def menu_add_action(self, name, callback, data=None, shortcut=None, icon=None): action = QAction(name, self) if icon: action.setIcon(icon) if shortcut: action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) if data: action.setData(data) action.triggered.connect(callback) self.addAction(action) self.menu.addAction(action) def menu_add_directory(self, name, data): action = QAction(name, self) action.setData(data) action.triggered.connect(self.on_menu_action_triggered) self.menu_directories.addAction(action) return action def menu_add_separator(self): self.menu.addSeparator() def add_action(self, name, shortcut, callback, icon=None): """ Ajoute une action au context menu et au widget navigation lui même. Créer une fonction à la volé pour fournir des arguments aux fonctions associé aux actions. """ action = QAction(name, self) if icon: action.setIcon(icon) action.setShortcut(shortcut) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.__wrapper(callback)) self.addAction(action) self.context_menu.addAction(action) def add_separator(self): """Simple abstraction of self.context_menu.addSeparator()""" self.context_menu.addSeparator() def __wrapper(self, callback): def __new_function(): """ __new_function représente la forme de tous les callbacks connecté à une action pour pouvoir utiliser les raccourcis en même temps que le menu contextuel. """ action = self.sender() file_info = action.data() if not file_info: indexes = self.tree.selectedIndexes() if indexes: model_index = indexes[0] file_info = self.model.fileInfo(model_index) callback(file_info, self) elif action.shortcut() == QKeySequence.New: file_info = self.model.fileInfo(self.tree.rootIndex()) callback(file_info, self) else: callback(file_info, self) action.setData(None) return __new_function def question(self, text, informative_text=None): message_box = QMessageBox(self) message_box.setText(text) if informative_text: message_box.setInformativeText(informative_text) message_box.setStandardButtons(QMessageBox.No | QMessageBox.Yes) message_box.setDefaultButton(QMessageBox.No) return message_box.exec() def on_context_menu(self, point): model_index = self.tree.indexAt(point) file_info = self.model.fileInfo(model_index) # pour chaque action on met a jour les data (file_info) # puis on altère les actions (ex enabled) for action in self.context_menu.actions(): if not action.isSeparator(): action.setData(file_info) action.setEnabled(model_index.isValid()) if action.shortcut() == QKeySequence.New: action.setEnabled(True) if not model_index.isValid(): file_info = self.model.fileInfo(self.tree.rootIndex()) action.setData(file_info) if action.shortcut() == QKeySequence.Paste: enable = FileSystemHelper.ready() and model_index.isValid() action.setEnabled(enable) if action.shortcut() == QKeySequence.Delete: # remove directory only if is an empty directory if model_index.isValid() and file_info.isDir(): path = file_info.absoluteFilePath() # QDir(path).count() always contains '.' and '..' action.setEnabled(QDir(path).count() == 2) # @ToDo #Alter.invoke_all( # 'navigation_on_menu_action', # model_index, file_info, action, self) if len(self.context_menu.actions()) > 0: self.context_menu.exec(self.tree.mapToGlobal(point)) # reset action data, sinon y a des problèmes dans _new_function for action in self.context_menu.actions(): action.setData(None) def on_item_activated(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) else: self.onFileItemActivated.emit(qFileInfo) def on_item_clicked(self, index): qFileInfo = self.model.fileInfo(index) if qFileInfo.isDir(): self.onDirItemActivated.emit(qFileInfo) self.tree.setExpanded(index, not self.tree.isExpanded(index)) else: self.onFileItemActivated.emit(qFileInfo) def open_directory(self): path = QFileDialog.getExistingDirectory(self, "Open Directory", ".") if path: name = os.path.basename(path) action = self.menu_add_directory(name, path) self.save_directories_path() action.trigger() def on_menu_action_triggered(self): action = self.sender() path = action.data() if path: self.model.setRootPath(path) self.tree.setRootIndex(self.model.index(path)) self.menu_button.setText(os.path.basename(path)) self.save_current_dir(path) def save_directories_path(self): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_DIRECTORIES, [action.data() for action in self.menu_directories.actions()]) def save_current_dir(self, path): ModuleManager.core['settings'].Settings.set_value( self.SETTINGS_CURRENT_DIR, path)
class LogInspectorWindow(QMainWindow): def __init__(self, configFilePath, parent=None): super(LogInspectorWindow, self).__init__(parent) self.initMatPlotLib() self.configFilePath = configFilePath folder = os.path.dirname(self.configFilePath) if not os.path.exists(folder): os.makedirs(folder) if os.path.exists(self.configFilePath): # config.yaml found. Read from file. file = open(self.configFilePath, 'r') self.config = yaml.safe_load(file) file.close() else: # config.yaml not found. Create new file. self.config = {} self.config['logs_directory'] = os.path.join( os.path.expanduser("~"), "Documents", "Inertial_Sense", "Logs") self.config['directory'] = "" self.config['serials'] = ["ALL"] file = open(self.configFilePath, 'w') yaml.dump(self.config, file) file.close() self.currently_selected = 'posNEDMap' self.downsample = 5 self.plotargs = None self.log = None self.plotter = None def initMatPlotLib(self): self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.figure.subplots_adjust(left=0.05, right=0.99, bottom=0.05, top=0.91, wspace=0.2, hspace=0.2) def addButton(self, name, function, multithreaded=True, layout=None): setattr(self, name + "button", QPushButton(name)) # if multithreaded: # setattr(self, name+"buttonThread", Thread(target=function)) # getattr(self, name+"button").pressed.connect(self.startLoadingIndicator) # getattr(self, name+"button").released.connect(getattr(self, name+"buttonThread").start) # else: getattr(self, name + "button").clicked.connect(function) # getattr(self, name + "button").setMinimumWidth(220) if layout is None: if self.buttonLayoutRightCol.count( ) < self.buttonLayoutMiddleCol.count(): self.buttonLayoutRightCol.addWidget( getattr(self, name + "button")) elif self.buttonLayoutMiddleCol.count( ) < self.buttonLayoutLeftCol.count(): self.buttonLayoutMiddleCol.addWidget( getattr(self, name + "button")) else: self.buttonLayoutLeftCol.addWidget( getattr(self, name + "button")) else: layout.addWidget(getattr(self, name + "button")) def updatePlot(self): self.plot(self.currently_selected, self.plotargs) def updateWindowTitle(self): if np.shape(self.log.data[0, DID_DEV_INFO])[0] != 0: info = self.log.data[0, DID_DEV_INFO][0] infoStr = 'SN' + str(info[1]) + ', H:' + verArrayToString( info[2]) + ', F:' + verArrayToString( info[3]) + ' build ' + str( info[4]) + ', ' + dateTimeArrayToString( info[8], info[9]) + ', ' + info[10].decode('UTF-8') self.setWindowTitle("LogInspector - " + infoStr) def choose_directory(self): log_dir = config['logs_directory'] directory = QFileDialog.getExistingDirectory( parent=self, caption='Choose Log Directory', directory=log_dir) if directory != '': try: self.load(directory) except Exception as e: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Unable to load log: " + e.__str__()) msg.setDetailedText(traceback.format_exc()) msg.exec() def load(self, directory): print("loading files from " + directory) # if self.log is None: self.log = Log() self.log.load(directory) print("done loading") self.plotter = logPlot(False, False, 'svg', self.log) self.plotter.setDownSample(self.downsample) # str = '' # if self.log.navMode: # str += 'NAV ' # if self.log.rtk: # str += 'RTK ' # if self.log.compassing: # str += 'Comp ' # self.statusLabel.setText(str) self.updatePlot() self.updateWindowTitle() self.stopLoadingIndicator() def setupUi(self): self.setObjectName("LogInspector") self.setWindowTitle("LogInspector") self.resize(1280, 900) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowMinMaxButtonsHint) self.setWindowIcon(QIcon("assets/Magnifying_glass_icon.png")) # MainWindow.showMaximized() self.createFileTree() self.createButtonColumn() self.formatButtonColumn() self.createBottomToolbar() self.figureLayout = QVBoxLayout() self.figureLayout.addWidget(self.canvas) self.figureLayout.addLayout(self.toolLayout) self.figureLayout.setStretchFactor(self.canvas, 1) layout = QHBoxLayout() layout.addLayout(self.controlLayout) layout.addLayout(self.figureLayout) layout.setStretch(1, 1) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) # self.resize(1280, 900) self.resize(1450, 1000) self.setAcceptDrops(True) def createButtonColumn(self): self.controlLayout = QVBoxLayout() self.buttonLayoutLeftCol = QVBoxLayout() self.buttonLayoutMiddleCol = QVBoxLayout() self.buttonLayoutRightCol = QVBoxLayout() self.addButton('Pos NED Map', lambda: self.plot('posNEDMap')) self.addButton('Pos NED', lambda: self.plot('posNED')) self.addButton('Pos LLA', lambda: self.plot('posLLA')) self.addButton('GPS LLA', lambda: self.plot('llaGps')) self.addButton('Vel NED', lambda: self.plot('velNED')) self.addButton('Vel UVW', lambda: self.plot('velUVW')) self.addButton('Attitude', lambda: self.plot('attitude')) self.addButton('Heading', lambda: self.plot('heading')) self.addButton('INS Status', lambda: self.plot('insStatus')) self.addButton('HDW Status', lambda: self.plot('hdwStatus')) self.addButton('GPS 1 Stats', lambda: self.plot('gpsStats')) self.addButton('GPS 2 Stats', lambda: self.plot('gps2Stats')) self.addButton('RTK Pos Stats', lambda: self.plot('rtkPosStats')) self.addButton('RTK Cmp Stats', lambda: self.plot('rtkCmpStats')) self.addButton('Flash Config', lambda: self.showFlashConfig()) self.addButton('Device Info', lambda: self.showDeviceInfo()) self.addButton('IMU PQR', lambda: self.plot('imuPQR')) self.addButton('IMU Accel', lambda: self.plot('imuAcc')) self.addButton('PSD PQR', lambda: self.plot('gyroPSD')) self.addButton('PSD Accel', lambda: self.plot('accelPSD')) self.addButton('Magnetometer', lambda: self.plot('magnetometer')) self.addButton('Temp', lambda: self.plot('temp')) def formatButtonColumn(self): self.buttonLayoutLeftCol.setAlignment(QtCore.Qt.AlignTop) self.buttonLayoutMiddleCol.setAlignment(QtCore.Qt.AlignTop) self.buttonLayoutRightCol.setAlignment(QtCore.Qt.AlignTop) self.buttonColumnLayout = QHBoxLayout() self.buttonColumnLayout.addLayout(self.buttonLayoutLeftCol) self.buttonColumnLayout.addLayout(self.buttonLayoutMiddleCol) self.buttonColumnLayout.addLayout(self.buttonLayoutRightCol) self.controlLayout.addLayout(self.buttonColumnLayout) self.controlDirLayout = QHBoxLayout() self.controlDirLayout.addWidget(self.dirLineEdit) self.controlLayout.addLayout(self.controlDirLayout) self.controlLayout.addWidget(self.fileTree) # self.buttonLayout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # self.addButton('load', self.choose_directory, multithreaded=False) def createBottomToolbar(self): self.toolLayout = QHBoxLayout() self.toolLayout.addWidget(self.toolbar) self.loadingIndictator = QLabel() self.loadingMovie = QMovie('assets/loader.gif') self.emptyLoadingPicture = QPicture() self.emptyLoadingPicture.load('assets/empty_loader.png') self.stopLoadingIndicator() self.toolLayout.addWidget(self.loadingIndictator) self.toolLayout.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # self.toolLayout.addWidget(QSpacerItem(150, 10, QSizePolicy.Expanding)) self.copyImagePushButton = QPushButton() # self.copyImagePushButton.setText("Copy") # self.copyImagePushButton.setMinimumWidth(1) # self.copyImagePushButton.style().standardIcon(QStyle.SP_DialogOpenButton) self.copyImagePushButton.setIcon(self.style().standardIcon( QStyle.SP_DialogSaveButton)) self.toolLayout.addWidget(self.copyImagePushButton) self.copyImagePushButton.clicked.connect(self.copyPlotToClipboard) downsampleLabel = QLabel() downsampleLabel.setText("DS") self.downSampleInput = QSpinBox() self.downSampleInput.setValue(self.downsample) self.toolLayout.addWidget(downsampleLabel) self.toolLayout.addWidget(self.downSampleInput) self.downSampleInput.valueChanged.connect(self.changeDownSample) self.statusLabel = QLabel() self.toolLayout.addWidget(self.statusLabel) def changeDownSample(self, val): self.downsample = val self.plotter.setDownSample(self.downsample) self.updatePlot() def copyPlotToClipboard(self): # pixmap = QPixmap.grabWidget(self.canvas) # QApplication.clipboard().setPixmap(pixmap) # pixmap.save('test.png') # store the image in a buffer using savefig(), this has the # advantage of applying all the default savefig parameters # such as background color; those would be ignored if you simply # grab the canvas using Qt buf = io.BytesIO() self.figure.savefig(buf) QApplication.clipboard().setImage(QImage.fromData(buf.getvalue())) buf.close() def startLoadingIndicator(self): self.loadingIndictator.setMovie(self.loadingMovie) self.loadingMovie.start() def dragEnterEvent(self, e): if (e.mimeData().hasUrls()): e.acceptProposedAction() def dropEvent(self, e): try: directory = e.mimeData().urls()[0].toLocalFile() self.load(directory) except Exception as e: self.showError(e) def showError(self, e): msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Unable to load log: " + e.__str__()) msg.setDetailedText(traceback.format_exc()) msg.exec() def createFileTree(self): self.dirModel = QFileSystemModel() self.dirModel.setRootPath(self.config["logs_directory"]) self.dirModel.setFilter(QtCore.QDir.Dirs | QtCore.QDir.NoDotAndDotDot) self.dirLineEdit = QLineEdit() self.dirLineEdit.setText(self.config["logs_directory"]) self.dirLineEdit.setFixedHeight(25) self.dirLineEdit.returnPressed.connect(self.handleTreeDirChange) self.fileTree = QTreeView() self.fileTree.setModel(self.dirModel) self.fileTree.setRootIndex( self.dirModel.index(self.config['logs_directory'])) self.fileTree.setColumnHidden(1, True) self.fileTree.setColumnHidden(2, True) self.fileTree.setColumnHidden(3, True) self.fileTree.setMinimumWidth(300) self.fileTree.clicked.connect(self.handleTreeViewClick) self.fileTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection) self.fileTree.customContextMenuRequested.connect( self.handleTreeViewRightClick) # self.populateRMSCheck(self.config['logs_directory']) def updateFileTree(self): self.dirModel.setRootPath(self.config["logs_directory"]) self.fileTree.setRootIndex( self.dirModel.index(self.config['logs_directory'])) def populateRMSCheck(self, directory): for subdir in os.listdir(directory): path = os.path.join(directory, subdir) if os.path.isdir(path): self.populateRMSCheck(path) elif 'RMS' in subdir: f = open(path) rms_report = f.read() p = re.compile(r'(?<=^PASS/FAIL).*\n', re.M) line = re.search(p, rms_report).group() failed = True if "FAIL" in line else False if failed: pass else: pass def handleTreeDirChange(self): self.config["logs_directory"] = self.dirLineEdit.text() self.updateFileTree() file = open(self.configFilePath, 'w') yaml.dump(self.config, file) file.close() def handleTreeViewClick(self): selected_directory = self.fileTree.model().filePath( self.fileTree.selectedIndexes()[0]) for fname in os.listdir(selected_directory): if fname.endswith('.dat'): try: self.load(selected_directory) except Exception as e: self.showError(e) break def handleTreeViewRightClick(self, event): selected_directory = os.path.normpath(self.fileTree.model().filePath( self.fileTree.selectedIndexes()[0])) menu = QMenu(self) copyAction = menu.addAction("Copy path") nppActionHot = menu.addAction("Run NPP, HOT start") nppActionCold = menu.addAction("Run NPP, COLD start") nppActionFactory = menu.addAction("Run NPP, FACTORY start") setDataInfoDirHotAction = menu.addAction( "Set dataInfo.json directory, HOT start") setDataInfoDirColdAction = menu.addAction( "Set dataInfo.json directory, COLD start") setDataInfoDirFactoryAction = menu.addAction( "Set dataInfo.json directory, FACTORY start") exploreAction = menu.addAction("Explore folder") cleanFolderAction = menu.addAction("Clean folder") deleteFolderAction = menu.addAction("Delete folder") action = menu.exec_(self.fileTree.viewport().mapToGlobal(event)) if action == copyAction: cb = QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(selected_directory, mode=cb.Clipboard) if action == nppActionHot: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_HOT) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials']) spp.run() if action == nppActionCold: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_COLD) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials'], startMode=START_MODE_COLD) spp.run() if action == nppActionFactory: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_FACTORY) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials'], startMode=START_MODE_FACTORY) spp.run() if action == setDataInfoDirHotAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_HOT) if action == setDataInfoDirColdAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_COLD) if action == setDataInfoDirFactoryAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_FACTORY) if action == exploreAction: openFolderWithFileBrowser(selected_directory) if action == cleanFolderAction: cleanFolder(selected_directory) if action == deleteFolderAction: msg = QMessageBox(self) msg.setIcon(QMessageBox.Question) msg.setText("Are you sure you want to delete this folder?\n\n" + selected_directory) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) result = msg.exec() if result == QMessageBox.Yes: removeDirectory(selected_directory) def stopLoadingIndicator(self): self.loadingMovie.stop() self.loadingIndictator.clear() self.loadingIndictator.setPicture(self.emptyLoadingPicture) def showDeviceInfo(self): dlg = DeviceInfoDialog(self.log, self) dlg.show() dlg.exec_() def showFlashConfig(self): dlg = FlashConfigDialog(self.log, self) dlg.show() dlg.exec_() def plot(self, func, args=None): print("plotting " + func) self.currently_selected = func self.plotargs = args self.figure.clear() if hasattr(self, 'plotter'): if args is not None: getattr(self.plotter, func)(*args, self.figure) else: getattr(self.plotter, func)(self.figure) self.canvas.draw() self.stopLoadingIndicator() print("done plotting")
class AnalyzeTab(QWidget): analyzeDone = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject') def __init__(self): super().__init__() # Layouts self.mainLayout = QHBoxLayout() self.lVbox = QVBoxLayout() self.lHbox = QHBoxLayout() self.lHbox_top = QHBoxLayout() self.rVbox = QVBoxLayout() self.rHbox = QHBoxLayout() self.rVbox2 = QVBoxLayout() self.stack = QStackedWidget() self.stack_Vbox = QVBoxLayout() self.stack_Hbox1 = QHBoxLayout() self.stack_Hbox2 = QHBoxLayout() self.hSplit = QSplitter(Qt.Horizontal) self.hSplit.setFrameShape(QFrame.StyledPanel) self.vSplit = QSplitter(Qt.Vertical) self.vSplit.setFrameShape(QFrame.StyledPanel) self.mainLayout.addLayout(self.lVbox, 1) self.mainLayout.addLayout(self.rVbox, 3) # Setup file browser self.fileModel = QFileSystemModel() self.fileModel.setNameFilters(['*.wav']) self.fileModel.setRootPath(QDir.currentPath()) self.fileTree = QTreeView() self.fileTree.setModel(self.fileModel) self.fileTree.setRootIndex(self.fileModel.index(r'./')) self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection) self.fileTree.setColumnHidden(2, True) self.fileTree.setColumnHidden(1, True) self.rootDirEdit = QLineEdit(os.path.dirname(__file__)) self.rootDirEdit.returnPressed.connect(self.on_edit_root) self.browseBtn = QPushButton('Browse') self.browseBtn.clicked.connect(self.on_browse) self.lHbox_top.addWidget(self.rootDirEdit, 3) self.lHbox_top.addWidget(self.browseBtn, 1) # Setup Canvas self.canvas = PlotCanvas(self) self.analyzeDone.connect(self.canvas.plot) self._analyze = lambda _: self.analyze(self.fileTree.selectedIndexes()) self.analyzeBtn = QPushButton('Analyze') self.analyzeBtn.clicked.connect(self._analyze) ## BATCH ANALYSIS CONTROLS ## self.batchAnalyzeChk = QCheckBox('Batch Analysis') self.dataTable = QTableWidget() self.batchCtrlBox = QGroupBox("Batch Analysis") self.batchCtrlBox.setLayout(self.stack_Vbox) # Analysis Mode self.modeGroup = QButtonGroup() self.modeBox = QGroupBox('Analysis Mode') self.modeBox.setLayout(self.stack_Hbox1) self.stack_Vbox.addWidget(self.modeBox) self.wavAnalysisChk = QCheckBox('Wav analysis') self.wavAnalysisChk.setChecked(True) self.calibrationLocationBox = QComboBox() self.calibrationLocationBox.addItems([str(n) for n in range(1, 11)]) self.calibrationCurveChk = QCheckBox('Calibration Curve') self.calibrationCurveChk.toggled.connect( lambda state: self.calibrationLocationBox.setEnabled(state)) self.calibrationCurveChk.setChecked(False) self.stack_Hbox1.addWidget(self.wavAnalysisChk, 3) self.stack_Hbox1.addWidget(self.calibrationCurveChk, 3) self.stack_Hbox1.addWidget(QLabel('Location: '), 1) self.stack_Hbox1.addWidget(self.calibrationLocationBox, 1) self.stack_Vbox.addLayout(self.stack_Hbox1) self.modeGroup.addButton(self.wavAnalysisChk) self.modeGroup.addButton(self.calibrationCurveChk) self.modeGroup.setExclusive(True) # Outputs self.outputCtrlBox = QGroupBox('Outputs') self.outputCtrlBox.setLayout(self.stack_Hbox2) self.stack_Vbox.addWidget(self.outputCtrlBox) self.toCSVchk = QCheckBox('.csv') self.toJSONchk = QCheckBox('.json') self.toCSVchk.stateChanged.connect(lambda _: self.update_settings( 'output', 'toCSV', self.toCSVchk.isChecked())) self.toJSONchk.stateChanged.connect(lambda _: self.update_settings( 'output', 'toJSON', self.toJSONchk.isChecked())) self.stack_Hbox2.addWidget(self.toCSVchk) self.stack_Hbox2.addWidget(self.toJSONchk) self.stack_Vbox.addLayout(self.stack_Hbox2) self.stack.addWidget(self.dataTable) self.stack.addWidget(self.batchCtrlBox) self.stack.setCurrentWidget(self.dataTable) self.stack.show() self.batchAnalyzeChk.stateChanged.connect(self.toggle_stack) self.batchAnalyzeChk.setChecked(False) self.stack_Vbox.addStretch() ## PROCESSING CONTROLS ## self.processControls = QGroupBox('Signal Processing') self.tOffsetSlider = QSlider(Qt.Horizontal, ) self.tOffsetSlider.setMinimum(1) self.tOffsetSlider.setMaximum(100) self.tOffsetSlider.setValue(100) self.tOffsetSlider.setTickPosition(QSlider.TicksBelow) self.tOffsetSlider.setTickInterval(10) self.tOffsetSlider.valueChanged.connect( lambda val: self.update_settings('processing', 'tChop', val)) self.tOffsetLayout = QHBoxLayout() self.tOffsetSlider_Box = QGroupBox( f'Chop Signal - {self.tOffsetSlider.value()}%') self.tOffsetSlider.valueChanged.connect( lambda val: self.tOffsetSlider_Box.setTitle(f'Chop Signal - {val}%' )) self.tOffsetSlider_Box.setLayout(self.tOffsetLayout) self.tOffsetLayout.addWidget(self.tOffsetSlider) self.nFFTSlider = QSlider(Qt.Horizontal, ) self.nFFTSlider.setMinimum(1) self.nFFTSlider.setMaximum(16) self.nFFTSlider.setValue(1) self.nFFTSlider.setTickPosition(QSlider.TicksBelow) self.nFFTSlider.setTickInterval(2) self.nFFTSlider.valueChanged.connect( lambda val: self.update_settings('processing', 'detail', val)) self.nFFTLayout = QHBoxLayout() self.nFFTSlider.valueChanged.connect( lambda val: self.nFFTSlider_Box.setTitle(f'FFT Size - {val*65536}' )) self.nFFTSlider_Box = QGroupBox( f'FFT Size - {self.nFFTSlider.value()*65536}') self.nFFTSlider_Box.setLayout(self.nFFTLayout) self.nFFTLayout.addWidget(self.nFFTSlider) self.rVbox2.addWidget(self.tOffsetSlider_Box) self.rVbox2.addWidget(self.nFFTSlider_Box) self.processControls.setLayout(self.rVbox2) self.lVbox.addLayout(self.lHbox_top, 1) self.lVbox.addWidget(self.fileTree, 7) self.lVbox.addLayout(self.lHbox, 1) self.lHbox.addWidget(self.analyzeBtn, 2) self.lHbox.addWidget(self.batchAnalyzeChk, 1) self.vSplit.addWidget(self.canvas) self.vSplit.addWidget(self.hSplit) self.rVbox.addWidget(self.vSplit) self.hSplit.addWidget(self.stack) self.hSplit.addWidget(self.processControls) self.settings = { 'processing': { 'tChop': self.tOffsetSlider.value(), 'detail': self.nFFTSlider.value() }, 'output': { 'toCSV': self.toCSVchk.isChecked(), 'toJSON': self.toJSONchk.isChecked() } } self.setLayout(self.mainLayout) def on_browse(self): # Browse to file tree root directory options = QFileDialog.Options() path = QFileDialog.getExistingDirectory( self, caption="Choose root directory", options=options) self.rootDirEdit.setText(path) self.fileTree.setRootIndex(self.fileModel.index(path)) def on_edit_root(self): # Update the file tree root directory self.fileTree.setRootIndex( self.fileModel.index(self.rootDirEdit.text())) def update_settings(self, category, setting, value): # Update settings and reprocess FFT if in single analysis mode self.settings[category][setting] = value if category == 'processing' and self.fileTree.selectedIndexes(): self.analyze(self.fileTree.selectedIndexes()) def toggle_stack(self, state): if state == 2: self.stack.setCurrentWidget(self.batchCtrlBox) self.fileTree.setSelectionMode(QAbstractItemView.MultiSelection) else: self.stack.setCurrentWidget(self.dataTable) self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection) def analyze(self, filePaths): if self.batchAnalyzeChk.isChecked(): if self.wavAnalysisChk.isChecked(): self.batch_analyze_wav( [self.fileModel.filePath(path) for path in filePaths[::4]]) if self.calibrationCurveChk.isChecked(): self.generate_calibration_curve( [self.fileModel.filePath(path) for path in filePaths[::4]]) else: if os.path.isdir(self.fileModel.filePath( filePaths[0])) or len(filePaths) > 4: QMessageBox.information( self, 'Error', 'Please select only 1 file for single analysis.') return self.single_analyze_wav(self.fileModel.filePath(filePaths[0])) def single_analyze_wav(self, filePath): """ Do an FFT and find peaks on a single wav file :param filePath: file path to .wav file """ tChopped, vChopped, fVals,\ powerFFT, peakFreqs, peakAmps = Utils.AnalyzeFFT(filePath, tChop=self.settings['processing']['tChop'], detail=self.settings['processing']['detail']) self.analyzeDone.emit(tChopped, vChopped, fVals, powerFFT, peakFreqs, peakAmps, filePath) self.update_table(peakFreqs, peakAmps) def batch_analyze_wav(self, filePaths): """ Perform a batch analysis of many .wav files. Outputs FFTs and peaks in .csv or .json format :param filePaths: A list of folders containing the .wav files to be analyzed """ toCSV = self.settings['output']['toCSV'] toJSON = self.settings['output']['toJSON'] start = time.time() fileTotal = 0 for path in filePaths: if os.path.isdir(path): blockName = os.path.basename(path) print(f'Block: {blockName}') files = [ os.path.join(path, file) for file in os.listdir(path) if '.wav' in file ] fileTotal += len(files) if toCSV: if not os.path.exists(os.path.join(path, 'fft_results_csv')): os.makedirs(os.path.join(path, 'fft_results_csv')) resultFilePath = os.path.join(path, 'fft_results_csv') print('Processing FFTs...') with multiprocessing.Pool(processes=4) as pool: results = pool.starmap( Utils.AnalyzeFFT, zip(files, itertools.repeat(True), itertools.repeat(True))) results = [ result for result in results if result is not None ] peaks = [result[0] for result in results] ffts = [result[1] for result in results] print('Writing to .csv...') resultFileName = os.path.join(resultFilePath, f'{blockName}_Peaks.csv') peakFrames = pd.concat(peaks) peakFrames.to_csv(resultFileName, index=False, header=True) with concurrent.futures.ThreadPoolExecutor( max_workers=16) as executor: executor.map(self.multi_csv_write, ffts) if toJSON: if not os.path.exists( os.path.join(path, 'fft_results_json')): os.makedirs(os.path.join(path, 'fft_results_json')) print(os.path.join(path, 'fft_results_json')) print('Processing FFTs...') with multiprocessing.Pool(processes=4) as pool: results = pool.starmap( Utils.AnalyzeFFT, zip(files, itertools.repeat(True), itertools.repeat(False), itertools.repeat(True))) results = [ result for result in results if result is not None ] print('Writing to .json...') with concurrent.futures.ThreadPoolExecutor( max_workers=16) as executor: executor.map(self.multi_json_write, results) end = time.time() print( f'**Done!** {len(filePaths)} blocks with {fileTotal} files took {round(end-start, 1)}s' ) def generate_calibration_curve(self, filePaths): """ Attempt to fit an exponential function to a set of data points (x: Peak Frequency, y: Compressive strength) provided in JSON format. ex:{ "shape": "2-Hole", "testData": { "location": "1", "strength": 3.092453552, "peaks": [ { "frequency": 1134.5561082797967, "magnitude": 0.349102384777402 }] }, "waveData": [...], "freqData": [...] } Plot the curve, data points and give the function if successful. ** NOTE ** This function is still experimental and a bit buggy. Sometimes the scipy.optimize curve_fit won't converge with the initial guess given for the coeffecients. You're probably better off writing your own code. :param filePaths: A list of folders containing .jsons """ # Strike Location location = self.calibrationLocationBox.currentText() # Function to fit to the data exp_f = lambda x, a, b, c: a * np.exp(b * x) + c # Threaded method for opening all the .jsons and fitting calibCurve = ThreadedCalibrationCurve(filePaths, location, exp_f) progressDialog = QProgressDialog( f'Gettings samples for location: {location}', None, 0, len(filePaths), self) progressDialog.setModal(True) calibCurve.blocksSearched.connect(progressDialog.setValue) try: peakFreqs, strengths, popt, pcov, fitX = calibCurve.run() except Exception as e: QMessageBox.information(self, 'Error', e) return # Calculate R Squared residuals = strengths - exp_f(peakFreqs, *popt) ss_res = np.sum(residuals**2) ss_tot = np.sum((strengths - np.mean(strengths))**2) r_squared = 1 - (ss_res / ss_tot) # Plot Results fig = Figure() plt.scatter(peakFreqs, strengths) plt.plot(fitX, exp_f(fitX, *popt), '-k') ax = plt.gca() plt.text( 0.05, 0.9, f'y = {round(popt[0],3)}*exp({round(popt[1], 5)}x) + {round(popt[2], 3)}\n', ha='left', va='center', transform=ax.transAxes) plt.text(0.05, 0.85, f'R^2 = {round(r_squared,3)}', ha='left', va='center', transform=ax.transAxes) plt.title(f'Calibration Curve, Location: {location}') plt.xlabel('Frequency (Hz)') plt.ylabel('Compressive Strength (MPa)') plt.show() def multi_csv_write(self, frameTuple): frame = frameTuple[1] wavPath = frameTuple[0] resultFileDir = os.path.join(os.path.dirname(wavPath), 'fft_results_csv') resultFileName = os.path.basename(wavPath) + '_fft.csv' resultFilePath = os.path.join(resultFileDir, resultFileName) frame.to_csv(resultFilePath, index=False, header=True) def multi_json_write(self, results): data = results[0] wavPath = results[1] jsonFileDir = os.path.join(os.path.dirname(wavPath), 'fft_results_json') resultFileName = os.path.basename(wavPath) + '_fft.json' resultFilePath = os.path.join(jsonFileDir, resultFileName) # blockName = os.path.basename(os.path.dirname(wavPath)) # blockDir = os.path.join(jsonFileDir, blockName) # if not os.path.exists(blockDir): # os.makedirs(blockDir) # print(resultFilePath) with open(resultFilePath, 'w') as f: json.dump(data, f, indent=2) def update_table(self, peakFreqs, peakAmps): """ :param peakFreqs: :param peakAmps: :return: """ self.dataTable.setRowCount(2) self.dataTable.setColumnCount(len(peakFreqs) + 1) self.dataTable.setItem(0, 0, QTableWidgetItem("Frequencies: ")) self.dataTable.setItem(1, 0, QTableWidgetItem("Powers: ")) for col, freq in enumerate(peakFreqs, start=1): self.dataTable.setItem(0, col, QTableWidgetItem(str(round(freq)))) for col, power in enumerate(peakAmps, start=1): item = QTableWidgetItem(str(round(power, 3))) if power > 0.7: item.setBackground(QColor(239, 81, 28)) elif power >= 0.4: item.setBackground(QColor(232, 225, 34)) elif power < 0.4: item.setBackground(QColor(113, 232, 34)) self.dataTable.setItem(1, col, item)
class FilenamePrompt(_BasePrompt): """A prompt for a filename.""" def __init__(self, question, parent=None): super().__init__(question, parent) self._init_texts(question) self._init_key_label() self._lineedit = LineEdit(self) if question.default: self._lineedit.setText(question.default) self._lineedit.textEdited.connect(self._set_fileview_root) self._vbox.addWidget(self._lineedit) self.setFocusProxy(self._lineedit) self._init_fileview() self._set_fileview_root(question.default) if config.val.prompt.filebrowser: self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self._to_complete = '' @pyqtSlot(str) def _set_fileview_root(self, path, *, tabbed=False): """Set the root path for the file display.""" separators = os.sep if os.altsep is not None: separators += os.altsep dirname = os.path.dirname(path) basename = os.path.basename(path) if not tabbed: self._to_complete = '' try: if not path: pass elif path in separators and os.path.isdir(path): # Input "/" -> don't strip anything pass elif path[-1] in separators and os.path.isdir(path): # Input like /foo/bar/ -> show /foo/bar/ contents path = path.rstrip(separators) elif os.path.isdir(dirname) and not tabbed: # Input like /foo/ba -> show /foo contents path = dirname self._to_complete = basename else: return except OSError: log.prompt.exception("Failed to get directory information") return root = self._file_model.setRootPath(path) self._file_view.setRootIndex(root) @pyqtSlot(QModelIndex) def _insert_path(self, index, *, clicked=True): """Handle an element selection. Args: index: The QModelIndex of the selected element. clicked: Whether the element was clicked. """ if index == QModelIndex(): path = os.path.join(self._file_model.rootPath(), self._to_complete) else: path = os.path.normpath(self._file_model.filePath(index)) if clicked: path += os.sep else: # On Windows, when we have C:\foo and tab over .., we get C:\ path = path.rstrip(os.sep) log.prompt.debug('Inserting path {}'.format(path)) self._lineedit.setText(path) self._lineedit.setFocus() self._set_fileview_root(path, tabbed=True) if clicked: # Avoid having a ..-subtree highlighted self._file_view.setCurrentIndex(QModelIndex()) def _init_fileview(self): self._file_view = QTreeView(self) self._file_model = QFileSystemModel(self) self._file_view.setModel(self._file_model) self._file_view.clicked.connect(self._insert_path) if config.val.prompt.filebrowser: self._vbox.addWidget(self._file_view) else: self._file_view.hide() # Only show name self._file_view.setHeaderHidden(True) for col in range(1, 4): self._file_view.setColumnHidden(col, True) # Nothing selected initially self._file_view.setCurrentIndex(QModelIndex()) # The model needs to be sorted so we get the correct first/last index self._file_model.directoryLoaded.connect( lambda: self._file_model.sort(0)) def accept(self, value=None, save=False): self._check_save_support(save) text = value if value is not None else self._lineedit.text() text = downloads.transform_path(text) if text is None: message.error("Invalid filename") return False self.question.answer = text return True def item_focus(self, which): # This duplicates some completion code, but I don't see a nicer way... assert which in ['prev', 'next'], which selmodel = self._file_view.selectionModel() parent = self._file_view.rootIndex() first_index = self._file_model.index(0, 0, parent) row = self._file_model.rowCount(parent) - 1 last_index = self._file_model.index(row, 0, parent) if not first_index.isValid(): # No entries return assert last_index.isValid() idx = selmodel.currentIndex() if not idx.isValid(): # No item selected yet idx = last_index if which == 'prev' else first_index elif which == 'prev': idx = self._file_view.indexAbove(idx) else: assert which == 'next', which idx = self._file_view.indexBelow(idx) # wrap around if we arrived at beginning/end if not idx.isValid(): idx = last_index if which == 'prev' else first_index idx = self._do_completion(idx, which) selmodel.setCurrentIndex( idx, QItemSelectionModel.ClearAndSelect | # type: ignore[arg-type] QItemSelectionModel.Rows) self._insert_path(idx, clicked=False) def _do_completion(self, idx, which): filename = self._file_model.fileName(idx) while not filename.startswith(self._to_complete) and idx.isValid(): if which == 'prev': idx = self._file_view.indexAbove(idx) else: assert which == 'next', which idx = self._file_view.indexBelow(idx) filename = self._file_model.fileName(idx) return idx def _allowed_commands(self): return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
class MainWindowClass(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.interface_lng_val = 'Russian' self.setWindowTitle("Графический интерфейс программы OpenFOAM") self.full_dir = '' self.prj_name = '' self.con = '' # ---------------------------Панель управления решением задачи МСС----------------------------- # self.proj_open = QAction(self) self.proj_open.setEnabled(True) proj_ico = self.style().standardIcon(QStyle.SP_ArrowUp) self.proj_open.setIcon(proj_ico) self.proj_open.setToolTip('Открыть проект') self.lng_chs = QAction(self) self.lng_chs.setEnabled(True) lng_chs_ico = self.style().standardIcon( QStyle.SP_FileDialogDetailedView) self.lng_chs.setIcon(lng_chs_ico) self.lng_chs.setToolTip('Выбрать язык интерфейса программы') self.toolBar_1 = QToolBar("MyToolBar") self.toolBar_1.addAction(self.proj_open) self.toolBar_1.addAction(self.lng_chs) self.proj_open.triggered.connect( lambda: first_toolbar_functions_class.on_proj_open(self)) self.addToolBar(self.toolBar_1) ###----------------------Панель управления подготовкой РС--------------------------### self.msh_open = QAction(self) self.msh_open.setEnabled(False) msh_ico = self.style().standardIcon(QStyle.SP_FileDialogNewFolder) self.msh_open.setIcon(msh_ico) self.msh_open.setToolTip('Открыть форму выбора расчетной сетки') self.msh_run = QAction(self) self.msh_run.setEnabled(False) msh_ico = self.style().standardIcon(QStyle.SP_ArrowRight) self.msh_run.setIcon(msh_ico) self.msh_run.setToolTip('Выполнить генерацию расчетной сетки') self.msh_visual = QAction(self) self.msh_visual.setEnabled(False) msh_visual_ico = self.style().standardIcon(QStyle.SP_MediaSeekForward) self.msh_visual.setIcon(msh_visual_ico) self.msh_visual.setToolTip('Выполнить визуализацию расчетной сетки') self.toolBar_2 = QToolBar() self.toolBar_2.addAction(self.msh_open) self.toolBar_2.addAction(self.msh_run) self.toolBar_2.addAction(self.msh_visual) self.msh_open.triggered.connect( lambda: second_toolbar_functions_class.on_msh_open(self)) self.msh_run.triggered.connect( lambda: second_toolbar_functions_class.on_msh_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.msh_visual.triggered.connect( lambda: second_toolbar_functions_class.on_visual_msh_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.addToolBar(self.toolBar_2) self.insertToolBarBreak(self.toolBar_2) ###----------------------Панель управления проведением стресс-анализа--------------------------### self.str_an_run = QAction(self) self.str_an_run.setEnabled(False) str_an_ico = self.style().standardIcon(QStyle.SP_CommandLink) self.str_an_run.setIcon(str_an_ico) self.str_an_run.setToolTip('Выполнить стресс-анализ') self.str_an_vis_run = QAction(self) self.str_an_vis_run.setEnabled(False) str_an_vis_ico = self.style().standardIcon(QStyle.SP_MediaPlay) self.str_an_vis_run.setIcon(str_an_vis_ico) self.str_an_vis_run.setToolTip( 'Выполнить визуализацию результатов стресс-анализ') self.toolBar_3 = QToolBar() self.toolBar_3.addAction(self.str_an_run) self.toolBar_3.addAction(self.str_an_vis_run) self.str_an_run.triggered.connect( lambda: second_toolbar_functions_class.on_str_an_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.str_an_vis_run.triggered.connect( lambda: second_toolbar_functions_class.on_visual_on_str_an_run( prj_path_val, mesh_name_txt_val, pp_dir, self, self. interface_lng_val, msh_type)) self.addToolBar(self.toolBar_3) self.insertToolBarBreak(self.toolBar_3) ###----------------Верхний виджет с полным путем до файла сетки----------------### self.tdw = QDockWidget() self.tdw.setFixedSize(1400, 65) self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures) self.tdw_grid = QGridLayout() self.tdw_grid.setColumnStretch(2, 1) self.tdw_frame = QFrame() self.tdw_frame.setStyleSheet("background-color: ghostwhite;" "border-width: 0.5px;" "border-style: solid;" "border-color: silver;") self.tdw_frame.setLayout(self.tdw_grid) self.tdw.setWidget(self.tdw_frame) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.tdw) ###-----------------Левый виджет с файловой системой проекта---------------------### self.fsw = QDockWidget() self.fsw.setFeatures(self.fsw.NoDockWidgetFeatures) self.fsw_label = QLabel() self.fsw_label.setAlignment(QtCore.Qt.AlignCenter) self.fsw_grid = QGridLayout() self.fsw_grid.addWidget(self.fsw_label, 0, 0) self.fsw_frame = QFrame() self.fsw_frame.setFixedSize(200, 35) self.fsw_frame.setStyleSheet("background-color: honeydew;" "border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;") self.fsw_frame.setLayout(self.fsw_grid) fs_lbl = "Файловая структура проекта" self.fsw_label.setText("<font color='SeaGreen'>" + fs_lbl + "</font>") self.fsw_label.setStyleSheet("border-style: none;" "font-size: 10pt;") self.fsw.setTitleBarWidget(self.fsw_frame) self.treeview = QTreeView() self.treeview.setFixedSize(200, 520) self.treeview.model = QtGui.QStandardItemModel() self.treeview.setModel(self.treeview.model) self.treeview.setColumnWidth(0, 100) self.treeview.setColumnHidden(1, True) self.treeview.setColumnHidden(2, True) self.treeview.setColumnHidden(3, True) self.treeview.header().hide() self.treeview.setItemsExpandable(False) self.treeview.clicked.connect(self.on_treeview_clicked) self.fsw.setWidget(self.treeview) ###-----------Правый виджет с формой вывода результатов генерации файлов-----------### self.cdw = QDockWidget() self.cdw.setFeatures(self.cdw.NoDockWidgetFeatures) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw) self.cdw_grid = QGridLayout() self.cdw_frame = QFrame() self.cdw_frame.setFixedSize(495, 35) self.cdw_frame.setStyleSheet("border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;" "background-color: honeydew;") self.cdw_frame.setLayout(self.cdw_grid) self.outf_lbl = QLabel() self.outf_lbl.setAlignment(QtCore.Qt.AlignCenter) self.outf_lbl.setStyleSheet("border-style: none;" "font-size: 9pt;") self.cdw_grid.addWidget(self.outf_lbl, 0, 0) self.outf_edit = QTextEdit() self.outf_scroll = QScrollArea() self.outf_scroll.setWidgetResizable(True) self.outf_scroll.setWidget(self.outf_edit) self.outf_scroll.setFixedSize(495, 520) ###-----------------Центральный виджет с формой параметров---------------------### self.ffw = QDockWidget() self.ffw.setFeatures(self.ffw.NoDockWidgetFeatures) self.ffw_label = QLabel() self.ffw_label.setAlignment(QtCore.Qt.AlignCenter) self.ffw_grid = QGridLayout() self.ffw_grid.addWidget(self.ffw_label, 0, 0) self.ffw_frame = QFrame() self.ffw_frame.setFixedSize(693, 44) self.ffw_frame.setStyleSheet("border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 4px;" "background-color: honeydew;") self.ffw_frame.setLayout(self.ffw_grid) ###------------------Нижний виджет со служебными сообщениями------------------### self.serv_mes = QDockWidget("Служебные сообщения") self.serv_mes.setFixedSize(1400, 160) self.serv_mes.setFeatures(self.serv_mes.NoDockWidgetFeatures) self.listWidget = QListWidget() self.serv_mes.setWidget(self.listWidget) ###---------------------Функции, связанные с работой главного окна------------------------### # ...........................Функция клика по файлу из дерева......................... ###........................Функция открытия окна выбора интерфейса программы...................### # ...........................Функция клика по файлу из дерева......................... def on_treeview_clicked(self, index): global fileName indexItem = self.treeview.model.index(index.row(), 0, index.parent()) file_name = self.treeview.model.itemFromIndex(indexItem).text() file_form_class.inp_file_form_func(self, file_name, self.con) file_name_title = file_form_class.out_file_name_func() self.clear_label = QLabel() if file_name_title != None: self.cdw.setWidget(self.clear_label) self.cdw.setTitleBarWidget(self.clear_label) self.setCentralWidget(self.ffw) file_form = file_form_class.out_file_form_func() self.ffw.setWidget(file_form) self.ffw.setTitleBarWidget(self.ffw_frame) self.ffw_label.setText("Форма параметров файла: " + "<font color='peru'>" + file_name_title + "</font>") self.ffw_label.setStyleSheet("border-style: none;" "font-size: 9pt;") else: self.ffw.setTitleBarWidget(self.clear_label) self.ffw.setWidget(self.clear_label) self.cdw.setWidget(self.clear_label) self.cdw.setTitleBarWidget(self.clear_label) if file_name_title == 'blockMeshDict' or file_name_title == 'snappyHexMeshDict': if self.interface_lng_val == 'Russian': msg_lbl = QLabel( '<span style="color:blue">Для создания расчетной сетки воспользуйтесь панелью инструментов</span>' ) elif self.interface_lng_val == 'English': msg_lbl = QLabel( '<span style="color:blue">For computational mesh generation use the toolbar</span>' ) self.listWidget.clear() self.item = QListWidgetItem() self.listWidget.addItem(self.item) self.listWidget.setItemWidget(self.item, msg_lbl) # .........................Функция получения языка интерфейса.......................... def on_lng_get(self, interface_lng): global interface_lng_val self.interface_lng_val = interface_lng if self.interface_lng_val == 'Russian': self.setWindowTitle("Генератор расчетных сеток") self.prj_open.setToolTip('Открыть проект') self.msh_run.setToolTip('Выполнить генерацию расчетной сетки') self.msh_visual.setToolTip( 'Выполнить визуализацию расчетной сетки') self.lng_chs.setToolTip('Выбрать язык интерфейса программы') elif self.interface_lng_val == 'English': self.setWindowTitle("Mesh generator") self.prj_open.setToolTip('Open project') self.msh_run.setToolTip('Run mesh generation') self.msh_visual.setToolTip('Run mesh vizualization') self.lng_chs.setToolTip( 'Select the interface language for the program') # .........................Функция получения пути до директории.......................... def on_prj_path_get(self, prj_path, mesh_name_txt): global prj_path_val global mesh_name_txt_val global pp_dir prj_path_val = prj_path mesh_name_txt_val = mesh_name_txt pp_dir, pp_sys = os.path.split(prj_path_val) # .............................Функция получения типа сетки.............................. def on_mesh_type_get(self, pd_2): global msh_type msh_type = pd_2