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')]
def update_file_tree(self): model = QFileSystemModel() model.setRootPath(self._root_dir) self.localFilesTreeView.setModel(model) local_selection_model = self.localFilesTreeView.selectionModel() local_selection_model.selectionChanged.connect(self.local_file_selection_changed) self.localFilesTreeView.setRootIndex(model.index(self._root_dir))
class E5DirCompleter(QCompleter): """ Class implementing a completer for directory names. """ def __init__(self, parent=None, completionMode=QCompleter.PopupCompletion, showHidden=False): """ Constructor @param parent parent widget of the completer (QWidget) @keyparam completionMode completion mode of the completer (QCompleter.CompletionMode) @keyparam showHidden flag indicating to show hidden entries as well (boolean) """ super(E5DirCompleter, self).__init__(parent) self.__model = QFileSystemModel(self) if showHidden: self.__model.setFilter(QDir.Filters(QDir.Drives | QDir.AllDirs | QDir.Hidden)) else: self.__model.setFilter(QDir.Filters(QDir.Drives | QDir.AllDirs)) self.setModel(self.__model) self.setCompletionMode(completionMode) if isWindowsPlatform(): self.setCaseSensitivity(Qt.CaseInsensitive) if parent: parent.setCompleter(self)
def __init__(self, module_manager): super(AssetBrowser, self).__init__() self.setupUi(self) self.init_module(module_manager) self.dir_model = QFileSystemModel() self.dir_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dir_model.setReadOnly(False) self.dir_view.setModel(self.dir_model) self.dir_view.hideColumn(1) self.dir_view.hideColumn(2) self.dir_view.hideColumn(3) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.file_model.setReadOnly(False) self.file_view.setModel(self.file_model) self.dock = self.modules_manager.new_docked(self, self.Name, "Asset browser", Qt.BottomDockWidgetArea) self.modules_manager.main_window.splitDockWidget(self.dock, self.modules_manager["asset_view"].dock, Qt.Horizontal)
class FileTree(QTreeView): def __init__(self): super(FileTree, self).__init__() self.model = QFileSystemModel() self.model.setRootPath('') self.setModel(self.model) self.setAnimated(False) self.setIndentation(20) self.setSortingEnabled(True)
def initRootDir(self,indexDir): if not indexDir: return self.indexDir = indexDir model = QFileSystemModel() model.setRootPath('') self.setModel(model) self.setAnimated(False) self.setIndentation(20) self.setSortingEnabled(True) self.setRootIndex(model.index(self.indexDir)) for i in range(1,model.columnCount()): self.hideColumn(i)
class E5FileCompleter(QCompleter): """ Class implementing a completer for file names. """ def __init__(self, parent=None, completionMode=QCompleter.PopupCompletion, showHidden=False): """ Constructor @param parent parent widget of the completer (QWidget) @keyparam completionMode completion mode of the completer (QCompleter.CompletionMode) @keyparam showHidden flag indicating to show hidden entries as well (boolean) """ super(E5FileCompleter, self).__init__(parent) self.__model = QFileSystemModel(self) if showHidden: self.__model.setFilter( QDir.Filters(QDir.Dirs | QDir.Files | QDir.Drives | QDir.AllDirs | QDir.Hidden)) else: self.__model.setFilter(QDir.Filters( QDir.Dirs | QDir.Files | QDir.Drives | QDir.AllDirs)) self.__model.directoryLoaded.connect(self.complete) self.__model.setRootPath("") self.setModel(self.__model) self.setCompletionMode(completionMode) if isWindowsPlatform(): self.setCaseSensitivity(Qt.CaseInsensitive) if parent: parent.setCompleter(self) def setRootPath(self, path): """ Public method to set the root path of the model. @param path root path for the model @type str """ if not os.path.isdir(path): path = os.path.dirname(path) self.__model.setRootPath(path) def rootPath(self): """ Public method to get the root path of the model. @return root path of the model @rtype str """ return self.__model.rootPath()
def dropMimeData(self, data, action, row, column, parent): # print 'dropMimeData %s %s %s %s' % (data.data('text/uri-list'), action, row, parent) # print data.text() # print data.formats() # print data.data('text/uri-list') # print row, "row" # print column, "col" # print action, "action" # print parent, "parent" # print parent.data(Qt.DisplayRole),"parent" filePath = data.data('text/uri-list').data()[7:] # filesFolderPath = filePath # canonical , os path parent falan fileName = os.path.basename(filePath) # fileName = "" # print type(filePath.data()) # print fileName # os.path.normpath(unicode(self.model().fileInfo(self.selectedIndexes()[0]).absoluteFilePath())) # dfolder = self.fileInfo(parent).absoluteFilePath() destFinalPath = os.path.normpath("%s/%s" % (self.filePath(parent), fileName)) # ya da emit.fileMoved filepath move to destFolder+filename self.fileDraggedAndMoved.emit("%s --------> %s" % (filePath, destFinalPath)) # return True return QFileSystemModel.dropMimeData(self, data, action, row, column, parent)
def _init_ui(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) model = QFileSystemModel(self) model.setRootPath('') view = QTreeView() view.setModel(model) view.setAnimated(False) view.setIndentation(20) view.setSortingEnabled(True) layout = QVBoxLayout() layout.addWidget(view) self.setLayout(layout)
def __init__(self, path): super(NProject, self).__init__() project = json_manager.read_ninja_project(path) self.path = path self._name = project.get('name', '') if self._name == '': self._name = file_manager.get_basename(path) self.project_type = project.get('project-type', '') self.description = project.get('description', '') if self.description == '': self.description = translations.TR_NO_DESCRIPTION self.url = project.get('url', '') self.license = project.get('license', '') self.main_file = project.get('mainFile', '') self.pre_exec_script = project.get('preExecScript', '') self.post_exec_script = project.get('postExecScript', '') self.indentation = project.get('indentation', settings.INDENT) self.use_tabs = project.get('use-tabs', settings.USE_TABS) self.extensions = project.get('supported-extensions', settings.SUPPORTED_EXTENSIONS) self.python_exec = project.get('pythonExec', settings.PYTHON_EXEC) self.python_path = project.get('PYTHONPATH', '') self.additional_builtins = project.get('additional_builtins', []) self.program_params = project.get('programParams', '') self.venv = project.get('venv', '') self.related_projects = project.get('relatedProjects', []) self.added_to_console = False self.is_current = False #Model is a QFileSystemModel to be set on runtime self.__model = QFileSystemModel() self.__model.setRootPath(path)
def _iconForPath(self, path): """Get icon for file or directory path. Uses QFileSystemModel """ if self._model is None: self._model = QFileSystemModel() index = self._model.index(path) return self._model.data(index, Qt.DecorationRole)
def __init__(self): super(AssetBrowser, self).__init__() self.setupUi(self) self.dir_model = QFileSystemModel() self.dir_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dir_model.setReadOnly(False) self.dir_view.setModel(self.dir_model) self.dir_view.hideColumn(1) self.dir_view.hideColumn(2) self.dir_view.hideColumn(3) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.file_model.setReadOnly(False) self.file_view.setModel(self.file_model)
def load_dir(self, dir_path): if dir_path == self.dir_path: return self.dir_path = dir_path model = QFileSystemModel() model.setRootPath(dir_path) self.setModel(model) index_root = model.index(model.rootPath()) self.setRootIndex(index_root) # hide unwanted info self.hideColumn(1) self.hideColumn(2) self.hideColumn(3) self.setHeaderHidden(True)
class ComplexDialog(QDialog, Ui_ComplexForm): def __init__(self, parent=None): super(ComplexDialog, self).__init__(parent) self.setupUi(self) self.file_model = QFileSystemModel() self.bundle_model = QStringListModel() bundle_lists = [] self.bundle_model.setStringList(bundle_lists) root = self.file_model.setRootPath("/Volumes") self.columnView_files.setModel(self.file_model) self.columnView_files.setRootIndex(root) self.listView_files.setModel(self.bundle_model) # connect the buttons self.pushButton_add_file.clicked.connect(self._add_to_bundle) self.pushButton_remove_file.clicked.connect(self._remove_from_bundle) self.pushButton_cancle.clicked.connect(self.close_window) self.pushButton_add_object.clicked.connect(self.return_bundle) def _add_to_bundle(self): selection = self.columnView_files.selectedIndexes() files = self.bundle_model.stringList() model = self.columnView_files.model() for index in selection: # path = os.path.join() if model.isDir(index): continue newfile = model.filePath(index) files.append(newfile) self.bundle_model.setStringList(files) # self.bundle_model.inser def _remove_from_bundle(self): selection = self.listView_files.selectedIndexes() model = self.listView_files.model() for index in selection: row = index.row() model.removeRows(row, 1) def return_bundle(self): self.close_window() @property def bundle(self): return self.bundle_model.stringList() def close_window(self): self.close()
def __init__(self): super(FileSystemOpener, self).__init__() hbox = QHBoxLayout(self) hbox.setContentsMargins(0, 0, 0, 0) self.btnClose = QPushButton( self.style().standardIcon(QStyle.SP_DialogCloseButton), '') self.completer = QCompleter(self) self.pathLine = ui_tools.LineEditTabCompleter(self.completer) fileModel = QFileSystemModel(self.completer) fileModel.setRootPath("") self.completer.setModel(fileModel) self.pathLine.setCompleter(self.completer) self.btnOpen = QPushButton( self.style().standardIcon(QStyle.SP_ArrowRight), 'Open!') hbox.addWidget(self.btnClose) hbox.addWidget(QLabel(_translate("FileSystemOpener", "Path:"))) hbox.addWidget(self.pathLine) hbox.addWidget(self.btnOpen) self.pathLine.returnPressed.connect(self._open_file) self.btnOpen.clicked['bool'].connect(self._open_file)
def open_project(self, project): project_path = project.path qfsm = None # Should end up having a QFileSystemModel if project_path not in self.__projects: qfsm = QFileSystemModel() project.model = qfsm qfsm.setRootPath(project_path) qfsm.setFilter(QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) # If set to true items that dont match are displayed disabled qfsm.setNameFilterDisables(False) pext = ["*{0}".format(x) for x in project.extensions] logger.debug(pext) qfsm.setNameFilters(pext) self.__projects[project_path] = project self.__check_files_for(project_path) self.projectOpened.emit(project_path) else: qfsm = self.__projects[project_path] return qfsm
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) self._vbox.addWidget(self._file_view) # 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 _init_more(self): self.setWindowTitle('Tags4') self.dirModel = QFileSystemModel() self.dirModel.setFilter(QDir.AllDirs | QDir.Drives | QDir.Hidden | QDir.NoDotAndDotDot) qidx = self.dirModel.setRootPath(self.rootPath) self.dirChooser.setModel(self.dirModel) self.dirChooser.setRootIndex(qidx) self.dirChooser.clicked.connect(self.browseSelectedDir) self.imageList.itemSelectionChanged.connect(self._editTagsItems) self.imageList.itemDoubleClicked.connect(self._spawnViewerItem) self.imageList.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tabWidget.currentChanged.connect(self._tabSelected) self.tagChooser.changed.connect(self.browseSelectedTags)
def __init__(self, parent=None): super().__init__(parent) self.folderBox = QComboBox(self) self.explorerTree = FileTreeView(self) self.explorerTree.doubleClickCallback = self._fileOpened self.explorerModel = QFileSystemModel(self) self.explorerModel.setFilter(QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) self.explorerModel.setNameFilters(["*.py"]) self.explorerModel.setNameFilterDisables(False) self.explorerTree.setModel(self.explorerModel) for index in range(1, self.explorerModel.columnCount()): self.explorerTree.hideColumn(index) self.setCurrentFolder() self.folderBox.currentIndexChanged[int].connect(self.updateCurrentFolder) layout = QVBoxLayout(self) layout.addWidget(self.folderBox) layout.addWidget(self.explorerTree) layout.setContentsMargins(5, 5, 0, 5)
def __init__(self, parent=None): super(ComplexDialog, self).__init__(parent) self.setupUi(self) self.file_model = QFileSystemModel() self.bundle_model = QStringListModel() bundle_lists = [] self.bundle_model.setStringList(bundle_lists) root = self.file_model.setRootPath("/Volumes") self.columnView_files.setModel(self.file_model) self.columnView_files.setRootIndex(root) self.listView_files.setModel(self.bundle_model) # connect the buttons self.pushButton_add_file.clicked.connect(self._add_to_bundle) self.pushButton_remove_file.clicked.connect(self._remove_from_bundle) self.pushButton_cancle.clicked.connect(self.close_window) self.pushButton_add_object.clicked.connect(self.return_bundle)
def load_project_structure2(self): model = QFileSystemModel() model.setRootPath(My_Sync.path2) self.treeView_2.setModel(model) self.treeView_2.setRootIndex(model.index(My_Sync.path2)) self.treeView_2.show()
class Main(QtWidgets.QMainWindow): def __init__(self): super(Main, self).__init__() # ================================================= CARGA FICHERO UI ================================================== uifile = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'InterfaceUI.ui') uic.loadUi(uifile, self) # ================================================= INICIA BOTONES ==================================================== # Boton añadir carpeta: self.boton_anadir_carpeta.clicked.connect(self.fn_boton_anadir_carpeta) # Boton borrar fichero self.boton_borrar_fichero.clicked.connect(self.fn_boton_borrar_fichero) # Boton reset self.boton_Reset.clicked.connect(self.fn_boton_Reset) # Botones patogeno self.boton_AB.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_AB)) self.boton_BC.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_BC)) self.boton_CA.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_CA)) self.boton_EC.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_EC)) self.boton_PA.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_PA)) self.boton_SA.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_SA)) self.boton_MO.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_MO)) self.boton_LE.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_LE)) self.boton_AM.clicked.connect( lambda: self.obten_nombre_patogeno_analisis(nombre_boton=self. boton_AM)) # Botones dilucion self.boton_D1.clicked.connect( lambda: self.obten_nombre_dilucion(nombre_boton=self.boton_D1)) self.boton_D2.clicked.connect( lambda: self.obten_nombre_dilucion(nombre_boton=self.boton_D2)) self.boton_D3.clicked.connect( lambda: self.obten_nombre_dilucion(nombre_boton=self.boton_D3)) self.comboBox_DOtro.currentIndexChanged.connect( self.obten_nombre_dilucion_comboBox) # Botones tiempo self.boton_T0.clicked.connect( lambda: self.obten_nombre_tiempo(nombre_boton=self.boton_T0)) self.boton_T7.clicked.connect( lambda: self.obten_nombre_tiempo(nombre_boton=self.boton_T7)) self.boton_T14.clicked.connect( lambda: self.obten_nombre_tiempo(nombre_boton=self.boton_T14)) self.boton_T28.clicked.connect( lambda: self.obten_nombre_tiempo(nombre_boton=self.boton_T28)) # Boton zona self.comboBox_zona.currentIndexChanged.connect( self.obten_nombre_zona_comboBox) # Botones ver-ocultar self.boton_ver.clicked.connect(self.fn_boton_ver) self.boton_ocultar.clicked.connect(self.fn_boton_ocultar) # Boton inferencia self.boton_Evaluar.clicked.connect(self.fn_boton_Evaluar) # Botones ventana finish = QAction("Quit", self) finish.triggered.connect(self.closeEvent) # Tabla resultados # columnas = ['ID Placa', 'CH', 'Ref', 'Resultado'] # self.tabla.setColumnCount(4) # self.tabla.setRowCount(1) # self.tabla.setHorizontalHeaderLabels(columnas) # self.tabla.setItem(0, 0, QTableWidgetItem('Hola')) # self.tabla.cellClicked.connect(self.fn_mostrarItem) self.db = QSqlDatabase.addDatabase('QODBC') self.db.setDatabaseName(CONN_STRING) self.db.open() self.qry = QSqlQuery(self.db) self.modelo_query = QSqlQueryModel() SQL_STATEMENT = 'INSERT INTO dbo.Tabla_Placa(id_TipoAnalisis, id_TipoPatogeno) VALUES (AG, EC)' self.ejecuta_query(SQL_STATEMENT) # Botones camara self.boton_camara.clicked.connect(self.fn_boton_camara) self.boton_CapturaImagen.clicked.connect(self.fn_boton_CapturaImagen) self.FLAG_CAMARA_ACTIVA = 0 self.FLAG_CAPTURA_IMAGEN = 0 self.inicializa_nombre_imagen() # Botones edicion self.boton_lapiz.clicked.connect(self.fn_boton_lapiz) self.boton_borrar.clicked.connect(self.fn_boton_borrar) self.boton_validar.clicked.connect(self.fn_boton_validar) self.boton_cancelar.clicked.connect(self.fn_boton_cancelar) self.boton_ausencia.clicked.connect(self.fn_boton_ausencia) self.boton_presencia.clicked.connect(self.fn_boton_presencia) self.visor.mousePressEvent = self.mousePressEvent self.primer_click_x = 0 self.primer_click_y = 0 self.segundo_click_x = 0 self.segundo_click_y = 0 self.lista_nuevas_boxes = [] self.lista_borrar_boxes = [] self.FLAG_DIBUJAR = False self.FLAG_BORRAR = False self.FLAG_PRIMER_CLICK = True self.FLAG_SEGUNDO_CLICK = False self.FLAG_VALIDAR_EDICION_DETECCION = False self.FLAG_VALIDAR_EDICION_CLASIFICACION = False # ================================================= INICIA DIRECTORIOS ============================================ """ El pipeline de este apartado se encarga de obtener y mostrar las imagenes que hay en el directorio, incluyendo las distintas subcarpetas de tipos de analisis, refererencias, etc. Concretamente, al clicar sobre el directorio de tipos de analisis, se actualiza su hijo, y asi consecutivamente. Para ello se han creado unas funciones externas que se encargan de ello. Además, tambien se obtiene la ruta de la imagen objetivo seleccionada para poder usarla en el resto de funciones de la interfaz. Si el elemento seleccionado es una imagen, se mostrará en el visor. Si esta imagen se ha inferenciado anteriormente, se mostrará la imagen con las regiones. Si no se ha inferenciado, se habilitará el botón de evaluacion de placa. """ # Asociamos la ruta donde se encuentran las carpetas de los tipos de analisis y creamos el objeto para listar el directorio self.dirModel = QFileSystemModel() self.dirModel.setRootPath(PATH_IMGS_PRUEBA) # Mediante la funcion externa, se recorren todos los ficheros existentes en el directorio padre lista_primer_directorio(self.lista_analisis, self.dirModel) # Mediante los clicks en las carpetas de los subdirectorios se llama a ciertas funciones que recorren el interior de # la carpeta seleccionada y lo muestran por pantalla. self.lista_analisis.clicked.connect(lambda: lista_resto_directorios( self.lista_analisis, self.lista_lotes, self.lista_imagenes, self. dirModel, 1)) self.lista_lotes.clicked.connect(lambda: lista_resto_directorios( self.lista_lotes, self.lista_imagenes, None, self.dirModel)) self.lista_lotes.clicked.connect( lambda: self.obten_path_del_directorio(Qlist=self.lista_lotes)) self.lista_imagenes.clicked.connect( lambda: self.obten_path_del_directorio(Qlist=self.lista_imagenes)) # La siguiente funcion obtiene el elemento seleccionado de los directorios, y en caso de ser una imagen, la mostrará en el visor. # tambien se adquiere el nombre del elemento seleccionado para poder trabajar futuramente con el. def obten_path_del_directorio(self, Qlist): index = Qlist.currentIndex() self.path_seleccionado_del_directorio = self.dirModel.filePath(index) self.elemento_seleccionado = self.path_seleccionado_del_directorio.split( '/')[-1] self.label_elemento_seleccionado.setText(self.elemento_seleccionado) self.boton_Evaluar.setEnabled(True) if self.path_seleccionado_del_directorio[-3:] == 'png': self.decide_que_imagen_colocar_en_visor() # ================================================= VISOR DE IMAGEN ================================================== """Este apartado contiene las funciones que manejan la imagen que se coloca en el visor. En funcion de si la imagen ha sido inferenciada o no, se carga su solucion o no. Si existe solucion, se permite activar el modo edicion, y los botones de ver/ocultar regiones. Si se ha clicado una imagen y anteriormente la camara estaba encendida, esta se apagara, y la imagen mostrada se sustituira por la seleccionada. """ def decide_que_imagen_colocar_en_visor(self): # Miramos si la imagen ha sido inferencia, y en caso de que si, la colocamos en el visor. Si no, colocamos la imagen # sin inferenciar. self.path_seleccionado_del_directorio_modificado = self.path_seleccionado_del_directorio self.lista_archivos_directorio = os.listdir( os.path.join(self.path_seleccionado_del_directorio_modificado, os.pardir)) imagen_con_OK = self.path_seleccionado_del_directorio_modificado.split( '/')[-1][:-4] + "_OK.png" self.activar_desactivar_botones_edicion(0) self.boton_Evaluar.setEnabled(True) self.label_resultado_prediccion.setText("Resultado no disponible") if imagen_con_OK in self.lista_archivos_directorio: self.path_seleccionado_del_directorio_modificado = self.path_seleccionado_del_directorio_modificado[: -4] + "_OK.png" self.boton_ver.setDisabled(True) self.boton_ocultar.setEnabled(True) self.activar_desactivar_botones_edicion(1) self.label_resultado_prediccion.setText( muestra_resultado_enLabel( self.path_seleccionado_del_directorio_modificado)) if self.FLAG_CAMARA_ACTIVA: self.activa_desactiva_camara(1) self.coloca_imagen_seleccionada_en_visor( path=self.path_seleccionado_del_directorio_modificado) def coloca_imagen_seleccionada_en_visor(self, path, camara=0, imagen_camara=None): # Colocamos la imagen correspondiente en el visor if camara == 1: imagen_visor = QPixmap.fromImage(imagen_camara) else: imagen_visor = QPixmap(f"{path}") self.imagen_visor_escalada = imagen_visor.scaled( int(self.visor.width()), int(self.visor.height()), QtCore.Qt.KeepAspectRatio) self.visor.setPixmap(self.imagen_visor_escalada) # Obtenemos las medidas del visor y de la imagen para despues poder comprobar si los click en modo edicion se efectuan dentro de la imagen ancho_imagen_visor = imagen_visor.width() alto_imagen_visor = imagen_visor.height() ancho_imagen_visor_escalada = self.imagen_visor_escalada.width() alto_imagen_visor_escalada = self.imagen_visor_escalada.height() ancho_visor = self.visor.width() alto_visor = self.visor.height() self.ancho_zonaClick_imagen = [ (ancho_visor - ancho_imagen_visor_escalada) / 2, (ancho_visor - ancho_imagen_visor_escalada) / 2 + ancho_imagen_visor_escalada ] self.alto_zonaClick_imagen = [ (alto_visor - alto_imagen_visor_escalada) / 2, (alto_visor - alto_imagen_visor_escalada) / 2 + alto_imagen_visor_escalada ] self.offset_X = (ancho_visor - ancho_imagen_visor_escalada) / 2 self.offset_Y = (alto_visor - alto_imagen_visor_escalada) / 2 self.factor_escala_dimension_x = ancho_imagen_visor_escalada / ancho_imagen_visor self.factor_escala_dimension_y = alto_imagen_visor_escalada / alto_imagen_visor # ================================================== MANEJAR CAMARA ================================================== """A traves del siguiente apartado se maneja mediante multihilo la ejecucion de la camara, de manera que esta se activa o desactiva segun los botones pulsados. En funcion de esto, se activan y desactivan ciertos botones. Ademas, al final del apartado se configura el estilo del boton de activar la camara para saber la sitaucion de esta. """ def fn_boton_camara(self): self.activa_desactiva_camara(self.FLAG_CAMARA_ACTIVA) def recibeImagenCamara(self, imagen_camara): self.coloca_imagen_seleccionada_en_visor(path=None, camara=1, imagen_camara=imagen_camara) # self.lista_imagenes.setDisabled(False) if self.FLAG_CAPTURA_IMAGEN: self.guarda_imagen_capturada(imagen_camara) def activa_desactiva_camara(self, FLAG_CAMARA): # Se enchufa la camara if FLAG_CAMARA == 0: self.camaraQThread = ActivaCamara() self.boton_camara.setDisabled(True) self.camaraQThread.envio_imagen.connect(self.recibeImagenCamara) self.camaraQThread.envio_imagen_capturar.connect( self.recibeImagenCamara) self.camaraQThread.start() self.boton_CapturaImagen.setEnabled(True) self.activar_desactivar_botones_eleccion(1) self.activar_desactivar_botones_edicion(0) self.styleSheet_boton_camara(FLAG_CAMARA) self.boton_camara.setDisabled(False) self.FLAG_CAMARA_ACTIVA = 1 # Se apaga la camara else: self.camaraQThread.stop() self.boton_camara.setDisabled(True) self.boton_CapturaImagen.setDisabled(True) self.activar_desactivar_botones_eleccion(0) self.styleSheet_boton_camara(FLAG_CAMARA) self.boton_camara.setDisabled(False) self.FLAG_CAMARA_ACTIVA = 0 def fn_boton_CapturaImagen(self): self.FLAG_CAPTURA_IMAGEN = 1 def styleSheet_boton_camara(self, FLAG_CAMARA): if FLAG_CAMARA: self.boton_camara.setStyleSheet( "QPushButton{background-color: #06aa58;; border: None; border-radius: 5px;}" "QPushButton:disabled{background-color: rgb(124, 124, 124);} #gris oscuro" ) self.boton_camara.setText("ACTIVAR CAMARA") else: self.boton_camara.setStyleSheet( "QPushButton{background-color: #06aa58;; border: None; border-radius: 5px;}" "QPushButton:disabled{background-color: rgb(124, 124, 124);} #gris oscuro" ) self.boton_camara.setText("DESACTIVAR CAMARA") # ============================================== GUARDAR IMAGEN CAMARA =============================================== """A traves del siguiente apartado se configuran las funciones que permiten guardar una imagen cuando se pulsa el boton de capturar imagen. Simplemente, se forma el nombre de la imagen en funcion de los botones seleccionados (tipo de patogeno, referencia, fecha, etc), y este nombre se une a la ruta donde se quiere guardar la imagen, definida por las carpetas seleccionadas en el menu de archivos. En caso de que el nombre de imagen ya existe, automaticamente se renombran las imagenes para que no se sobreescriban. """ def guarda_imagen_capturada(self, imagen_camara): imagen = QPixmap.fromImage(imagen_camara) carpeta_destino = self.path_seleccionado_del_directorio self.comprobar_si_existe_nombre(self.nombre_imagen) imagen.save(f"{carpeta_destino}/{self.nombre_imagen}.png") self.FLAG_CAPTURA_IMAGEN = 0 def obten_nombre_patogeno_analisis(self, nombre_boton): try: self.id_analisis = TEXTO_CARPETAS_ANALISIS[ self.path_seleccionado_del_directorio.split('/')[-2]] except: texto = "Debes de seleccionar antes una carpeta de referencia (COLUMNA CENTRAL)" crea_mensaje_alerta(texto) self.id_num = "" self.id_patogeno = f"_{TEXTO_BOTONES_PATOGENO[nombre_boton.text()]}" self.forma_nombre_imagen() def obten_nombre_dilucion(self, nombre_boton): self.id_dilucion = f"-{TEXTO_BOTONES_DILUCION[nombre_boton.text()]}" self.forma_nombre_imagen() def obten_nombre_dilucion_comboBox(self): self.id_dilucion = f"-{TEXTO_COMBOBOX_DILUCION[self.comboBox_DOtro.currentText()]}" self.forma_nombre_imagen() def obten_nombre_tiempo(self, nombre_boton): self.id_tiempo = f"-{TEXTO_BOTONES_TIEMPO[nombre_boton.text()]}" self.forma_nombre_imagen() def obten_nombre_zona_comboBox(self): self.id_zona = f"-{TEXTO_COMBOBOX_ZONAS[self.comboBox_zona.currentText()]}" self.forma_nombre_imagen() def forma_nombre_imagen(self): self.nombre_imagen = f"{self.id_analisis}{self.id_patogeno}{self.id_num}{self.id_tiempo}{self.id_dilucion}{self.id_zona}" # self.comprobar_si_existe_nombre(self.nombre_imagen) self.label_nombre_imagen.setText(self.nombre_imagen) def comprobar_si_existe_nombre(self, nombre_imagen): if (f"{nombre_imagen}.png" or f"{nombre_imagen[0:5]}0{nombre_imagen[5:]}.png") in os.listdir( self.path_seleccionado_del_directorio): id = nombre_imagen.split('-')[0] if len(id) == 6: self.id_num = int(id[-1]) + 1 else: self.id_num = 1 os.rename( f"{self.path_seleccionado_del_directorio}/{nombre_imagen}.png", f"{self.path_seleccionado_del_directorio}/{nombre_imagen[0:5]}0{nombre_imagen[5:]}.png" ) self.forma_nombre_imagen() def inicializa_nombre_imagen(self): self.id_analisis = "" self.id_patogeno = "" self.id_tiempo = "" self.id_dilucion = "" self.id_num = "" self.id_zona = "" self.comboBox_zona.setCurrentIndex(0) self.comboBox_DOtro.setCurrentIndex(0) self.forma_nombre_imagen() def fn_boton_Reset(self): self.inicializa_nombre_imagen() # ============================================= AÑADIR / ELIMINAR FICHEROS ============================================ """Mediante las siguientes funciones se añadir o eliminan ficheros y/o carpetas seleecionadas en el menu de archivos. Siempre se pedira confirmacion en caso de eliminar algo a través de un mensaje de alerta. """ def fn_boton_anadir_carpeta(self): nombre_nueva_carpeta = self.edit_nombre_nueva_carpeta.text() if len(nombre_nueva_carpeta) != 0: index = self.lista_analisis.currentIndex() path_nueva_carpeta_aux = self.dirModel.filePath(index) path_nueva_carpeta = f"{path_nueva_carpeta_aux}/{nombre_nueva_carpeta}" try: os.mkdir(path_nueva_carpeta) except: texto = "La carpeta que intentas crear ya existe" crea_mensaje_alerta(texto) else: texto = "No has introducido ningun nombre de carpeta" crea_mensaje_alerta(texto) def fn_boton_borrar_fichero(self, event): borrar = QMessageBox.question( self, "ELIMINAR FICHERO", "¿ESTAS SEGURO DE ELIMINAR ESTE FICHERO?", QMessageBox.Yes | QMessageBox.No) if borrar == QMessageBox.Yes: if self.path_seleccionado_del_directorio[-4:] != ".png": shutil.rmtree(self.path_seleccionado_del_directorio) model_limpiar_lista_imagenes = QStandardItemModel() self.lista_imagenes.setModel(model_limpiar_lista_imagenes) model_limpiar_lista_imagenes.removeRow(0) else: os.remove(self.path_seleccionado_del_directorio) else: event.ignore() # ========================================= ACTIVAR DESACTIVAR CONJUNTO DE BOTONES =================================== """Aqui se configura la ativacion/desactivacion de los botones de la GUI dependiendo del modo de trabajo en el que estemos, ya sea evaluación, o captura de imagenes. """ def activar_desactivar_botones_eleccion(self, FLAG_BOTONES): self.boton_AB.setEnabled(FLAG_BOTONES) self.boton_BC.setEnabled(FLAG_BOTONES) self.boton_CA.setEnabled(FLAG_BOTONES) self.boton_EC.setEnabled(FLAG_BOTONES) self.boton_PA.setEnabled(FLAG_BOTONES) self.boton_SA.setEnabled(FLAG_BOTONES) self.boton_MO.setEnabled(FLAG_BOTONES) self.boton_LE.setEnabled(FLAG_BOTONES) self.boton_AM.setEnabled(FLAG_BOTONES) self.boton_D1.setEnabled(FLAG_BOTONES) self.boton_D2.setEnabled(FLAG_BOTONES) self.boton_D3.setEnabled(FLAG_BOTONES) self.comboBox_DOtro.setEnabled(FLAG_BOTONES) self.boton_T0.setEnabled(FLAG_BOTONES) self.boton_T7.setEnabled(FLAG_BOTONES) self.boton_T14.setEnabled(FLAG_BOTONES) self.boton_T28.setEnabled(FLAG_BOTONES) self.comboBox_zona.setEnabled(FLAG_BOTONES) def activar_desactivar_botones_edicion(self, FLAG_BOTONES): self.boton_ver.setEnabled(FLAG_BOTONES) self.boton_ocultar.setEnabled(FLAG_BOTONES) self.boton_lapiz.setEnabled(FLAG_BOTONES) self.boton_borrar.setEnabled(FLAG_BOTONES) # self.boton_validar.setEnabled(FLAG_BOTONES) # self.boton_cancelar.setEnabled(FLAG_BOTONES) self.boton_ausencia.setEnabled(FLAG_BOTONES) self.boton_presencia.setEnabled(FLAG_BOTONES) self.boton_Evaluar.setEnabled(FLAG_BOTONES) # ================================================= VER / OCULTAR RESULTADO ========================================== """Estas funciones permiten ocultar/mostrar las regiones de una imagen en caso de haberlas. """ def fn_boton_ver(self): self.coloca_imagen_seleccionada_en_visor( path=self.path_seleccionado_del_directorio_modificado) self.boton_ver.setDisabled(True) self.boton_ocultar.setEnabled(True) def fn_boton_ocultar(self): self.coloca_imagen_seleccionada_en_visor( path=self.path_seleccionado_del_directorio) self.boton_ocultar.setDisabled(True) self.boton_ver.setEnabled(True) # ================================================ FUNCIONES INFERENCIA ============================================== """En este apartado se ejecuta el pipeline asociado a la inferencia de la imagen seleccionada. Se ha de clicar en el boton evaluar, y entonces se ejecuta un multihilo que a su vez ejecuta distintas funciones. Entre ellas, elegir el modelo de prediccion, determinar si la tarea es de deteccion y clasificacion, y guardar el resultado en una nueva imagen/fichero. Además, se ha añadido una progressBar que se actualiza a medida que las imagenes se infernecias, ya que se puede inferenciar una unica placa si se selecciona la imagen, o todas las placas contenidas en la carpeta si se selecciona la carpeta. """ def fn_boton_Evaluar(self): self.progresBar.setValue(0) Main.setDisabled(self, True) self.prediccionQThread = CalculaPrediccion( self.path_seleccionado_del_directorio) self.prediccionQThread.envio_prediccion.connect(self.recibePrediccion) self.prediccionQThread.envio_valor_progressBar.connect( self.maneja_valor_progresBar) self.prediccionQThread.start() def recibePrediccion(self, prediccion): "Se obtiene un diccionario con los paths de las imagenes y la prediccion" self.prediccionQThread.stop() try: guarda_ImagenFichero_prediccion(prediccion) except: texto = "Todas las placas han sido ya evaluadas" Main.setDisabled(self, False) self.progresBar.setValue(0) crea_mensaje_alerta(texto) Main.setDisabled(self, False) self.progresBar.setValue(100) def maneja_valor_progresBar(self, valor): self.progresBar.setValue(valor) # ============================================== FUNCIONES CERRAR VENTANA ============================================ """A traves de estas funciones se define la logica de cierre de ventana. """ def closeEvent(self, event): """ Cerrar la ventana a través de el boton X de la esquina supeior derecha :param event: evento del raton :return: None """ close = QMessageBox.question(self, "SALIR", "¿ESTAS SEGURO/A DE QUERER SALIR?", QMessageBox.Yes | QMessageBox.No) if close == QMessageBox.Yes: event.accept() exit() else: event.ignore() def keyPressEvent(self, e): """ Cerrar la ventana a traves de la tecla ESC :param e: evento del teclado :return: None """ if e.key() == QtCore.Qt.Key_Escape: self.closeEvent(e) self.close() if e.key() == QtCore.Qt.Key_F11: if self.isMaximized(): self.showNormal() else: self.showMaximized() # =================================================== MODO EDICION ==================================================== """Es en el actual apartado se configuran las funciones de las botoneras de edicion. Para ello, se tiene en cuenta la pulsacion del raton. Si se selecciona el lapiz, se pintan las regiones en la pantalla mediante dos clicks y despues se han de confirmar los cambios. Esta confirmacion generara un nuevo archivo con las coordenadas de las regiones y una nueva imagen pintada. En caso de utilizar la herramienta de borrar, se selecciona la region a borrar y posteriormente se confirma, eliminando asi las respectivas coordenadas. Mediante los botones de ausencia y presencia, y se elige la clase a la cual pertene la placa que se esta editando. """ def fn_boton_lapiz(self): self.activar_desactivar_botones_edicion(False) self.boton_validar.setDisabled(False) self.boton_cancelar.setDisabled(False) self.FLAG_DIBUJAR = True self.FLAG_VALIDAR_EDICION_DETECCION = True def fn_boton_borrar(self): self.activar_desactivar_botones_edicion(False) self.boton_validar.setDisabled(False) self.boton_cancelar.setDisabled(False) self.FLAG_BORRAR = True self.FLAG_VALIDAR_EDICION_DETECCION = True def fn_boton_ausencia(self): self.activar_desactivar_botones_edicion(False) self.boton_validar.setDisabled(False) self.boton_cancelar.setDisabled(False) self.nueva_clase = 'AUSENCIA' self.FLAG_VALIDAR_EDICION_CLASIFICACION = True def fn_boton_presencia(self): self.activar_desactivar_botones_edicion(False) self.boton_validar.setDisabled(False) self.boton_cancelar.setDisabled(False) self.nueva_clase = 'PRESENCIA' self.FLAG_VALIDAR_EDICION_CLASIFICACION = True def fn_boton_validar(self): self.activar_desactivar_botones_edicion(True) self.boton_validar.setDisabled(True) self.boton_cancelar.setDisabled(True) if self.FLAG_DIBUJAR: nuevo_resultado = self.lista_nuevas_boxes elif self.FLAG_BORRAR: nuevo_resultado = self.lista_borrar_boxes elif self.FLAG_VALIDAR_EDICION_CLASIFICACION: nuevo_resultado = self.nueva_clase valida_cambios_edicion( nuevo_resultado, path_archivo=self.path_seleccionado_del_directorio_modificado, flag_dibujar=self.FLAG_DIBUJAR, flag_borrar=self.FLAG_BORRAR, flag_edicion_clasificacion=self.FLAG_VALIDAR_EDICION_CLASIFICACION) self.coloca_imagen_seleccionada_en_visor( path=self.path_seleccionado_del_directorio_modificado) self.label_resultado_prediccion.setText( muestra_resultado_enLabel( self.path_seleccionado_del_directorio_modificado)) self.lista_nuevas_boxes = [] self.lista_borrar_boxes = [] self.FLAG_DIBUJAR = False self.FLAG_BORRAR = False self.FLAG_VALIDAR_EDICION_CLASIFICACION = False def fn_boton_cancelar(self): self.activar_desactivar_botones_edicion(True) self.boton_validar.setDisabled(True) self.boton_cancelar.setDisabled(True) self.coloca_imagen_seleccionada_en_visor( path=self.path_seleccionado_del_directorio_modificado) self.label_resultado_prediccion.setText( muestra_resultado_enLabel( self.path_seleccionado_del_directorio_modificado)) self.lista_nuevas_boxes = [] self.lista_borrar_boxes = [] self.FLAG_DIBUJAR = False self.FLAG_BORRAR = False self.FLAG_VALIDAR_EDICION_DETECCION = False self.FLAG_VALIDAR_EDICION_CLASIFICACION = False def mousePressEvent(self, event): if self.FLAG_DIBUJAR: if self.FLAG_PRIMER_CLICK: self.primer_click = self.visor.mapFromParent(event.pos()) self.primer_click_x = self.primer_click.x() self.primer_click_y = self.primer_click.y() if comprueba_click_dentro_imagen(self.primer_click_x, self.primer_click_y, self.ancho_zonaClick_imagen, self.alto_zonaClick_imagen): self.FLAG_PRIMER_CLICK = False self.FLAG_SEGUNDO_CLICK = True elif self.FLAG_SEGUNDO_CLICK: self.segundo_click = self.visor.mapFromParent(event.pos()) self.segundo_click_x = self.segundo_click.x() self.segundo_click_y = self.segundo_click.y() if comprueba_click_dentro_imagen(self.segundo_click_x, self.segundo_click_y, self.ancho_zonaClick_imagen, self.alto_zonaClick_imagen): self.FLAG_PRIMER_CLICK = True self.FLAG_SEGUNDO_CLICK = False dibuja_region(QPainter(self.visor.pixmap()), self.primer_click_x, self.primer_click_y, self.segundo_click_x, self.segundo_click_y, 'green', 3, self.offset_X, self.offset_Y) self.update() self.visor.update() # Guardamos en una lista la nueva region añadida box_a_anadir = [ int( min([ self.primer_click_x - self.offset_X, self.segundo_click_x - self.offset_X ]) / self.factor_escala_dimension_x), int( min([ self.primer_click_y - self.offset_Y, self.segundo_click_y - self.offset_Y ]) / self.factor_escala_dimension_y), int( max([ self.primer_click_x - self.offset_X, self.segundo_click_x - self.offset_X ]) / self.factor_escala_dimension_x), int( max([ self.primer_click_y - self.offset_Y, self.segundo_click_y - self.offset_Y ]) / self.factor_escala_dimension_y) ] self.lista_nuevas_boxes.append(box_a_anadir) elif self.FLAG_BORRAR: self.click_borrar = self.visor.mapFromParent(event.pos()) self.click_borrar_x = self.click_borrar.x() self.click_borrar_y = self.click_borrar.y() if comprueba_click_dentro_imagen(self.click_borrar_x, self.click_borrar_x, self.ancho_zonaClick_imagen, self.alto_zonaClick_imagen): coordenadas_click = [ int(self.click_borrar_x), int(self.click_borrar_y) ] box_a_borrar, click_correcto = borrar_region( QPainter(self.visor.pixmap()), coordenadas_click, self.path_seleccionado_del_directorio_modificado, 'red', 3, self.offset_X, self.offset_Y, self.factor_escala_dimension_x, self.factor_escala_dimension_y) if click_correcto: self.update() self.visor.update() self.lista_borrar_boxes.append(box_a_borrar) # def paintEvent(self, event): # if self.FLAG_DIBUJAR: # qp = QPainter(self.visor.pixmap()) # br = QtGui.QBrush(QColor(100, 10, 10, 40)) # qp.setBrush(br) # qp.drawRect(QtCore.QRect(self.begin, self.end)) # def mousePressEvent(self, event): # self.begin = self.visor.mapFromParent(event.pos()) # self.end = self.visor.mapFromParent(event.pos()) # self.update() # # self.visor.update() # def mouseMoveEvent(self, event): # self.end = self.visor.mapFromParent(event.pos()) # self.update() # # self.visor.update() # def mouseReleaseEvent(self, event): # self.begin = self.visor.mapFromParent(event.pos()) # self.end = self.visor.mapFromParent(event.pos()) # self.update() # self.visor.update() # =================================================== TABLA RESULTADOS ================================================== def fn_mostrarItem(self, fila, columna): try: print(self.tabla.item(fila, columna).text()) except: pass def ejecuta_query(self, sqlStatement): self.qry.prepare(sqlStatement) self.qry.exec() self.fn_muestra_datos(self.qry) def fn_muestra_datos(self, query): self.modelo_query.setQuery(query) self.tabla.setModel(self.modelo_query) self.tabla.show()
class FileChooser(QWidget): fileOpened = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) # TODO: migrate to FolderComboBox? self.folderBox = QComboBox(self) self.explorerTree = FileTreeView(self) self.explorerTree.doubleClickCallback = self._fileOpened self.explorerModel = QFileSystemModel(self) self.explorerModel.setFilter(QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) self.explorerModel.setNameFilters(["*.py"]) self.explorerModel.setNameFilterDisables(False) self.explorerTree.setModel(self.explorerModel) for index in range(1, self.explorerModel.columnCount()): self.explorerTree.hideColumn(index) self.setCurrentFolder() self.folderBox.currentIndexChanged[int].connect( self.updateCurrentFolder) layout = QVBoxLayout(self) layout.addWidget(self.folderBox) layout.addWidget(self.explorerTree) layout.setContentsMargins(5, 5, 0, 0) def _fileOpened(self, modelIndex): path = self.explorerModel.filePath(modelIndex) if os.path.isfile(path): self.fileOpened.emit(path) def currentFolder(self): return self.explorerModel.rootPath() def setCurrentFolder(self, path=None): if path is None: app = QApplication.instance() path = app.getScriptsDirectory() else: assert os.path.isdir(path) self.explorerModel.setRootPath(path) self.explorerTree.setRootIndex(self.explorerModel.index(path)) self.folderBox.blockSignals(True) self.folderBox.clear() style = self.style() dirIcon = style.standardIcon(style.SP_DirIcon) self.folderBox.addItem(dirIcon, os.path.basename(path)) self.folderBox.insertSeparator(1) self.folderBox.addItem(self.tr("Browse…")) self.folderBox.setCurrentIndex(0) self.folderBox.blockSignals(False) def updateCurrentFolder(self, index): if index < self.folderBox.count() - 1: return path = QFileDialog.getExistingDirectory(self, self.tr("Choose Directory"), self.currentFolder(), QFileDialog.ShowDirsOnly) if path: QSettings().setValue("scripting/path", path) self.setCurrentFolder(path)
class PBTKGUI(QApplication): def __init__(self): super().__init__(argv) signal(SIGINT, SIG_DFL) views = dirname(realpath(__file__)) + '/views/' self.welcome = loadUi(views + 'welcome.ui') self.choose_extractor = loadUi(views + 'choose_extractor.ui') self.choose_proto = loadUi(views + 'choose_proto.ui') self.create_endpoint = loadUi(views + 'create_endpoint.ui') self.choose_endpoint = loadUi(views + 'choose_endpoint.ui') self.fuzzer = loadUi(views + 'fuzzer.ui') self.welcome.step1.clicked.connect(self.load_extractors) self.choose_extractor.rejected.connect( partial(self.set_view, self.welcome)) self.choose_extractor.extractors.itemClicked.connect( self.prompt_extractor) self.welcome.step2.clicked.connect(self.load_protos) self.proto_fs = QFileSystemModel() self.choose_proto.protos.setModel(self.proto_fs) self.proto_fs.directoryLoaded.connect( self.choose_proto.protos.expandAll) for i in range(1, self.proto_fs.columnCount()): self.choose_proto.protos.hideColumn(i) self.choose_proto.protos.setRootIndex( self.proto_fs.index(str(BASE_PATH / 'protos'))) self.choose_proto.rejected.connect(partial(self.set_view, self.welcome)) self.choose_proto.protos.clicked.connect(self.new_endpoint) self.create_endpoint.transports.itemClicked.connect( self.pick_transport) self.create_endpoint.loadRespPbBtn.clicked.connect( self.load_another_pb) self.create_endpoint.rejected.connect( partial(self.set_view, self.choose_proto)) self.create_endpoint.buttonBox.accepted.connect(self.write_endpoint) self.welcome.step3.clicked.connect(self.load_endpoints) self.choose_endpoint.rejected.connect( partial(self.set_view, self.welcome)) self.choose_endpoint.endpoints.itemClicked.connect(self.launch_fuzzer) self.fuzzer.rejected.connect( partial(self.set_view, self.choose_endpoint)) self.fuzzer.fuzzFields.clicked.connect(self.fuzz_endpoint) self.fuzzer.deleteThis.clicked.connect(self.delete_endpoint) self.fuzzer.comboBox.activated.connect(self.launch_fuzzer) self.fuzzer.urlField.setWordWrapMode(QTextOption.WrapAnywhere) for tree in (self.fuzzer.pbTree, self.fuzzer.getTree): tree.itemEntered.connect(lambda item, _: item.edit() if hasattr(item, 'edit') else None) tree.itemClicked.connect( lambda item, col: item.update_check(col=col)) tree.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.welcome.mydirLabel.setText(self.welcome.mydirLabel.text() % BASE_PATH) self.welcome.mydirBtn.clicked.connect( partial(QDesktopServices.openUrl, QUrl.fromLocalFile(str(BASE_PATH)))) self.set_view(self.welcome) self.exec_() """ Step 1 - Extract .proto structures from apps """ def load_extractors(self): self.choose_extractor.extractors.clear() for name, meta in extractors.items(): item = QListWidgetItem(meta['desc'], self.choose_extractor.extractors) item.setData(Qt.UserRole, name) self.set_view(self.choose_extractor) def prompt_extractor(self, item): extractor = extractors[item.data(Qt.UserRole)] inputs = [] if not assert_installed(self.view, **extractor.get('depends', {})): return if not extractor.get('pick_url', False): files, mime = QFileDialog.getOpenFileNames() for path in files: inputs.append((path, Path(path).stem)) else: text, good = QInputDialog.getText(self.view, ' ', 'Input an URL:') if text: url = urlparse(text) inputs.append((url.geturl(), url.netloc)) if inputs: wait = QProgressDialog('Extracting .proto structures...', None, 0, 0) wait.setWindowTitle(' ') self.set_view(wait) self.worker = Worker(inputs, extractor) self.worker.progress.connect(self.extraction_progress) self.worker.finished.connect(self.extraction_done) self.worker.signal_proxy.connect(self.signal_proxy) self.worker.start() def extraction_progress(self, info, progress): self.view.setLabelText(info) if progress is not None: self.view.setRange(0, 100) self.view.setValue(progress * 100) else: self.view.setRange(0, 0) def extraction_done(self, outputs): nb_written_all, wrote_endpoints = 0, False for folder, output in outputs.items(): nb_written, wrote_endpoints = extractor_save( BASE_PATH, folder, output) nb_written_all += nb_written if wrote_endpoints: self.set_view(self.welcome) QMessageBox.information( self.view, ' ', '%d endpoints and their <i>.proto</i> structures have been extracted! You can now reuse the <i>.proto</i>s or fuzz the endpoints.' % nb_written_all) elif nb_written_all: self.set_view(self.welcome) QMessageBox.information( self.view, ' ', '%d <i>.proto</i> structures have been extracted! You can now reuse the <i>.protos</i> or define endpoints for them to fuzz.' % nb_written_all) else: self.set_view(self.choose_extractor) QMessageBox.warning( self.view, ' ', 'This extractor did not find Protobuf structures in the corresponding format for specified files.' ) """ Step 2 - Link .protos to endpoints """ # Don't load .protos from the filesystem until asked to, in order # not to slow down startup. def load_protos(self): self.proto_fs.setRootPath(str(BASE_PATH / 'protos')) self.set_view(self.choose_proto) def new_endpoint(self, path): if not self.proto_fs.isDir(path): path = self.proto_fs.filePath(path) if assert_installed(self.choose_proto, binaries=['protoc']): if not getattr(self, 'only_resp_combo', False): self.create_endpoint.pbRequestCombo.clear() self.create_endpoint.pbRespCombo.clear() has_msgs = False for name, cls in load_proto_msgs(path): has_msgs = True if not getattr(self, 'only_resp_combo', False): self.create_endpoint.pbRequestCombo.addItem( name, (path, name)) self.create_endpoint.pbRespCombo.addItem( name, (path, name)) if not has_msgs: QMessageBox.warning( self.view, ' ', 'There is no message defined in this .proto.') return self.create_endpoint.reqDataSubform.hide() if not getattr(self, 'only_resp_combo', False): self.create_endpoint.endpointUrl.clear() self.create_endpoint.transports.clear() self.create_endpoint.sampleData.clear() self.create_endpoint.pbParamKey.clear() self.create_endpoint.parsePbCheckbox.setChecked(False) for name, meta in transports.items(): item = QListWidgetItem(meta['desc'], self.create_endpoint.transports) item.setData(Qt.UserRole, (name, meta.get('ui_data_form'))) elif getattr(self, 'saved_transport_choice'): self.create_endpoint.transports.setCurrentItem( self.saved_transport_choice) self.pick_transport(self.saved_transport_choice) self.saved_transport_choice = None self.only_resp_combo = False self.set_view(self.create_endpoint) def pick_transport(self, item): name, desc = item.data(Qt.UserRole) self.has_pb_param = desc and 'regular' in desc self.create_endpoint.reqDataSubform.show() if self.has_pb_param: self.create_endpoint.pbParamSubform.show() else: self.create_endpoint.pbParamSubform.hide() self.create_endpoint.sampleDataLabel.setText( 'Sample request data, one per line (in the form of %s):' % desc) def load_another_pb(self): self.only_resp_combo = True self.saved_transport_choice = self.create_endpoint.transports.currentItem( ) self.set_view(self.choose_proto) def write_endpoint(self): request_pb = self.create_endpoint.pbRequestCombo.itemData( self.create_endpoint.pbRequestCombo.currentIndex()) url = self.create_endpoint.endpointUrl.text() transport = self.create_endpoint.transports.currentItem() sample_data = self.create_endpoint.sampleData.toPlainText() pb_param = self.create_endpoint.pbParamKey.text() has_resp_pb = self.create_endpoint.parsePbCheckbox.isChecked() resp_pb = self.create_endpoint.pbRespCombo.itemData( self.create_endpoint.pbRespCombo.currentIndex()) if not (request_pb and urlparse(url).netloc and transport and (not self.has_pb_param or pb_param) and (not has_resp_pb or resp_pb)): QMessageBox.warning( self.view, ' ', 'Please fill all relevant information fields.') else: json = { 'request': { 'transport': transport.data(Qt.UserRole)[0], 'proto_path': request_pb[0].replace(str(BASE_PATH / 'protos'), '').strip('/\\'), 'proto_msg': request_pb[1], 'url': url } } if self.has_pb_param: json['request']['pb_param'] = pb_param sample_data = list(filter(None, sample_data.split('\n'))) if sample_data: transport_obj = transports[transport.data(Qt.UserRole)[0]] transport_obj = transport_obj['func'](pb_param, url) for sample_id, sample in enumerate(sample_data): try: sample = transport_obj.serialize_sample(sample) except Exception: return QMessageBox.warning( self.view, ' ', 'Some of your sample data is not in the specified format.' ) if not sample: return QMessageBox.warning( self.view, ' ', "Some of your sample data didn't contain the Protobuf parameter key you specified." ) sample_data[sample_id] = sample json['request']['samples'] = sample_data if has_resp_pb: json['response'] = { 'format': 'raw_pb', 'proto_path': resp_pb[0].replace(str(BASE_PATH / 'protos'), '').strip('/\\'), 'proto_msg': resp_pb[1] } insert_endpoint(BASE_PATH / 'endpoints', json) QMessageBox.information(self.view, ' ', 'Endpoint created successfully.') self.set_view(self.welcome) def load_endpoints(self): self.choose_endpoint.endpoints.clear() for name in listdir(str(BASE_PATH / 'endpoints')): if name.endswith('.json'): item = QListWidgetItem( name.split('.json')[0], self.choose_endpoint.endpoints) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) pb_msg_to_endpoints = defaultdict(list) with open(str(BASE_PATH / 'endpoints' / name)) as fd: for endpoint in load(fd): pb_msg_to_endpoints[endpoint['request']['proto_msg']. split('.')[-1]].append(endpoint) for pb_msg, endpoints in pb_msg_to_endpoints.items(): item = QListWidgetItem(' ' * 4 + pb_msg, self.choose_endpoint.endpoints) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) for endpoint in endpoints: item = QListWidgetItem( ' ' * 8 + (urlparse(endpoint['request']['url']).path or '/'), self.choose_endpoint.endpoints) item.setData(Qt.UserRole, endpoint) self.set_view(self.choose_endpoint) """ Step 3: Fuzz and test endpoints live """ def launch_fuzzer(self, item): if type(item) == int: data, sample_id = self.fuzzer.comboBox.itemData(item) else: data, sample_id = item.data(Qt.UserRole), 0 if data and assert_installed(self.view, binaries=['protoc']): self.current_req_proto = BASE_PATH / 'protos' / data['request'][ 'proto_path'] self.pb_request = load_proto_msgs(self.current_req_proto) self.pb_request = dict( self.pb_request)[data['request']['proto_msg']]() if data.get('response') and data['response']['format'] == 'raw_pb': self.pb_resp = load_proto_msgs(BASE_PATH / 'protos' / data['response']['proto_path']) self.pb_resp = dict( self.pb_resp)[data['response']['proto_msg']] self.pb_param = data['request'].get('pb_param') self.base_url = data['request']['url'] self.endpoint = data self.transport_meta = transports[data['request']['transport']] self.transport = self.transport_meta['func'](self.pb_param, self.base_url) sample = '' if data['request'].get('samples'): sample = data['request']['samples'][sample_id] self.get_params = self.transport.load_sample( sample, self.pb_request) # Get initial data into the Protobuf tree view self.fuzzer.pbTree.clear() self.ds_items = defaultdict(dict) self.ds_full_names = {} self.parse_desc(self.pb_request.DESCRIPTOR, self.fuzzer.pbTree) self.parse_fields(self.pb_request) # Do the same for transport-specific data self.fuzzer.getTree.clear() if self.transport_meta.get('ui_tab'): self.fuzzer.tabs.setTabText(1, self.transport_meta['ui_tab']) if self.get_params: for key, val in self.get_params.items(): ProtocolDataItem(self.fuzzer.getTree, key, val, self) else: self.fuzzer.tabs.setTabText(1, '(disabled)') # how to hide it ? # Fill the request samples combo box if we're loading a new # endpoint. if type(item) != int: if len(data['request'].get('samples', [])) > 1: self.fuzzer.comboBox.clear() for sample_id, sample in enumerate( data['request']['samples']): self.fuzzer.comboBox.addItem( sample[self.pb_param] if self.pb_param else str(sample), (data, sample_id)) self.fuzzer.comboBoxLabel.show() self.fuzzer.comboBox.show() else: self.fuzzer.comboBoxLabel.hide() self.fuzzer.comboBox.hide() self.set_view(self.fuzzer) self.fuzzer.frame.setUrl(QUrl("about:blank")) self.update_fuzzer() """ Parsing and rendering the Protobuf message to a tree view: Every Protobuf field is fed to ProtobufItem (a class inheriting QTreeWidgetItem), and the created object is saved in the ds_items entry for the corresponding descriptor. """ # First, parse the descriptor (structure) of the Protobuf message. def parse_desc(self, msg, item, path=[]): for ds in msg.fields: new_item = ProtobufItem(item, ds, self, path) if ds.type == ds.TYPE_MESSAGE and ds.full_name not in path: self.parse_desc(ds.message_type, new_item, path + [ds.full_name]) # Then, parse the fields (contents) of the Protobuf message. def parse_fields(self, msg, path=[]): for ds, val in msg.ListFields(): if ds.label == ds.LABEL_REPEATED: for val_index, val_value in enumerate(val): if ds.type == ds.TYPE_MESSAGE: self.ds_items[id(ds)][tuple(path)].setExpanded(True) self.ds_items[id(ds)][tuple(path)].setDefault( parent=msg, msg=val, index=val_index) self.parse_fields(val_value, path + [ds.full_name]) else: self.ds_items[id(ds)][tuple(path)].setDefault( val_value, parent=msg, msg=val, index=val_index) self.ds_items[id(ds)][tuple(path)].duplicate(True) else: if ds.type == ds.TYPE_MESSAGE: self.ds_items[id(ds)][tuple(path)].setExpanded(True) self.ds_items[id(ds)][tuple(path)].setDefault(parent=msg, msg=val) self.parse_fields(val, path + [ds.full_name]) else: self.ds_items[id(ds)][tuple(path)].setDefault(val, parent=msg, msg=val) def update_fuzzer(self): resp = self.transport.perform_request(self.pb_request, self.get_params) data, text, url, mime = resp.content, resp.text, resp.url, resp.headers[ 'Content-Type'].split(';')[0] meta = '%s %d %08x\n%s' % (mime, len(data), crc32(data) & 0xffffffff, resp.url) self.fuzzer.urlField.setText(meta) self.fuzzer.frame.update_frame(data, text, url, mime, getattr(self, 'pb_resp', None)) def fuzz_endpoint(self): QMessageBox.information(self.view, ' ', 'Automatic fuzzing is not implemented yet.') def delete_endpoint(self): if QMessageBox.question(self.view, ' ', 'Delete this endpoint?') == QMessageBox.Yes: path = str(BASE_PATH / 'endpoints' / (urlparse(self.base_url).netloc + '.json')) with open(path) as fd: json = load(fd) json.remove(self.endpoint) with open(path, 'w') as fd: dump(json, fd, ensure_ascii=False, indent=4) if not json: remove(path) self.load_endpoints() """ Utility methods follow """ def set_view(self, view): if hasattr(self, 'view'): self.view.hide() view.show() self.view = view resolution = QDesktopWidget().screenGeometry() view.move((resolution.width() / 2) - (view.frameSize().width() / 2), (resolution.height() / 2) - (view.frameSize().height() / 2)) """ signal() can't be called from inside a thread, and some extractors need it in order not to have their GUI child process interrupt signal catched by our main thread, so here is an ugly way to reach signal() through a slot. """ def signal_proxy(self, *args): signal(*args)
class DisplayDirectory(QMainWindow): def __init__(self): super().__init__() self.initializeUI() def initializeUI(self): """ Initialize the window and display its contents to the screen. """ self.setMinimumSize(500, 400) self.setWindowTitle('12.1 – View Directory GUI') self.createMenu() self.setupTree() self.show() def createMenu(self): """ Set up the menu bar. """ open_dir_act = QAction('Open Directory...', self) open_dir_act.triggered.connect(self.chooseDirectory) root_act = QAction("Return to Root", self) root_act.triggered.connect(self.returnToRootDirectory) # Create menubar menu_bar = self.menuBar() #menu_bar.setNativeMenuBar(False) # uncomment for macOS # Create file menu and add actions dir_menu = menu_bar.addMenu('Directories') dir_menu.addAction(open_dir_act) dir_menu.addAction(root_act) def setupTree(self): """ Set up the QTreeView so that it displays the contents of the local filesystem. """ self.model = QFileSystemModel() self.model.setRootPath('') self.tree = QTreeView() self.tree.setIndentation(10) self.tree.setModel(self.model) # Set up container and layout frame = QFrame() frame_v_box = QVBoxLayout() frame_v_box.addWidget(self.tree) frame.setLayout(frame_v_box) self.setCentralWidget(frame) def chooseDirectory(self): """ Select a directory to display. """ file_dialog = QFileDialog(self) file_dialog.setFileMode(QFileDialog.Directory) directory = file_dialog.getExistingDirectory(self, "Open Directory", "", QFileDialog.ShowDirsOnly) self.tree.setRootIndex(self.model.index(directory)) def returnToRootDirectory(self): """ Re-display the contents of the root directory. """ self.tree.setRootIndex(self.model.index(''))
class FileBrowser(QTreeView): def __init__(self, parent=None, textPad=None, notebook=None, codeView=None): super().__init__() self.path = self.checkPath(os.getcwd()) self.filename = None self.text = None self.initItems() self.textPad = textPad self.notebook = notebook self.codeView = codeView self.mainWindow = parent self.index = None self.copySourceFilePath = None # copy / paste items self.copySourceFileName = None self.isCopyFileFolder = None self.setStyleSheet(""" border: 5 px; background-color: black; color: white; alternate-background-color: #FFFFFF; selection-background-color: #3b5784; """) # Contextmenu self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.openMenu) self.popMenu = QMenu() self.popMenu.setStyleSheet(""" color: #FFFFFF; background-color: #2c2c2c; selection-background-color: #3b5784; alternate-background-color: #FFFFFF; """) infoAction = QAction('Info', self) infoAction.triggered.connect(self.onInfo) createFolderAction = QAction('Create New Folder', self) createFolderAction.triggered.connect(self.onCreateNewFolder) copyAction = QAction('Copy Item', self) copyAction.triggered.connect(self.onCopy) pasteAction = QAction('Paste Item', self) pasteAction.triggered.connect(self.onPaste) renameAction = QAction('Rename Item', self) renameAction.triggered.connect(self.onRename) deleteAction = QAction('Delete Item', self) deleteAction.triggered.connect(self.onDelete) terminalAction = QAction('Open Terminal', self) terminalAction.triggered.connect(self.onTerminal) self.popMenu.addAction(infoAction) self.popMenu.addSeparator() self.popMenu.addAction(createFolderAction) self.popMenu.addSeparator() self.popMenu.addAction(copyAction) self.popMenu.addAction(pasteAction) self.popMenu.addAction(renameAction) self.popMenu.addSeparator() self.popMenu.addAction(deleteAction) self.popMenu.addSeparator() self.popMenu.addAction(terminalAction) def openMenu(self, position): # -> open ContextMenu self.popMenu.exec_(self.mapToGlobal(position)) def onInfo(self): if not self.index: return index = self.index indexItem = self.model.index(index.row(), 0, index.parent()) fileName, filePath, fileDir, fileInfo = self.getFileInformation() bundle = fileInfo.isBundle() # bool dir = fileInfo.isDir() # bool file = fileInfo.isFile() # bool executable = fileInfo.isExecutable() # bool readable = fileInfo.isReadable() # bool writable = fileInfo.isWritable() # bool created = fileInfo.created() # QDateTime #modified = fileInfo.lastModified() # QDateTime owner = fileInfo.owner() # QString size = fileInfo.size() # QInt s = format(size, ',d') text = '' text += 'Type:\t' if bundle: text += 'Bundle\n\n' if dir: text += 'Path\n\n' if file: text += 'File\n\n' if readable: text += 'read:\tyes\n' else: text += 'read:\tno\n' if writable: text += 'write:\tyes\n' else: text += 'write:\tno\n' if executable: text += 'exec:\tyes\n\n' else: text += 'exec:\tno\n\n' text += 'size:\t' + str(s) + ' bytes' + '\n' text += 'owner:\t' + owner + '\n' text += 'created:\t' + str(created.date().day()) + '.' + \ str(created.date().month()) + '.' + \ str(created.date().year()) + ' ' + \ created.time().toString() + '\n' q = MessageBox(QMessageBox.Information, fileName, text, QMessageBox.NoButton) q.exec_() def onCreateNewFolder(self): if not self.index: return else: index = self.index fileName, filePath, fileDir, fileInfo = self.getFileInformation() path = os.getcwd() + '/' path = self.checkPath(path) index = self.index fileName, filePath, fileDir, fileInfo = self.getFileInformation() dialog = EnterDialog(self.mainWindow, fileName, \ filePath, fileDir, fileInfo, False, path) dialog.exec_() # return def onCopy(self): if not self.index: return fileName, filePath, fileDir, fileInfo = self.getFileInformation() if fileName == '..': self.clearSelection() self.mainWindow.statusBar.showMessage("can't copy this item !", 3000) self.copySourceFilePath = None self.copySourceFileName = None self.isCopyFileFolder = None return if fileDir: self.copySourceFilePath = filePath self.copySourceFileName = fileName self.isCopyFileFolder = True self.mainWindow.statusBar.showMessage('Path: <' + \ self.copySourceFileName + \ '> marked', 3000) else: self.copySourceFilePath = filePath self.copySourceFileName = fileName self.mainWindow.statusBar.showMessage('File: <' + \ self.copySourceFileName + \ '> marked', 3000) def onPaste(self): if not self.index: return if not self.copySourceFilePath: self.mainWindow.statusBar.showMessage('nothing marked !', 3000) return if not self.copySourceFileName: self.mainWindow.statusBar.showMessage('nothing marked !', 3000) return fileName, filePath, fileDir, fileInfo = self.getFileInformation() rootPath = os.getcwd() rootPath = self.checkPath(rootPath) fileList = os.listdir(self.path) # File list at current path if fileName == '..': # clicked on '..' rootPath = os.getcwd() rootPath = self.checkPath(rootPath) if fileDir and self.isCopyFileFolder: # copy path to another path if fileName == '..': path = os.getcwd() path = self.checkPath(path) else: path = filePath newPath = path + '/' + self.copySourceFileName fileList = os.listdir(path) if self.copySourceFileName in fileList: q = MessageBox( QMessageBox.Warning, "Error", "Another path with the same name already exists.", QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return if self.copySourceFilePath in newPath: q = MessageBox(QMessageBox.Critical, 'Error', 'Name of path already exists in new path', QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return try: os.mkdir(newPath) self.copytree(self.copySourceFilePath, newPath) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return elif fileDir and not self.isCopyFileFolder: # copy file to path if fileName == '..': path = os.getcwd() path = self.checkPath(path) else: path = filePath fileList = os.listdir(path) # File list at current path if self.copySourceFileName in fileList: result = MessageBox(QMessageBox.Warning, "Warning", "File already exists.\n" + "Continue ?", QMessageBox.Yes | QMessageBox.No) if (result.exec_() == QMessageBox.Yes): try: shutil.copy(self.copySourceFilePath, path) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return else: self.resetMarkedItems() return else: try: shutil.copy(self.copySourceFilePath, path) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return elif not fileDir and self.isCopyFileFolder: # copy path to selected file -> correct this user input ... newPath = rootPath + '/' + self.copySourceFileName if self.copySourceFileName in fileList: q = MessageBox( QMessageBox.Information, "Error", "Another path with the same name already exists.", QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return try: os.mkdir(newPath) self.copytree(self.copySourceFilePath, newPath) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return elif not fileDir and not self.isCopyFileFolder: # user copy file to another file -> correct this input fileList = os.listdir(rootPath) # File list in current path if self.copySourceFileName in fileList: result = MessageBox( QMessageBox.Warning, "Warning", "File with this name already exists !" + "Continue ?", QMessageBox.Yes | QMessageBox.No) if (result.exec_() == QMessageBox.Yes): try: shutil.copy(self.copySourceFilePath, rootPath) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) return else: self.resetMarkedItems(True) return else: try: shutil.copy(self.copySourceFilePath, rootPath) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.Ok) q.exec_() self.resetMarkedItems(True) return self.resetMarkedItems() def resetMarkedItems(self, showMessage=False): # reset marked items self.copySourceFilePath = None self.copySourceFileName = None self.isCopyFileFolder = None if showMessage: self.mainWindow.statusBar.showMessage('Mark removed !', 3000) # copy path with subfolder # thanks to stackoverflow.com ..... ! def copytree(self, src, dst, symlinks=False, ignore=None): if not os.path.exists(dst): os.makedirs(dst) if not os.path.exists(src): os.makedirs(src) for item in os.listdir(src): s = os.path.join(src, item) d = os.path.join(dst, item) if os.path.isdir(s): self.copytree(s, d, symlinks, ignore) else: if not os.path.exists( d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1: shutil.copy2(s, d) def onRename(self): if not self.index: return fileName, filePath, fileDir, fileInfo = self.getFileInformation() dialog = EnterDialog(self.mainWindow, fileName, filePath, fileDir, fileInfo, True) dialog.exec_() def onDelete(self): if not self.index: return fileName, filePath, fileDir, fileInfo = self.getFileInformation() if fileDir: if fileName == '..': self.mainWindow.statusBar.showMessage( 'can not delete this item !', 3000) return else: result = MessageBox(QMessageBox.Warning, 'Delete directory', '<b>' + filePath + '</b>' + " ?", QMessageBox.Yes | QMessageBox.No) if (result.exec_() == QMessageBox.Yes): try: shutil.rmtree(filePath) self.mainWindow.statusBar.showMessage('Done !', 3000) self.resetMarkedItems() except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) else: return else: pathList = filePath.split('/')[:-1] path = '' for elem in pathList: path += elem + '/' file = filePath.split('/')[-1] result = MessageBox(QMessageBox.Warning, 'Delete file', path + "<b>" + file + "</b>" + " ?", QMessageBox.Yes | QMessageBox.No) if (result.exec_() == QMessageBox.Yes): try: os.remove(filePath) self.mainWindow.statusBar.showMessage('Done !', 3000) except Exception as e: q = MessageBox(QMessageBox.Critical, "Error", str(e), QMessageBox.NoButton) q.exec_() self.resetMarkedItems(True) def onTerminal(self): c = Configuration() system = c.getSystem() command = c.getTerminal(system) thread = RunThread(command) thread.start() def initItems(self): font = QFont() font.setPixelSize(16) self.prepareModel(os.getcwd()) self.setToolTip(os.getcwd()) # prepare drag and drop self.setDragEnabled(False) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.setSizePolicy(sizePolicy) self.setAutoExpandDelay(2) self.setAlternatingRowColors(False) self.setAnimated(False) self.setIndentation(20) self.setSortingEnabled(False) self.setRootIsDecorated(False) self.setPalette(QPalette(Qt.black)) self.verticalScrollBar().setStyleSheet("""border: 20px solid black; background-color: darkgreen; alternate-background-color: #FFFFFF;""") self.horizontalScrollBar().setStyleSheet("""border: 20px solid black; background-color: darkgreen; alternate-background-color: #FFFFFF;""") self.setFont(font) # signals self.doubleClicked.connect(self.onDoubleClicked) self.clicked.connect(self.onClicked) self.pressed.connect(self.onClicked) #self.entered.connect(self.onEntered) self.columnMoved() # that hides the size, file type and last modified colomns self.setHeaderHidden(True) self.hideColumn(1) self.hideColumn(2) self.hideColumn(3) self.resize(400, 400) def prepareModel(self, path): self.model = QFileSystemModel() self.model.setRootPath(path) #model.setFilter(QDir.AllDirs |QDir.NoDotAndDotDot | QDir.AllEntries) self.model.setFilter(QDir.Files | QDir.AllDirs | QDir.NoDot | QDir.Hidden) #self.model.setNameFilters(self.filter) self.model.rootPathChanged.connect(self.onRootPathChanged) self.fsindex = self.model.setRootPath(path) self.setModel(self.model) self.setRootIndex(self.fsindex) def checkPath(self, path): if '\\' in path: path = path.replace('\\', '/') return path def getFileInformation(self): index = self.index indexItem = self.model.index(index.row(), 0, index.parent()) fileName = self.model.fileName(indexItem) filePath = self.model.filePath(indexItem) fileDir = self.model.isDir(indexItem) fileInfo = self.model.fileInfo(indexItem) fileName = self.checkPath(fileName) filePath = self.checkPath(filePath) return (fileName, filePath, fileDir, fileInfo) def onClicked(self, index): self.index = index #.... index des FileSystemModels indexItem = self.model.index(index.row(), 0, index.parent()) fileName, filePath, fileDir, fileInfo = self.getFileInformation() self.setToolTip(filePath) if fileDir: self.path = self.checkPath(os.getcwd()) self.filename = None else: self.filename = filePath self.path = self.checkPath(os.getcwd()) #print('self.filename: ', self.filename) #print('self.path: ', self.path) def refresh(self, dir=None): if not dir: dir = self.checkPath(os.getcwd()) else: dir = dir self.model.setRootPath(dir) if self.rootIsDecorated: self.setRootIsDecorated(False) self.clearSelection() def onDoubleClicked(self, index): self.index = index #.... wie oben ... def onClicked(...): indexItem = self.model.index(index.row(), 0, index.parent()) fileName, filePath, fileDir, fileInfo = self.getFileInformation() if fileDir: filePath = self.checkPath(filePath) try: os.chdir(filePath) except Exception as e: self.mainWindow.statusBar.showMessage(str(e), 3000) self.path = self.checkPath(os.getcwd()) self.model.setRootPath(filePath) if self.rootIsDecorated: self.setRootIsDecorated(False) else: self.filename = filePath try: with open(self.filename, 'r') as f: self.text = f.read() except Exception as e: self.mainWindow.statusBar.showMessage(str(e), 3000) self.filename = None return # debug if self.textPad: if not self.textPad.filename: editor = CodeEditor(self.mainWindow) editor.setText(self.text) editor.filename = filePath self.notebook.newTab(editor) self.textPad = editor x = self.notebook.count() # number of tabs index = x - 1 self.notebook.setCurrentIndex(index) tabName = os.path.basename(editor.filename) self.notebook.setTabText(x, tabName) self.textPad = editor #self.textPad.filename = filePath else: editor = CodeEditor(self.mainWindow) editor.setText(self.text) editor.filename = filePath tabName = os.path.basename(editor.filename) self.notebook.newTab(editor) x = self.notebook.count() # number of tabs index = x - 1 self.notebook.setCurrentIndex(index) self.textPad = editor #self.textPad.filename = filePath if not self.textPad: editor = CodeEditor(self.mainWindow) editor.filename = None self.notebook.newTab(editor) x = self.notebook.count() index = x - 1 self.notebook.setCurrentIndex(index) self.textPad = editor #self.textPad.filename = filePath # make codeView codeViewList = self.codeView.makeDictForCodeView(self.text) self.codeView.updateCodeView(codeViewList) # update textPad Autocomplete autocomplete = Qsci.QsciAPIs(self.textPad.lexer) self.textPad.autocomplete = autocomplete self.textPad.setPythonAutocomplete() self.clearSelection() def onRootPathChanged(self): self.setModel(None) self.setModel(self.model) self.fsindex = self.model.setRootPath(QDir.currentPath()) self.setRootIndex(self.fsindex) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.setSizePolicy(sizePolicy) self.setAutoExpandDelay(2) self.setAlternatingRowColors(False) self.setAnimated(True) self.setIndentation(20) self.setSortingEnabled(False) self.setRootIsDecorated(False) self.setHeaderHidden(True) self.hideColumn(1) self.hideColumn(2) self.hideColumn(3) self.setToolTip(QDir.currentPath()) self.path = os.getcwd() self.path = self.checkPath(self.path)
def data(self, index, role): if role == Qt.ToolTipRole: return self.filePath(index) else: return QFileSystemModel.data(self, index, role)
def __init__(self, *args): QFileSystemModel.__init__(self, *args)
class MainWindow(UiBase): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui() self.ui.setupUi(self) # button actions self.ui.actionexit.triggered.connect(self.exit) self.ui.actionAbout.triggered.connect(self.about) self.ui.actionOpen_Folder.triggered.connect(self.folderOpen) # lineEdit input from users. movies, tvmovies, tvshows self.ui.movie_lineEdit.textChanged.connect(self.text_Changed) self.ui.TVshow_movie_lineEdit.textChanged.connect(self.text_Changed) self.ui.TVshow_lineEdit.textChanged.connect(self.text_Changed) self.model = QFileSystemModel() # set defualt directories self.path = (expanduser("~") + '\\Videos') # windows path self.index = self.model.setRootPath(self.path) # path QT indexed print(self.index) print(self.index.data()) # gets Videos... nothing else... print(self.index.data( 1)) # I guess I am looking for the rest of the info. # if i add an int other then 0 it gives me the object again. # the document say nothing to me about what to do about this??? # self.new_path = (expanduser("~")+'\\Videos') # self.future_index = self.model.setRootPath(self.new_path) # <widget class="QTreeView" name="treeView"> self.ui.treeView.setModel(self.model) self.ui.treeView.setAnimated(False) self.ui.treeView.setIndentation(20) self.ui.treeView.setSortingEnabled(True) self.ui.treeView.setRootIndex(self.index) self.ui.treeView.setColumnHidden(1, True) self.ui.treeView.setColumnHidden(2, True) self.ui.treeView.setColumnHidden(3, True) # <widget class="QTreeView" name="treeView_future"> self.ui.treeView_future.setModel(self.model) self.ui.treeView_future.setAnimated(False) self.ui.treeView_future.setIndentation(20) self.ui.treeView_future.setSortingEnabled(True) # self.ui.treeView_future.setRootIndex(self.index) self.ui.treeView_future.setColumnHidden(1, True) self.ui.treeView_future.setColumnHidden(2, True) self.ui.treeView_future.setColumnHidden(3, True) # print('this is the path:', M_F_F(self.path)) # results of # print(str(M_F(self.path))) class fake_media(): now = datetime.now() fake_year = (now.strftime("%Y")) FakefolderFile = "C:\\mymovies\\B\\The Best Movie Ever.2018.PG\\The Best Movie Ever.2018.PG.mp4" # FakefolderFile = "C:\\The Best Movie Ever.2018.PG\\The Best Movie Ever.2018.PG.mp4" Title = "The Best Movie Ever" # Our fake Title Year = (fake_year) # always the curent year CR = "Pg" # CR = Certified Rating def F_O(self): # F_O = Fake Orginize parts = self.FakefolderFile.split("\\") A = str(self.Title) B = self.Title + str(self.Year) # B = re.match(self.Title, str(self.Year)) C = self.Title + str(self.Year) + self.CR # C = re.match(self.Title, str(self.Year), self.CR) D = "Must have Title and Year name" # print(parts) # print(parts[3]) # print(parts[3].split(".")) # print(A+B+C+D) # print(A, B, C, D) fake_media().F_O() # rules for media title class media_title(): pass # rules for media year class media_year(): pass # rules for media certified rating class media_certified_rating(): pass # user text input from movies, tv movies, tvshows def text_Changed(self): # user_text = [self.sender().objectName(), repr(self.sender().text())] # print(user_text) #wanting to know witch lineEdit text is changing? # if text input is from lineEdit change label text def label_output(self): Txt = self.sender().text() Objn = self.sender().objectName() if Objn == ('movie_lineEdit'): if Txt == (''): self.ui.movie_recipe_results.setText( 'Must start with Title') elif Txt == ('T'): self.ui.movie_recipe_results.setText('The Best Movie Ever') elif Txt == ('T Y'): self.ui.movie_recipe_results.setText( 'The Best Movie Ever 2018') elif Txt == ('T Y CR'): self.ui.movie_recipe_results.setText( 'The Best Movie Ever 2018 PG') elif Objn == ('TVshow_movie_lineEdit'): if Txt == (''): self.ui.Tvshow_movie_recipe_results.setText( 'Must start with Title') elif Txt == ('T'): self.ui.Tvshow_movie_recipe_results.setText( 'The Best Movie Ever') elif Txt == ('T Y'): self.ui.Tvshow_movie_recipe_results.setText( 'The Best Movie Ever 2018') elif Txt == ('T Y CR'): self.ui.Tvshow_movie_recipe_results.setText( 'The Best Movie Ever 2018 TV-PG') elif Objn == ('TVshow_lineEdit'): if Txt == (''): self.ui.Tvshow_recipe_results.setText( 'Must start with Title') elif Txt == ('T'): self.ui.Tvshow_recipe_results.setText( 'The Best TVShow Ever') elif Txt == ('T Y'): self.ui.Tvshow_recipe_results.setText( 'The Best TVShow Ever 2018') elif Txt == ('T Y CR'): self.ui.Tvshow_recipe_results.setText\ ('The Best TVShow Ever 2018 TV-PG') elif Txt == ('T Y CR S-E'): self.ui.Tvshow_recipe_results.setText\ ('The Best TVShow Ever 2018 TV-PG S01E01') elif Txt == ('T Y CR S-E ET'): self.ui.Tvshow_recipe_results.setText\ ('The Best TVShow Ever 2018 TV-PG S01E01 Best Episode') label_output(self) # for gwtting directories of media files def folderOpen(self): input_dir = QFileDialog.getExistingDirectory(None, 'Select a folder:', self.path) if input_dir == '': return self.path else: pass index = self.model.setRootPath(input_dir) self.ui.treeView.setRootIndex(index) # to show user what folders and files will look like after they submit def futureTreeview(self): self.ui.treeView.setRootIndex(self._future_index) # the about popup window def about(self): QMessageBox.about(self, "About", "This is a Template") # um, the exit for this application or software def exit(self): print('exit main window') QtWidgets.QApplication.instance().exit() def timon(self): # print('timer on') t = Timer(6.0, self.exit) t.start()
def setup_events(self): model = QFileSystemModel() root = model.setRootPath(self.root_path) self.filesTreeView.setModel(model) self.filesTreeView.setRootIndex(root) self.filesTreeView.selectionModel().selectionChanged.connect(self.item_selection_changed_slot)
def double_click_event(index): global model, label if model.isDir(index): 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 창 띄우기
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 createDockWindows(self): dock = QDockWidget("Folders", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) #Code to Create FileView Colums and FolderTree self.FileView = QtWidgets.QColumnView() self.FileView.setGeometry(QtCore.QRect(240, 10, 291, 281)) self.FolderTree = QtWidgets.QTreeView() self.FolderTree.setGeometry(QtCore.QRect(10, 10, 221, 281)) FolderTree = self.FolderTree #FolderTree.hidecolumn(1),... ?? to show only name column #include FolderTree to a Dock at the left side dock.setWidget(FolderTree) self.addDockWidget(Qt.LeftDockWidgetArea, dock) #set the model and rootpath for filling the FolderTree from self.ui dirmodel = QFileSystemModel() #set filter to show only folders dirmodel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) dirmodel.setRootPath(rootpath) #filemodel and filter for only files on right side filemodel = QFileSystemModel() filemodel.setFilter(QDir.NoDotAndDotDot | QDir.Files) filemodel.setRootPath(rootpath) FolderView = self.FolderTree FolderView.setModel(dirmodel) FolderView.setRootIndex(dirmodel.index(rootpath)) FileView = self.FileView FileView.setModel(filemodel) dock = QDockWidget("Files", self) dock.setWidget(FileView) self.addDockWidget(Qt.RightDockWidgetArea, dock) #important lines for the connection, which does not work self.FolderTree.clicked['QModelIndex'].connect(self.setpathonclick)
class Win(QMainWindow): def __init__(self, options): super(Win, self).__init__() self.db = dbtag.Db() self.db.open(options.db) self.db.create_tables() self.rootPath = options.filespath self._init_widgets() self._init_more() def _init_widgets(self): bigsplitter = QSplitter(Qt.Horizontal, self) self.setCentralWidget(bigsplitter) leftsplitter = QSplitter(Qt.Vertical, self) self.tabWidget = QTabWidget(self) self.tagChooser = TagChooser(self.db) self.dirChooser = QTreeView(self) self.tabWidget.addTab(self.dirChooser, 'Dir') self.tabWidget.addTab(self.tagChooser, 'Tags') self.tagEditor = TagEditor(self.db) self.imageList = ImageList() leftsplitter.addWidget(self.tabWidget) leftsplitter.addWidget(self.tagEditor) bigsplitter.addWidget(leftsplitter) bigsplitter.addWidget(self.imageList) self.viewer = ImageViewer(self.db) def _init_more(self): self.setWindowTitle('Tags4') self.dirModel = QFileSystemModel() self.dirModel.setFilter(QDir.AllDirs | QDir.Drives | QDir.Hidden | QDir.NoDotAndDotDot) qidx = self.dirModel.setRootPath(self.rootPath) self.dirChooser.setModel(self.dirModel) self.dirChooser.setRootIndex(qidx) self.dirChooser.clicked.connect(self.browseSelectedDir) self.imageList.itemSelectionChanged.connect(self._editTagsItems) self.imageList.itemDoubleClicked.connect(self._spawnViewerItem) self.imageList.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tabWidget.currentChanged.connect(self._tabSelected) self.tagChooser.changed.connect(self.browseSelectedTags) def editTags(self, path): self.tagEditor.setFile(path) def editTagsItems(self, paths): self.tagEditor.setFiles(paths) def spawnViewer(self, files, currentFile): self.viewer.spawn(files, currentFile) @Slot() def _editTagsItems(self): self.editTagsItems([qitem.getPath() for qitem in self.imageList.selectedItems()]) @Slot(QListWidgetItem) def _spawnViewerItem(self, qitem): self.spawnViewer(self.imageList.getFiles(), qitem.getPath()) @Slot() def browseSelectedDir(self): path = self.dirModel.filePath(self.dirChooser.currentIndex()) if not path: return files = [os.path.join(path, f) for f in os.listdir(path)] files = filter(os.path.isfile, files) files.sort() self.imageList.setFiles(files) @Slot() def browseSelectedTags(self): self.imageList.setFiles(self.tagChooser.matchingFiles()) @Slot(int) def _tabSelected(self, idx): if idx == 0: self.browseSelectedDir() else: self.browseSelectedTags() def browsePath(self, path): self.imageList.setFiles(os.path.join(path, f) for f in os.listdir(path))
def load_tree(self, project): """Load the tree view on the right based on the project selected.""" qfsm = QFileSystemModel() qfsm.setRootPath(project.path) load_index = qfsm.index(qfsm.rootPath()) qfsm.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) qfsm.setNameFilterDisables(False) pext = ["*{0}".format(x) for x in project.extensions] qfsm.setNameFilters(pext) self._tree.setModel(qfsm) self._tree.setRootIndex(load_index) t_header = self._tree.header() t_header.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) t_header.setSectionResizeMode(0, QHeaderView.Stretch) t_header.setStretchLastSection(False) t_header.setSectionsClickable(True) self._tree.hideColumn(1) # Size self._tree.hideColumn(2) # Type self._tree.hideColumn(3) # Modification date
def setup_ui(self): self.ui.setupUi(self) settings = QSettings() self.ui.splitter.setSizes([600, 1000]) self.ui.splitter.setChildrenCollapsible(False) # Set up folder view lastDir = settings.value("mainwindow/workingDirectory", QDir.homePath()) log.debug('Current directory: {currentDir}'.format(currentDir=lastDir)) self.fileModel = QFileSystemModel(self) self.fileModel.setFilter(QDir.AllDirs | QDir.Dirs | QDir.Drives | QDir.NoDotAndDotDot | QDir.Readable | QDir.Executable | QDir.Writable) self.fileModel.iconProvider().setOptions( QFileIconProvider.DontUseCustomDirectoryIcons) self.fileModel.setRootPath(QDir.rootPath()) self.fileModel.directoryLoaded.connect(self.onFileModelDirectoryLoaded) self.proxyFileModel = QSortFilterProxyModel(self) self.proxyFileModel.setSortRole(Qt.DisplayRole) self.proxyFileModel.setSourceModel(self.fileModel) self.proxyFileModel.sort(0, Qt.AscendingOrder) self.proxyFileModel.setSortCaseSensitivity(Qt.CaseInsensitive) self.ui.folderView.setModel(self.proxyFileModel) self.ui.folderView.setHeaderHidden(True) self.ui.folderView.hideColumn(3) self.ui.folderView.hideColumn(2) self.ui.folderView.hideColumn(1) index = self.fileModel.index(lastDir) proxyIndex = self.proxyFileModel.mapFromSource(index) self.ui.folderView.scrollTo(proxyIndex) self.ui.folderView.expanded.connect(self.onFolderViewExpanded) self.ui.folderView.clicked.connect(self.onFolderTreeClicked) self.ui.buttonFind.clicked.connect(self.onButtonFind) self.ui.buttonRefresh.clicked.connect(self.onButtonRefresh) # Set up introduction self.showInstructions() # Set up video view self.ui.filterLanguageForVideo.set_unknown_text(_('All languages')) self.ui.filterLanguageForVideo.selected_language_changed.connect( self.on_language_combobox_filter_change) # self.ui.filterLanguageForVideo.selected_language_changed.connect(self.onFilterLanguageVideo) self.videoModel = VideoModel(self) self.ui.videoView.setHeaderHidden(True) self.ui.videoView.setModel(self.videoModel) self.ui.videoView.activated.connect(self.onClickVideoTreeView) self.ui.videoView.clicked.connect(self.onClickVideoTreeView) self.ui.videoView.customContextMenuRequested.connect(self.onContext) self.videoModel.dataChanged.connect(self.subtitlesCheckedChanged) self.language_filter_change.connect( self.videoModel.on_filter_languages_change) self.ui.buttonSearchSelectVideos.clicked.connect( self.onButtonSearchSelectVideos) self.ui.buttonSearchSelectFolder.clicked.connect( self.onButtonSearchSelectFolder) self.ui.buttonDownload.clicked.connect(self.onButtonDownload) self.ui.buttonPlay.clicked.connect(self.onButtonPlay) self.ui.buttonIMDB.clicked.connect(self.onViewOnlineInfo) self.ui.videoView.setContextMenuPolicy(Qt.CustomContextMenu) # Drag and Drop files to the videoView enabled self.ui.videoView.__class__.dragEnterEvent = self.dragEnterEvent self.ui.videoView.__class__.dragMoveEvent = self.dragEnterEvent self.ui.videoView.__class__.dropEvent = self.dropEvent self.ui.videoView.setAcceptDrops(1) # FIXME: ok to drop this connect? # self.ui.videoView.clicked.connect(self.onClickMovieTreeView) self.retranslate()
class Script(QWidget, form_class): def __init__(self, parent=None): super(Script, self).__init__(parent) self.setupUi(self) # private variable self.__currentpath = "" self.__modfiedstate = False self._PyQtSignalConnect = console.PyQtSignalConnect() # treeView Size self.splitter.setSizes([ Config().getint('SIZE', 'QtScriptFileExplorer'), (self.size().width()) - Config().getint('SIZE', 'QtScriptFileExplorer') ]) # treeView model create self.model = QFileSystemModel() self.model.setNameFilters(["*.py"]) # treeView setting self.treeView.setModel(self.model) self.treeView.setRootIndex(self.model.setRootPath('./')) self.treeView.setAnimated(True) self.treeView.setSortingEnabled(False) [self.treeView.hideColumn(ii) for ii in range(1, 5)] self.treeView.header().setStretchLastSection(False) self.treeView.header().setSectionResizeMode(0, QHeaderView.Stretch) # signal connect self.treeView.activated.connect(lambda e : \ self._open_script(self.model.filePath(e))) self.btnSave.clicked.connect(lambda: self._save_script()) self.btnNew.clicked.connect(lambda: self._new_script()) self.btnRun.clicked.connect(lambda: self._run_script()) self.btnOpen.clicked.connect(lambda: self._btnOpen_clicked()) self.fontComboBox.currentFontChanged.connect( lambda x: self.plainTextEdit.setFont(x)) self.plainTextEdit.keyPressEvent = self._plainTextEdit_keyPressEvent self.plainTextEdit.wheelEvent = self._plainTextEdit_wheelEvent self.plainTextEdit.setAcceptDrops(True) self.plainTextEdit.dropEvent = lambda e: self._open_script(e.mimeData( ).urls()[0].toLocalFile()) self.plainTextEdit.modificationChanged.connect( lambda x: self._change_modified_state(x)) self._PyQtSignalConnect.script_run.connect( lambda: self.btnRun.animateClick()) def getstate(self): return self.__modfiedstate def _change_modified_state(self, param): self.__modfiedstate = param def _btnOpen_clicked(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)", options=options) if (os.path.isfile(fileName) == True): self._open_script(fileName) else: pass @ismodified def _new_script(self): self.plainTextEdit.clear() self._change_modified_state(False) def _save_script(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getSaveFileName( self, "QFileDialog.getSaveFileName()", self.__currentpath, "Python Files (*.py)", options=options) if fileName == "": pass else: with open(fileName, "w") as f: f.write(self.plainTextEdit.toPlainText()) self.__currentpath = fileName # when re save occurs, it will be used in default path self._change_modified_state(False) return fileName @ismodified def _open_script(self, path): try: with open(path) as f: self.__currentpath = path self.plainTextEdit.clear() self.plainTextEdit.setPlainText(f.read()) except UnicodeDecodeError as e: pass except PermissionError as e: pass def _change_root(self): text = self.lineEdit.displayText() self.treeView.setRootIndex(self.model.setRootPath(text)) self.lineEdit.clear() def _plainTextEdit_keyPressEvent(self, event): # this is monkey....... # how to change tab to 4 space ? if (event.key() == Qt.Key_Tab): self.plainTextEdit.insertPlainText(" " * 4) else: QPlainTextEdit.keyPressEvent(self.plainTextEdit, event) def _plainTextEdit_wheelEvent(self, event): if (event.modifiers() & Qt.ControlModifier): self._plainTextEdit_zoom(event.angleDelta().y()) else: QPlainTextEdit.wheelEvent(self.plainTextEdit, event) def _plainTextEdit_zoom(self, delta): if delta < 0: self.plainTextEdit.zoomOut(2) elif delta > 0: self.plainTextEdit.zoomIn(2) def _run_script(self): self.btnRun.setEnabled(False) console.cexec(self.plainTextEdit.toPlainText(), isfile=True) self.btnRun.setEnabled(True)
class Ui(QtWidgets.QMainWindow): # this safely gets a widget reference def getUI(self, type, name): x = self.findChild(type, name) if x is None: raise Exception('cannot find widget ' + name) return x def clear(self): if not self.capturing: self.canvas.clear() self.stage = 0 self.data = None self.done = True # we've not done anything yet # set image for input to processing # input: numpy w x h x 3 image, RGB 0-255 def setImage(self, img): # cv is bgr, qt (and sensible things) are rgb img = cv.cvtColor(img, cv.COLOR_BGR2RGB) # crop to ROI and resize # img = cropSquare(img,340,430,100) img = cv.resize(img, dsize=(600, 600), interpolation=cv.INTER_CUBIC) self.img = img self.clear() self.canvas.display(0, self.img) self.done = False # input: filename # output: numpy w x h x 3 image, RGB 0-255 def loadFile(self, fname): img = cv.imread(fname) print("Image read") if img is None: raise Exception('cannot read image') self.setImage(img) # open file, get ROI and convert to grey def openFileAction(self): fname, _ = QFileDialog.getOpenFileName(self, 'Open file', '.', "Image files (*.jpg *.gif)") if fname is None or fname == '': return self.loadFile(fname) def nextStage(self): if self.done: return print("Stage {0}, image {1} ".format(self.stage, self.img.shape)) start = time.perf_counter() # perform the next stage - the type of the image depends on the stage. # At input it's a 24-bit image. self.img, self.data, self.done, text = ellipse_blob.stage( self.stage, (self.img, self.data)) self.stage = self.stage + 1 self.canvas.display(self.stage, self.img) print("Time taken {0} ".format(time.perf_counter() - start)) if isinstance(text, tuple): text, status = text st = self.getUI(QtWidgets.QPlainTextEdit, 'status') st.appendPlainText(status) self.canvas.text(self.stage, text) def findEllipsesAction(self): while True: print("Stage ", self.done, self.stage) self.nextStage() if self.done: break def liveCaptureAction(self): self.capturing = not self.capturing b = self.getUI(QtWidgets.QPushButton, 'liveCaptureButton') if self.capturing: s = "End live" b.setStyleSheet('QPushButton {background-color:#ff8080;}') else: s = "Begin live" b.setStyleSheet('QPushButton {}') b.setText(s) def fileClickedAction(self, idx): if not self.dirModel.isDir(idx): item = self.dirModel.filePath(idx) self.loadFile(item) # confirm a quit menu action def confirmQuitAction(self): # reply = QMessageBox.question(self, # 'Confirm', # 'Really quit?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) # if reply == QMessageBox.Yes: # app.quit() app.quit() def tick(self): if self.capturing: if self.done: if self.cam is None: self.cam = cv.VideoCapture(self.camNo) self.cam.set(cv.CAP_PROP_FRAME_WIDTH, 640) self.cam.set(cv.CAP_PROP_FRAME_HEIGHT, 480) self.cam.set(cv.CAP_PROP_BUFFERSIZE, 1) ret, img = self.cam.read() if not ret: # no cam, should turn off button and capturing self.liveCaptureAction() else: self.setImage(img) self.done = False else: self.nextStage() def __init__(self, *args, **kwargs): super(Ui, self).__init__( *args, **kwargs) # Call the inherited classes __init__ method uic.loadUi('test.ui', self) # Load the .ui file # now we get references to the widgets we want and connect # things up. Brackets here to make the line break work. (self.getUI(QtWidgets.QAction, 'actionQuit').triggered.connect(self.confirmQuitAction)) (self.getUI(QtWidgets.QAction, 'actionOpen').triggered.connect(self.openFileAction)) (self.getUI(QtWidgets.QAction, 'actionLive').triggered.connect(self.liveCaptureAction)) (self.getUI(QtWidgets.QPushButton, 'findEllipsesButton').clicked.connect( self.findEllipsesAction)) (self.getUI(QtWidgets.QPushButton, 'liveCaptureButton').clicked.connect( self.liveCaptureAction)) # set up the file tree self.dirModel = QFileSystemModel() self.dirModel.setRootPath(QDir.currentPath()) self.dirModel.setNameFilters(["*.jpg", "*.png"]) tree = self.getUI(QtWidgets.QTreeView, 'treeView') tree.setModel(self.dirModel) tree.setRootIndex(self.dirModel.index(QDir.currentPath())) tree.setIndentation(10) tree.setSortingEnabled(True) tree.setColumnWidth(0, tree.width() / 1.5) tree.setColumnHidden(1, True) tree.setColumnHidden(2, True) tree.doubleClicked.connect(self.fileClickedAction) self.treeView = tree # set up the live camera system (to null) self.capturing = False self.cam = None # set up the drawing area and the timer which updates it self.canvas = self.getUI(QtWidgets.QWidget, 'view') self.timer = QTimer() self.timer.timeout.connect(self.tick) self.timer.start(100) self.clear() # set up internal state self.show() # Show the GUI
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): 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 | 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')]
def __init__(self): super().__init__(argv) signal(SIGINT, SIG_DFL) views = dirname(realpath(__file__)) + '/views/' self.welcome = loadUi(views + 'welcome.ui') self.choose_extractor = loadUi(views + 'choose_extractor.ui') self.choose_proto = loadUi(views + 'choose_proto.ui') self.create_endpoint = loadUi(views + 'create_endpoint.ui') self.choose_endpoint = loadUi(views + 'choose_endpoint.ui') self.fuzzer = loadUi(views + 'fuzzer.ui') self.welcome.step1.clicked.connect(self.load_extractors) self.choose_extractor.rejected.connect( partial(self.set_view, self.welcome)) self.choose_extractor.extractors.itemClicked.connect( self.prompt_extractor) self.welcome.step2.clicked.connect(self.load_protos) self.proto_fs = QFileSystemModel() self.choose_proto.protos.setModel(self.proto_fs) self.proto_fs.directoryLoaded.connect( self.choose_proto.protos.expandAll) for i in range(1, self.proto_fs.columnCount()): self.choose_proto.protos.hideColumn(i) self.choose_proto.protos.setRootIndex( self.proto_fs.index(str(BASE_PATH / 'protos'))) self.choose_proto.rejected.connect(partial(self.set_view, self.welcome)) self.choose_proto.protos.clicked.connect(self.new_endpoint) self.create_endpoint.transports.itemClicked.connect( self.pick_transport) self.create_endpoint.loadRespPbBtn.clicked.connect( self.load_another_pb) self.create_endpoint.rejected.connect( partial(self.set_view, self.choose_proto)) self.create_endpoint.buttonBox.accepted.connect(self.write_endpoint) self.welcome.step3.clicked.connect(self.load_endpoints) self.choose_endpoint.rejected.connect( partial(self.set_view, self.welcome)) self.choose_endpoint.endpoints.itemClicked.connect(self.launch_fuzzer) self.fuzzer.rejected.connect( partial(self.set_view, self.choose_endpoint)) self.fuzzer.fuzzFields.clicked.connect(self.fuzz_endpoint) self.fuzzer.deleteThis.clicked.connect(self.delete_endpoint) self.fuzzer.comboBox.activated.connect(self.launch_fuzzer) self.fuzzer.urlField.setWordWrapMode(QTextOption.WrapAnywhere) for tree in (self.fuzzer.pbTree, self.fuzzer.getTree): tree.itemEntered.connect(lambda item, _: item.edit() if hasattr(item, 'edit') else None) tree.itemClicked.connect( lambda item, col: item.update_check(col=col)) tree.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.welcome.mydirLabel.setText(self.welcome.mydirLabel.text() % BASE_PATH) self.welcome.mydirBtn.clicked.connect( partial(QDesktopServices.openUrl, QUrl.fromLocalFile(str(BASE_PATH)))) self.set_view(self.welcome) self.exec_()
class MainWindow(QMainWindow, form_class): def __init__(self): super().__init__() self.setupUi(self) self.image = None self.set_tree_view() self.set_radio_button() def set_tree_view(self): self.root_path = '../' self.file_system_model = QFileSystemModel() self.tree_view.setModel(self.file_system_model) self.file_system_model.setRootPath(self.root_path) self.tree_view.setRootIndex( self.file_system_model.index(self.root_path)) self.tree_view.setColumnWidth(0, 200) self.tree_view.setColumnHidden(1, True) self.tree_view.setColumnHidden(2, True) self.tree_view.setColumnHidden(3, True) self.tree_view.doubleClicked.connect(self.tree_view_double_clicked) def tree_view_double_clicked(self, index): if self.file_system_model.isDir(index): # print('Directory') pass else: path = self.file_system_model.filePath(index) self.image = cv2.imread(path) self.image_processing() def set_radio_button(self): self.radio_rgb.clicked.connect(self.image_processing) self.radio_gray.clicked.connect(self.image_processing) self.radio_bin.clicked.connect(self.image_processing) def image_processing(self): if self.image is None: return if self.radio_rgb.isChecked(): processed = self.image elif self.radio_gray.isChecked(): processed = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) else: gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) processed = (gray > 128).astype(np.uint8) * 255 if len(processed.shape) == 2: show_image = QtGui.QImage(processed, processed.shape[1], processed.shape[0], processed.shape[1], QtGui.QImage.Format_Grayscale8) else: show_image = QtGui.QImage(processed, processed.shape[1], processed.shape[0], processed.shape[1] * 3, QtGui.QImage.Format_BGR888) self.label_image.setPixmap(QtGui.QPixmap(show_image))
class FileTree(QWidget): def __init__(self, filter=['*.czi'], defaultfolder=r'c:\Zen_Output'): super(QWidget, self).__init__() # define filter to allowed file extensions #filter = ['*.czi', '*.ome.tiff', '*ome.tif' '*.tiff' '*.tif'] # define the style for the FileTree via s style sheet self.setStyleSheet(""" QTreeView:: item { background - color: rgb(38, 41, 48) font - weight: bold } QTreeView:: item: : selected { background - color: rgb(38, 41, 48) color: rgb(0, 255, 0) } QTreeView QHeaderView: section { background - color: rgb(38, 41, 48) color: rgb(255, 255, 255) } """) self.model = QFileSystemModel() self.model.setRootPath(defaultfolder) self.model.setFilter(QtCore.QDir.AllDirs | QDir.Files | QtCore.QDir.NoDotAndDotDot) self.model.setNameFilterDisables(False) self.model.setNameFilters(filter) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(defaultfolder)) self.tree.setAnimated(True) self.tree.setIndentation(20) self.tree.setSortingEnabled(False) header = self.tree.header() header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) windowLayout = QVBoxLayout() windowLayout.addWidget(self.tree) self.setLayout(windowLayout) self.tree.clicked.connect(self.on_treeView_clicked) def on_treeView_clicked(self, index): indexItem = self.model.index(index.row(), 0, index.parent()) filename = self.model.fileName(indexItem) filepath = self.model.filePath(indexItem) # open the file when clicked print('Opening ImageFile : ', filepath) open_image_stack(filepath)
class App(QMainWindow, QWidget): # 창의 대부분의 기능 def __init__(self): # 창 기본 세팅 설정 super().__init__() # Window options! self.title = 'HexQT' self.left = 0 self.top = 0 self.width = 1280 self.height = 840 self.rowSpacing = 4 # How many bytes before a double space. self.rowLength = 16 # 헥사 창에 얼마나 많은 byte 가 들어갈 것인지 self.byteWidth = 4 # How many bits to include in a byte. self.mode = Mode.READ self.initUI() def openFile(self): fileSelect = FileSelector() fileName = fileSelect.fileName self.readFile(fileName) # readFile ... Reads file data from a file in the form of bytes and generates the text for the hex-editor. def readFile(self, fileName): fileData = '' if fileName: with open(fileName, 'rb') as fileObj: fileData = fileObj.read() self.generateView(fileData) # saveFile ... Method for saving the edited hex file. def saveFile(self): print('Saved!') # generateView ... Generates text view for hexdump likedness. def generateView(self, text): space = ' ' bigSpace = ' ' * 4 rowSpacing = self.rowSpacing rowLength = self.rowLength offset = 0 offsetText = '' mainText = '' asciiText = '' for chars in range(1, len(text) + 1): byte = text[chars - 1] char = chr(text[chars - 1]) # Asciitext 는 오른쪽 출력부 if char is ' ': asciiText += '.' elif char is '\n': asciiText += '!' else: asciiText += char # main text 가 중앙에 있는것 mainText += format(byte, '0' + str(self.byteWidth) + 'x') if chars % rowLength is 0: offsetText += format(offset, '08x') + '\n' mainText += '\n' asciiText += '\n' elif chars % rowSpacing is 0: mainText += space * 2 else: mainText += space offset += len(char) self.offsetTextArea.setText(offsetText) self.mainTextArea.setText(mainText) self.asciiTextArea.setText(asciiText) # openFile ... Opens a file directory and returns the filename. # highlightMain ... Bi-directional highlighting from main. def highlightMain(self): # Create and get cursors for getting and setting selections. highlightCursor = QTextCursor(self.asciiTextArea.document()) # asciitextArea의 처음을 가르치는 커서를 구성 cursor = self.mainTextArea.textCursor() # 커서의 위치의 사본을 따서 복사 함 # Clear any current selections and reset text color. highlightCursor.select(QTextCursor.Document) highlightCursor.setCharFormat(QTextCharFormat()) highlightCursor.clearSelection() # Information about where selections and rows start. selectedText = cursor.selectedText() # The actual text selected. selectionStart = cursor.selectionStart() selectionEnd = cursor.selectionEnd() mainText = self.mainTextArea.toPlainText().replace('\n', 'A') #mainText = self.mainTextArea.toPlainText() totalBytes = 0 for char in mainText[selectionStart:selectionEnd]: if char is not ' ': totalBytes += len(char) asciiStart = 0 for char in mainText[:selectionStart]: if char is not ' ': asciiStart += len(char) totalBytes = round(totalBytes / self.byteWidth) asciiStart = round(asciiStart / self.byteWidth) asciiEnd = asciiStart + totalBytes asciiText = self.asciiTextArea.toPlainText() # Select text and highlight it. highlightCursor.setPosition(asciiStart, QTextCursor.MoveAnchor) highlightCursor.setPosition(asciiEnd, QTextCursor.KeepAnchor) highlight = QTextCharFormat() highlight.setBackground(Qt.darkCyan) highlightCursor.setCharFormat(highlight) highlightCursor.clearSelection() # highlightAscii ... Bi-directional highlighting from ascii. def highlightAscii(self): selectedText = self.asciiTextArea.textCursor().selectedText() # offsetJump ... Creates a dialogue and gets the offset to jump to and then jumps to that offset. def offsetJump(self): # input dialog 를 활용 하여 jump to ofsset 을 만듭니다. jumpText = InputDialogue('Jump to Offset', 'Offset').dialogueReponse jumpOffset = 0xF mainText = self.mainTextArea.toPlainText() mainText = mainText.strip().replace(' ', ' ') textCursor = self.mainTextArea.textCursor() # createMainView ... Creates the primary view and look of the application (3-text areas.) def createMainView(self): qhBox = QHBoxLayout() qhBox2 = QHBoxLayout() qvBox = QVBoxLayout() self.dirModel = QFileSystemModel() self.dirModel.setRootPath('') self.fileModel = QFileSystemModel() self.tree = QTreeView() self.list = QListView() self.tree.setModel(self.dirModel) self.list.setModel(self.fileModel) self.tree.clicked.connect(self.tree_on_clicked) self.list.clicked.connect(self.list_on_clicked) self.mainTextArea = QTextEdit() self.offsetTextArea = QTextEdit() self.asciiTextArea = QTextEdit() # Initialize them all to read only. self.mainTextArea.setReadOnly(True) self.asciiTextArea.setReadOnly(True) self.offsetTextArea.setReadOnly(True) # Create the fonts and styles to be used and then apply them. font = QFont("DejaVu Sans Mono", 11, QFont.Normal, True) self.mainTextArea.setFont(font) self.asciiTextArea.setFont(font) self.offsetTextArea.setFont(font) #self.offsetTextArea.setTextColor(Qt.red) # Syncing scrolls. syncScrolls(self.mainTextArea, self.asciiTextArea, self.offsetTextArea) # Highlight linking. BUG-GY self.mainTextArea.selectionChanged.connect(self.highlightMain) self.asciiTextArea.selectionChanged.connect(self.highlightAscii) qhBox.addWidget(self.offsetTextArea, 1) qhBox.addWidget(self.mainTextArea, 6) qhBox.addWidget(self.asciiTextArea, 2) qhBox2.addWidget(self.tree) qhBox2.addWidget(self.list) qvBox.addLayout(qhBox2) qvBox.addLayout(qhBox) return qvBox def tree_on_clicked(self, index): path = self.dirModel.fileInfo(index).absoluteFilePath() self.list.setRootIndex(self.fileModel.setRootPath(path)) def list_on_clicked(self, index): path = self.fileModel.fileInfo(index).absoluteFilePath() #self.openbyList(self,path) self.readFile(path) # initUI ... Initializes the min look of the application. def initUI(self): # Initialize basic window options. self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # Center the window. qtRectangle = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) # Creates a menu bar, (file, edit, options, etc...) mainMenu = self.menuBar() # Menus for window. fileMenu = mainMenu.addMenu('File') editMenu = mainMenu.addMenu('Edit') viewMenu = mainMenu.addMenu('View') helpMenu = mainMenu.addMenu('Help') # FILE MENU --------------------------------------- # Open button. openButton = QAction(QIcon(), 'Open', self) openButton.setShortcut('Ctrl+O') openButton.setStatusTip('Open file') openButton.triggered.connect(self.openFile) # Save button. saveButton = QAction(QIcon(), 'Save', self) saveButton.setShortcut('Ctrl+S') saveButton.setStatusTip('Open file') saveButton.triggered.connect(self.saveFile) # Optional exit stuff. exitButton = QAction(QIcon(), 'Exit', self) exitButton.setShortcut('Ctrl+Q') exitButton.setStatusTip('Exit application') exitButton.triggered.connect(self.close) fileMenu.addAction(openButton) fileMenu.addAction(saveButton) fileMenu.addAction(exitButton) # EDIT MENU --------------------------------------- # Jump to Offset offsetButton = QAction(QIcon(), 'Jump to Offset', self) offsetButton.setShortcut('Ctrl+J') offsetButton.setStatusTip('Jump to Offset') offsetButton.triggered.connect(self.offsetJump) editMenu.addAction(offsetButton) # Creating a widget for the central widget thingy. centralWidget = QWidget() centralWidget.setLayout(self.createMainView()) self.setCentralWidget(centralWidget) # Show our masterpiece. self.show()
def load_tree(self, project): """Load the tree view on the right based on the project selected.""" qfsm = QFileSystemModel() qfsm.setRootPath(project.path) load_index = qfsm.index(qfsm.rootPath()) qfsm.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) qfsm.setNameFilterDisables(False) pext = ["*{0}".format(x) for x in project.extensions] qfsm.setNameFilters(pext) self._tree.setModel(qfsm) self._tree.setRootIndex(load_index) t_header = self._tree.header() t_header.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) t_header.setSectionResizeMode(0, QHeaderView.Stretch) t_header.setStretchLastSection(False) t_header.setClickable(True) self._tree.hideColumn(1) # Size self._tree.hideColumn(2) # Type self._tree.hideColumn(3) # Modification date
def __init__(self, parent): QWidget.__init__(self) self.parent = parent self.name = 'File Manager' self.port = '9080' self.server = None drives = win32api.GetLogicalDriveStrings().split('\\\000')[:-1] self.logical_drives = drives + [d+'/' for d in drives] # create file manager tab self.file_manager_layout = QGridLayout(self) # create left manager (PC) self.left_up_btn = QPushButton() self.left_up_btn.setIcon(QIcon('images/up_btn.png')) self.left_up_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_up_btn, 0, 0, 1, 1) self.left_dir_path = QLineEdit(self.parent.expanduser_dir) self.file_manager_layout.addWidget(self.left_dir_path, 0, 1, 1, 8) self.left_go_to_btn = QPushButton() self.left_go_to_btn.setIcon(QIcon('images/right_btn.png')) self.left_go_to_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_go_to_btn, 0, 9, 1, 1) self.lefttableview = QTableView() self.lefttableview.setSelectionBehavior(QTableView.SelectRows) self.lefttableview.verticalHeader().hide() self.lefttableview.setShowGrid(False) self.lefttableview.contextMenuEvent = lambda event: self.left_context(event) self.left_file_model = QFileSystemModel() self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.left_file_model.setRootPath(self.parent.expanduser_dir) self.left_file_model_path = self.parent.expanduser_dir self.lefttableview.setModel(self.left_file_model) self.lefttableview.setColumnWidth(0, 150) self.lefttableview.setRootIndex(self.left_file_model.index(self.parent.expanduser_dir)) self.file_manager_layout.addWidget(self.lefttableview, 1, 0, 5, 10) # central buttons self.download_file_from_device_btn = QPushButton() self.download_file_from_device_btn.setIcon(QIcon('images/left_btn.png')) self.download_file_from_device_btn.setFixedWidth(30) self.download_file_from_device_btn.setEnabled(False) self.upload_file_to_device_btn = QPushButton() self.upload_file_to_device_btn.setIcon(QIcon('images/right_btn.png')) self.upload_file_to_device_btn.setFixedWidth(30) self.upload_file_to_device_btn.setEnabled(False) self.delete_file_btn = QPushButton() self.delete_file_btn.setIcon(QIcon('images/delete_btn.png')) self.delete_file_btn.setFixedWidth(30) self.file_manager_layout.addWidget(self.download_file_from_device_btn, 3, 10, 1, 1) self.file_manager_layout.addWidget(self.delete_file_btn, 4, 10, 1, 1) # create right manager (Device) self.right_up_btn = QPushButton() self.right_up_btn.setIcon(QIcon('images/up_btn.png')) self.right_up_btn.setFixedWidth(25) self.right_up_btn.setEnabled(False) self.file_manager_layout.addWidget(self.right_up_btn, 0, 11, 1, 1) self.add_folder_btn = QPushButton() self.add_folder_btn.setIcon(QIcon('images/folder_add.png')) self.add_folder_btn.setFixedWidth(25) self.add_folder_btn.setToolTip(_('Add new folder')) self.add_folder_btn.setEnabled(False) self.file_manager_layout.addWidget(self.add_folder_btn, 0, 12, 1, 1) self.right_dir_path = QLineEdit() self.file_manager_layout.addWidget(self.right_dir_path, 0, 13, 1, 7) self.right_update_btn = QPushButton() self.right_update_btn.setIcon(QIcon('images/update.png')) self.right_update_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.right_update_btn, 0, 20, 1, 1) self.righttableview = QTableView() self.righttableview.setSelectionBehavior(QTableView.SelectRows) self.righttableview.contextMenuEvent = lambda event: self.right_context(event) self.righttableview.verticalHeader().hide() self.righttableview.setShowGrid(False) self.right_file_model = QStandardItemModel() self.right_file_model_path = [] self.right_active_dir = None self.righttableview.setModel(self.right_file_model) self.file_manager_layout.addWidget(self.righttableview, 1, 11, 5, 10) # auto sync self.timer = QTimer() self.timer.setInterval(10000) self.file_models_auto_sync = QCheckBox(_('Auto sync')) self.left_file_model_auto_sync_label = QLineEdit() self.left_file_model_auto_sync_label.setReadOnly(True) self.right_file_model_auto_sync_label = QLineEdit() self.right_file_model_auto_sync_label.setReadOnly(True) self.file_manager_layout.addWidget(self.file_models_auto_sync, 6, 9, 1, 3, alignment=Qt.AlignCenter) self.file_manager_layout.addWidget(self.left_file_model_auto_sync_label, 6, 0, 1, 9) self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) self.timer.timeout.connect(lambda: self.check_device_sync()) self.lefttableview.clicked.connect(lambda idx: self.left_file_model_clicked(idx)) self.lefttableview.doubleClicked.connect(lambda idx: self.left_file_model_doubleclicked(idx)) self.left_up_btn.clicked.connect(lambda: self.left_file_model_up(self.left_file_model.index(self.left_dir_path.text()))) self.left_go_to_btn.clicked.connect(lambda: self.left_file_model_go_to_dir()) self.right_update_btn.clicked.connect(lambda: self.right_file_model_update()) self.righttableview.doubleClicked.connect(lambda idx: self.right_file_model_doubleclicked(idx)) self.right_up_btn.clicked.connect(lambda: self.right_file_model_up()) self.add_folder_btn.clicked.connect(lambda: self.right_file_model_add_folder()) self.righttableview.clicked.connect(lambda idx: self.right_file_model_clicked(idx)) self.download_file_from_device_btn.clicked.connect(lambda: self.download_file_from_device()) self.upload_file_to_device_btn.clicked.connect(lambda: self.upload_file_to_device()) self.delete_file_btn.clicked.connect(lambda: self.delete_file_from_file_model()) self.parent.settings_widget.signal_ip_changed.connect(lambda ip: self.change_ip(ip)) self.parent.signal_language_changed.connect(lambda: self.retranslate())
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'PyQt5 file system view - pythonspot.com' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.default_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files/examples')) self.user_path = (os.path.join('/media')) self.currentPath = None self.initUI() 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()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.setNameFilters(["*.ngc", '*.py']) self.list = QListView() self.list.setModel(self.model) self.updateDirectoryView(self.default_path) self.list.setWindowTitle("Dir View") self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.clicked) self.list.activated.connect(self.load) self.list.setAlternatingRowColors(True) self.cb = QComboBox() self.cb.currentTextChanged.connect(self.filterChanged) self.cb.addItems(sorted({'*.ngc', '*.py', '*'})) #self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button = QPushButton() self.button.setText('Media') self.button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button.setToolTip('Jump to Media directory') self.button.clicked.connect(self.onMediaClicked) self.button2 = QPushButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setToolTip('Jump to linuxcnc directory') self.button2.clicked.connect(self.onUserClicked) hbox = QHBoxLayout() hbox.addWidget(self.button) hbox.addWidget(self.button2) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addWidget(self.list) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def updateDirectoryView(self, path): self.list.setRootIndex(self.model.setRootPath(path)) def filterChanged(self, text): self.model.setNameFilters([text]) def clicked(self, index): # the signal passes the index of the clicked item dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) def onMediaClicked(self): self.updateDirectoryView(self.user_path) def onUserClicked(self): self.updateDirectoryView(self.default_path) def select_row(self, style): style = style.lower() selectionModel = self.list.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(self.list.rootIndex()) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows: row += 1 else: row = self.rows else: return top = self.model.index(row, 0, self.list.rootIndex()) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.default_path, str, 'BOOK_KEEPING') self.updateDirectoryView(last_path) LOG.debug("lAST FILE PATH: {}".format(last_path)) else: LOG.debug("lAST FILE PATH: {}".format(self.default_path)) self.updateDirectoryView(self.default_path) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def load(self): row = self.list.selectionModel().currentIndex() self.clicked(row) fname = self.currentPath if fname is None: return if fname: if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING') ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') def up(self): self.select_row('up') def down(self): self.select_row('down')
class FileChooser(QWidget): fileOpened = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) # TODO: migrate to FolderComboBox? self.folderBox = QComboBox(self) self.explorerTree = FileTreeView(self) self.explorerTree.doubleClickCallback = self._fileOpened self.explorerModel = QFileSystemModel(self) self.explorerModel.setFilter( QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) self.explorerModel.setNameFilters(["*.py"]) self.explorerModel.setNameFilterDisables(False) self.explorerTree.setModel(self.explorerModel) for index in range(1, self.explorerModel.columnCount()): self.explorerTree.hideColumn(index) self.setCurrentFolder() self.folderBox.currentIndexChanged[int].connect( self.updateCurrentFolder) layout = QVBoxLayout(self) layout.addWidget(self.folderBox) layout.addWidget(self.explorerTree) layout.setContentsMargins(5, 5, 0, 0) def _fileOpened(self, modelIndex): path = self.explorerModel.filePath(modelIndex) if os.path.isfile(path): self.fileOpened.emit(path) def currentFolder(self): return self.explorerModel.rootPath() def setCurrentFolder(self, path=None): if path is None: app = QApplication.instance() path = app.getScriptsDirectory() else: assert os.path.isdir(path) self.explorerModel.setRootPath(path) self.explorerTree.setRootIndex(self.explorerModel.index(path)) self.folderBox.blockSignals(True) self.folderBox.clear() style = self.style() dirIcon = style.standardIcon(style.SP_DirIcon) self.folderBox.addItem(dirIcon, os.path.basename(path)) self.folderBox.insertSeparator(1) self.folderBox.addItem(self.tr("Browse…")) self.folderBox.setCurrentIndex(0) self.folderBox.blockSignals(False) def updateCurrentFolder(self, index): if index < self.folderBox.count() - 1: return path = QFileDialog.getExistingDirectory( self, self.tr("Choose Directory"), self.currentFolder(), QFileDialog.ShowDirsOnly) if path: QSettings().setValue("scripting/path", path) self.setCurrentFolder(path)
class AssetBrowser(QMainWindow, Ui_MainWindow): asset_clicked = pyqtSignal(str, str, name='assetClicked') def __init__(self): super(AssetBrowser, self).__init__() self.setupUi(self) self.dir_model = QFileSystemModel() self.dir_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dir_model.setReadOnly(False) self.dir_view.setModel(self.dir_model) self.dir_view.hideColumn(1) self.dir_view.hideColumn(2) self.dir_view.hideColumn(3) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.file_model.setReadOnly(False) self.file_view.setModel(self.file_model) def open_project(self, project_dir): path = os.path.join(project_dir) self.dir_model.setRootPath(path) self.file_model.setRootPath(path) self.dir_view.setRootIndex(self.dir_model.index(path)) self.file_view.setRootIndex(self.file_model.index(path)) def dir_clicked(self, idx): path = self.dir_model.fileInfo(idx).absoluteFilePath() self.file_view.setRootIndex(self.file_model.setRootPath(path)) def file_doubleclicked(self, idx): fileinfo = self.file_model.fileInfo(idx) path = fileinfo.absoluteFilePath() ext = fileinfo.suffix() self.asset_clicked.emit(path, ext)
class FileManager(QWidget): def __init__(self, parent): QWidget.__init__(self) self.parent = parent self.name = 'File Manager' self.port = '9080' self.server = None drives = win32api.GetLogicalDriveStrings().split('\\\000')[:-1] self.logical_drives = drives + [d+'/' for d in drives] # create file manager tab self.file_manager_layout = QGridLayout(self) # create left manager (PC) self.left_up_btn = QPushButton() self.left_up_btn.setIcon(QIcon('images/up_btn.png')) self.left_up_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_up_btn, 0, 0, 1, 1) self.left_dir_path = QLineEdit(self.parent.expanduser_dir) self.file_manager_layout.addWidget(self.left_dir_path, 0, 1, 1, 8) self.left_go_to_btn = QPushButton() self.left_go_to_btn.setIcon(QIcon('images/right_btn.png')) self.left_go_to_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.left_go_to_btn, 0, 9, 1, 1) self.lefttableview = QTableView() self.lefttableview.setSelectionBehavior(QTableView.SelectRows) self.lefttableview.verticalHeader().hide() self.lefttableview.setShowGrid(False) self.lefttableview.contextMenuEvent = lambda event: self.left_context(event) self.left_file_model = QFileSystemModel() self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.left_file_model.setRootPath(self.parent.expanduser_dir) self.left_file_model_path = self.parent.expanduser_dir self.lefttableview.setModel(self.left_file_model) self.lefttableview.setColumnWidth(0, 150) self.lefttableview.setRootIndex(self.left_file_model.index(self.parent.expanduser_dir)) self.file_manager_layout.addWidget(self.lefttableview, 1, 0, 5, 10) # central buttons self.download_file_from_device_btn = QPushButton() self.download_file_from_device_btn.setIcon(QIcon('images/left_btn.png')) self.download_file_from_device_btn.setFixedWidth(30) self.download_file_from_device_btn.setEnabled(False) self.upload_file_to_device_btn = QPushButton() self.upload_file_to_device_btn.setIcon(QIcon('images/right_btn.png')) self.upload_file_to_device_btn.setFixedWidth(30) self.upload_file_to_device_btn.setEnabled(False) self.delete_file_btn = QPushButton() self.delete_file_btn.setIcon(QIcon('images/delete_btn.png')) self.delete_file_btn.setFixedWidth(30) self.file_manager_layout.addWidget(self.download_file_from_device_btn, 3, 10, 1, 1) self.file_manager_layout.addWidget(self.delete_file_btn, 4, 10, 1, 1) # create right manager (Device) self.right_up_btn = QPushButton() self.right_up_btn.setIcon(QIcon('images/up_btn.png')) self.right_up_btn.setFixedWidth(25) self.right_up_btn.setEnabled(False) self.file_manager_layout.addWidget(self.right_up_btn, 0, 11, 1, 1) self.add_folder_btn = QPushButton() self.add_folder_btn.setIcon(QIcon('images/folder_add.png')) self.add_folder_btn.setFixedWidth(25) self.add_folder_btn.setToolTip(_('Add new folder')) self.add_folder_btn.setEnabled(False) self.file_manager_layout.addWidget(self.add_folder_btn, 0, 12, 1, 1) self.right_dir_path = QLineEdit() self.file_manager_layout.addWidget(self.right_dir_path, 0, 13, 1, 7) self.right_update_btn = QPushButton() self.right_update_btn.setIcon(QIcon('images/update.png')) self.right_update_btn.setFixedWidth(25) self.file_manager_layout.addWidget(self.right_update_btn, 0, 20, 1, 1) self.righttableview = QTableView() self.righttableview.setSelectionBehavior(QTableView.SelectRows) self.righttableview.contextMenuEvent = lambda event: self.right_context(event) self.righttableview.verticalHeader().hide() self.righttableview.setShowGrid(False) self.right_file_model = QStandardItemModel() self.right_file_model_path = [] self.right_active_dir = None self.righttableview.setModel(self.right_file_model) self.file_manager_layout.addWidget(self.righttableview, 1, 11, 5, 10) # auto sync self.timer = QTimer() self.timer.setInterval(10000) self.file_models_auto_sync = QCheckBox(_('Auto sync')) self.left_file_model_auto_sync_label = QLineEdit() self.left_file_model_auto_sync_label.setReadOnly(True) self.right_file_model_auto_sync_label = QLineEdit() self.right_file_model_auto_sync_label.setReadOnly(True) self.file_manager_layout.addWidget(self.file_models_auto_sync, 6, 9, 1, 3, alignment=Qt.AlignCenter) self.file_manager_layout.addWidget(self.left_file_model_auto_sync_label, 6, 0, 1, 9) self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) self.timer.timeout.connect(lambda: self.check_device_sync()) self.lefttableview.clicked.connect(lambda idx: self.left_file_model_clicked(idx)) self.lefttableview.doubleClicked.connect(lambda idx: self.left_file_model_doubleclicked(idx)) self.left_up_btn.clicked.connect(lambda: self.left_file_model_up(self.left_file_model.index(self.left_dir_path.text()))) self.left_go_to_btn.clicked.connect(lambda: self.left_file_model_go_to_dir()) self.right_update_btn.clicked.connect(lambda: self.right_file_model_update()) self.righttableview.doubleClicked.connect(lambda idx: self.right_file_model_doubleclicked(idx)) self.right_up_btn.clicked.connect(lambda: self.right_file_model_up()) self.add_folder_btn.clicked.connect(lambda: self.right_file_model_add_folder()) self.righttableview.clicked.connect(lambda idx: self.right_file_model_clicked(idx)) self.download_file_from_device_btn.clicked.connect(lambda: self.download_file_from_device()) self.upload_file_to_device_btn.clicked.connect(lambda: self.upload_file_to_device()) self.delete_file_btn.clicked.connect(lambda: self.delete_file_from_file_model()) self.parent.settings_widget.signal_ip_changed.connect(lambda ip: self.change_ip(ip)) self.parent.signal_language_changed.connect(lambda: self.retranslate()) def retranslate(self): self.file_models_auto_sync.setText(_('Auto sync')) self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')]) def change_ip(self, ip): self.server = ':'.join([ip, self.port]) self.right_file_model_path = [] self.right_file_model.clear() def left_file_model_clicked(self, idx): if os.path.isfile(self.left_file_model.filePath(idx)) and self.parent.geoshark_widget.device_on_connect: self.upload_file_to_device_btn.setEnabled(True) else: self.upload_file_to_device_btn.setEnabled(False) def left_file_model_doubleclicked(self, idx): self.left_up_btn.setEnabled(True) fileinfo = self.left_file_model.fileInfo(idx) if fileinfo.isDir(): self.lefttableview.setRootIndex(idx) self.left_dir_path.setText(self.left_file_model.filePath(idx)) self.left_file_model_path = self.left_file_model.filePath(idx) def left_file_model_up(self, idx): self.upload_file_to_device_btn.setEnabled(False) if self.left_dir_path.text() in self.logical_drives: self.left_file_model = QFileSystemModel() self.left_file_model.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.left_file_model.setRootPath('') self.lefttableview.setModel(self.left_file_model) self.left_dir_path.setText('My computer') self.left_up_btn.setEnabled(False) else: fileinfo = self.left_file_model.fileInfo(idx) dir = fileinfo.dir() self.left_dir_path.setText(dir.path()) self.left_file_model_path = dir.path() self.lefttableview.setRootIndex(self.left_file_model.index(dir.absolutePath())) def left_file_model_go_to_dir(self): if os.path.isdir(self.left_dir_path.text()): self.left_file_model_path = self.left_dir_path.text() self.left_up_btn.setEnabled(True) self.upload_file_to_device_btn.setEnabled(False) self.left_file_model.setRootPath(self.left_dir_path.text()) self.lefttableview.setRootIndex(self.left_file_model.index(self.left_dir_path.text())) def right_file_model_update(self): if not self.parent.geoshark_widget.device_on_connect: return url = 'http://{}/active_dir'.format(self.server) try: res = requests.get(url, timeout=5) if res.ok: self.right_active_dir = res.text except requests.exceptions.RequestException: pass file_list = self.get_folder_list() if file_list is None: return self.fill_right_file_model(file_list) self.download_file_from_device_btn.setEnabled(False) def get_folder_list(self, folder_path=None): if self.server is None: return if folder_path is None: folder_path = '/'.join(self.right_file_model_path) url = 'http://{}/data/{}'.format(self.server, folder_path) try: res = requests.get(url, timeout=1) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: res = res.json() return res else: return None def check_device_sync(self): pc_path = self.left_file_model_auto_sync_label.text() device_path = self.right_file_model_auto_sync_label.text() if self.file_models_auto_sync.isChecked() and pc_path != '' and device_path != '': file_list = self.get_folder_list(self.right_file_model_auto_sync_label.text()) left_list_of_files = os.listdir(self.left_file_model_auto_sync_label.text()) for f in file_list: if f['name'] not in left_list_of_files or os.path.getsize('{}/{}'.format(pc_path, f['name'])) != f['size']: self.download_file_from_device(device_path='{}/{}'.format(device_path, f['name']), pc_path=pc_path) def fill_right_file_model(self, directory): self.add_folder_btn.setEnabled(True) if len(self.right_file_model_path) < 1: self.right_up_btn.setEnabled(False) else: self.right_up_btn.setEnabled(True) self.add_folder_btn.setEnabled(False) self.right_file_model.removeRows(0, self.right_file_model.rowCount()) self.right_dir_path.setText('/'.join(self.right_file_model_path)) self.right_file_model.setHorizontalHeaderLabels([_('Name'), _('Size'), _('Changed date')]) for row, instance in enumerate(directory): if instance['name'] == self.right_active_dir: image = QIcon('images/directory_active.png') else: image = QIcon('images/{}.png'.format(instance['type'])) item = QStandardItem(image, instance['name']) item.setData(instance['type'], 5) item.setEditable(False) self.right_file_model.setItem(row, 0, item) item = QStandardItem(str(instance['size'])) item.setEditable(False) self.right_file_model.setItem(row, 1, item) item = QStandardItem(str(datetime.datetime.fromtimestamp(instance['changed']).strftime('%d.%m.%Y %H:%M'))) item.setEditable(False) self.right_file_model.setItem(row, 2, item) self.righttableview.setColumnWidth(0, max(150, self.righttableview.columnWidth(0))) def left_context(self, event): context_menu = {} index = self.lefttableview.indexAt(event.pos()) if index.row() == -1: return context_menu[_('Set active directory')] = lambda: self.set_pc_active_directory(self.left_file_model.filePath(index)) context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index) if not self.left_file_model.isDir(index): del context_menu[_('Set active directory')] menu = QMenu() actions = [QAction(a) for a in context_menu.keys()] menu.addActions(actions) action = menu.exec_(event.globalPos()) if action: context_menu[action.text()]() def set_pc_active_directory(self, path): self.left_file_model_auto_sync_label.setText(path) self.parent.settings_widget.left_folder_tracked.setText(path) def right_context(self, event): context_menu = {} index = self.righttableview.indexAt(event.pos()) if index.row() == -1: return item = self.right_file_model.itemFromIndex(index) item_row = item.row() context_menu[_('Set active directory')] = lambda: self.set_active_directory(item) context_menu[_('Remove element')] = lambda: self.delete_file_from_file_model(index) if self.right_file_model.item(item_row, 0).data(5) != 'directory': del context_menu[_('Set active directory')] menu = QMenu() actions = [QAction(a) for a in context_menu.keys()] menu.addActions(actions) action = menu.exec_(event.globalPos()) if action: context_menu[action.text()]() def set_active_directory(self, item): if not self.parent.geoshark_widget.device_on_connect: return dirname = item.text() url = 'http://{}/active_dir'.format(self.server) try: res = requests.post(url=url, data=dirname, timeout=5) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('Can not set active directory.\nGeoShark is not responding.')) return if res.ok: self.right_file_model_update() self.set_active_path(dirname) elif res.status_code == 400: show_error(_('GeoShark error'), _('Request declined - request body specifies invalid path.')) return elif res.status_code == 409: show_error(_('GeoShark error'), _('Request declined - switching active directory is forbidden during active session.')) return else: print(res.status_code) return def set_active_path(self, dirname): path = '/'.join(self.right_file_model_path + [dirname]) self.parent.settings_widget.right_folder_tracked.setText(path) self.right_file_model_auto_sync_label.setText(path) def right_file_model_clicked(self, idx): if not self.parent.geoshark_widget.device_on_connect: return if self.right_file_model.item(idx.row(), 0).data(5) == 'file': self.download_file_from_device_btn.setEnabled(True) else: self.download_file_from_device_btn.setEnabled(False) def right_file_model_doubleclicked(self, idx): if not self.parent.geoshark_widget.device_on_connect: return model_path = '/'.join(self.right_file_model_path) idx_name = self.right_file_model.item(idx.row(), 0).text() if model_path != '': dir = '{}/{}'.format(model_path, idx_name) else: dir = '{}'.format(idx_name) file_list = self.get_folder_list(dir) if file_list is None: return self.right_file_model_path = dir.split('/') self.fill_right_file_model(file_list) def right_file_model_up(self): if not self.parent.geoshark_widget.device_on_connect: return self.download_file_from_device_btn.setEnabled(False) up_dir = '/'.join(self.right_file_model_path[:-1]) file_list = self.get_folder_list(up_dir) if file_list is None: return if up_dir == '': self.right_file_model_path = [] else: self.right_file_model_path = up_dir.split('/') self.fill_right_file_model(file_list) def right_file_model_add_folder(self): if not self.parent.geoshark_widget.device_on_connect: return row = self.right_file_model.rowCount() item = QStandardItem(QIcon('images/folder.png'), 'New Directory') item.setData('directory', 5) item.setEditable(True) self.right_file_model.setItem(row, 0, item) item = QStandardItem(str(0.0)) item.setEditable(False) self.right_file_model.setItem(row, 1, item) item = QStandardItem(str(datetime.datetime.today().strftime('%d.%m.%Y %H:%M'))) item.setEditable(False) self.right_file_model.setItem(row, 2, item) def download_file_from_device(self, device_path=None, pc_path=None): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return if not device_path: fileName = self.find_selected_idx() if fileName: fileName = fileName.data() device_path = '/'.join(self.right_file_model_path + [fileName]) else: return right_file_model_filename = device_path.split('/')[-1] save_to_file = '{}/{}'.format(self.left_file_model_path, right_file_model_filename) \ if not pc_path else '{}/{}'.format(pc_path, right_file_model_filename) if os.path.isfile(save_to_file): answer = show_warning_yes_no(_('File warning'), _('There is a file with the same name in PC.\n' 'Do you want to rewrite <b>{}</b>?'.format(right_file_model_filename))) if answer == QMessageBox.No: return url = 'http://{}/data/{}'.format(self.server, device_path) try: b = bytearray() res = requests.get(url, timeout=5, stream=True) if res.ok: progress = QProgressBar() progress.setFormat(right_file_model_filename) self.file_manager_layout.addWidget(progress, 6, 12, 1, 9) total_length = int(res.headers.get('content-length')) len_b = 0 for chunk in tee_to_bytearray(res, b): len_b += len(chunk) progress.setValue((len_b/total_length)*99) QApplication.processEvents() else: return except: self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: progress.setValue(100) with open(save_to_file, 'wb') as file: file.write(b) for i in reversed(range(self.file_manager_layout.count())): if isinstance(self.file_manager_layout.itemAt(i).widget(), QProgressBar): self.file_manager_layout.itemAt(i).widget().setParent(None) self.file_manager_layout.addWidget(self.right_file_model_auto_sync_label, 6, 12, 1, 9) def upload_file_to_device(self): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return file = self.left_file_model.filePath(self.lefttableview.currentIndex()) filename = file.split('/')[-1] url = 'http://{}/data/{}'.format(self.server, '/'.join(self.right_file_model_path)) filesize = os.path.getsize(file) if filesize == 0: show_error(_('File error'), _('File size must be non zero.')) return progress = ProgressBar(text=_('Upload File Into GeoShark'), window_title=_('Upload file to GeoShark')) encoder = MultipartEncoder( fields={'upload_file': (filename, open(file, 'rb'))} # added mime-type here ) data = MultipartEncoderMonitor(encoder, lambda monitor: progress.update((monitor.bytes_read/filesize)*99)) try: res = requests.post(url, data=data, headers={'Content-Type': encoder.content_type}, timeout=5) except requests.exceptions.RequestException: progress.close() show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: progress.update(100) self.right_file_model_update() def delete_file_from_file_model(self, index=None): selected = self.find_selected_idx() if index is None and selected is None: return if index is None: index = selected model = index.model() index_row = index.row() path = model.filePath(index) if hasattr(model, 'filePath') else model.index(index_row, 0).data() answer = show_warning_yes_no(_('Remove File warning'), _('Do you really want to remove:\n{}').format(path)) if answer == QMessageBox.No: return if isinstance(model, QFileSystemModel): model.remove(index) elif isinstance(model, QStandardItemModel): if not self.parent.geoshark_widget.device_on_connect or self.server is None: return filename = self.right_file_model.item(index.row(), 0).text() path = '/'.join(self.right_file_model_path + [filename]) url = 'http://{}/data/{}'.format(self.server, path) try: res = requests.delete(url) except requests.exceptions.RequestException: show_error(_('GeoShark error'), _('GeoShark is not responding.')) return if res.ok: self.right_file_model_update() elif res.status_code == 400: self.right_file_model.removeRow(index.row()) elif res.status_code == 409: show_error(_('GeoShark error'), _('Request declined - directory is the part of active session working directory.')) return def find_selected_idx(self): left_indexes = self.lefttableview.selectedIndexes() right_indexes = self.righttableview.selectedIndexes() if len(left_indexes) == 0 and len(right_indexes) == 0: return None index = left_indexes[0] if len(left_indexes) > len(right_indexes) else right_indexes[0] return index def save_file_models_folder(self): self.left_file_model_auto_sync_label.setText(self.parent.settings_widget.left_folder_tracked.text()) self.right_file_model_auto_sync_label.setText(self.parent.settings_widget.right_folder_tracked.text())
def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) MainWindow.setLayoutDirection(QtCore.Qt.LeftToRight) self.MRATcentralwidget = QtWidgets.QWidget(MainWindow) self.MRATcentralwidget.setObjectName("MRATcentralwidget") self.widget = QtWidgets.QWidget(self.MRATcentralwidget) self.widget.setGeometry(QtCore.QRect(10, 0, 201, 480)) #test = PThresholdTempSourceTTest.Results #if PThresholdTempSourceTTest.Results != "": data = {'col1':['0','0','0'], 'col2':['0','0','0'], 'col3':['7','8','9']} self.table = MyTable(data, 5, 3) #self.table.show() #self.table.show() #tree.resize(340, 480) #tree.show() MainWindow.setCentralWidget(self.MRATcentralwidget) self.dockWidget = QtWidgets.QDockWidget(MainWindow) self.dockWidget.setObjectName("dockWidget") self.dockWidget= QDockWidget("MRAT work space", self) self.dockWidgetContents = QtWidgets.QWidget() self.dockWidgetContents.setObjectName("dockWidgetContents") self.dockWidget.setWidget(self.dockWidgetContents) MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget) self.dockWidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.table = QTableWidget() #self.widget.setObjectName("widget") self.treeView = QtWidgets.QTreeView(self.dockWidget) self.treeView.setGeometry(QtCore.QRect(10, 20, 191, 480)) self.treeView.sizeAdjustPolicy = "AdjustToContents" self.treeView.setObjectName("treeView") self.model = QFileSystemModel() self.rootPath = '' self.model.setRootPath(self.rootPath) self.treeView.setModel(self.model) self.treeView.setAnimated(True) self.treeView.setIndentation(5) self.treeView.setSortingEnabled(True) self.treeView.setWindowTitle("MRAT workspace") self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setMinimumSize(QtCore.QSize(10, 10)) self.menubar.setDefaultUp(False) self.menubar.setNativeMenuBar(False) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") self.menuEdit = QtWidgets.QMenu(self.menubar) self.menuEdit.setObjectName("menuEdit") self.menuData = QtWidgets.QMenu(self.menubar) self.menuData.setObjectName("menuData") self.menuGraphics = QtWidgets.QMenu(self.menubar) self.menuGraphics.setObjectName("menuGraphics") self.menuStatistics = QtWidgets.QMenu(self.menubar) self.menuStatistics.setObjectName("menuStatistics") self.menuT_TESTS = QtWidgets.QMenu(self.menuStatistics) self.menuT_TESTS.setObjectName("menuT_TESTS") self.menuTemporal = QtWidgets.QMenu(self.menuT_TESTS) self.menuTemporal.setObjectName("menuTemporal") self.menuResults = QtWidgets.QMenu(self.menubar) self.menuResults.setObjectName("menuResults") self.menuHelp = QtWidgets.QMenu(self.menubar) self.menuHelp.setObjectName("menuHelp") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.toolBar = QtWidgets.QToolBar(MainWindow) self.toolBar.setObjectName("toolBar") MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.actionSpatio_Temporal = QtWidgets.QAction(MainWindow) self.actionSpatio_Temporal.setObjectName("actionSpatio_Temporal") self.actionSpatio_Temporal_2 = QtWidgets.QAction(MainWindow) self.actionSpatio_Temporal_2.setObjectName("actionSpatio_Temporal_2") self.actionNew_Analysis = QtWidgets.QAction(MainWindow) self.actionNew_Analysis.setObjectName("actionNew_Analysis") self.actionOpen_Analysis = QtWidgets.QAction(MainWindow) self.actionOpen_Analysis.setObjectName("actionOpen_Analysis") self.actionPTHreshold = QtWidgets.QAction(MainWindow) self.actionPTHreshold.setObjectName("actionPTHreshold") self.actionTFCE = QtWidgets.QAction(MainWindow) self.actionTFCE.setObjectName("actionTFCE") self.actionWindow = QtWidgets.QAction(MainWindow) self.actionWindow.setObjectName("actionWindow") self.actionImport_File = QtWidgets.QAction(MainWindow) self.actionImport_File.setObjectName("actionImport_File") self.actionExport_File = QtWidgets.QAction(MainWindow) self.actionExport_File.setObjectName("actionExport_File") self.actionQuit = QtWidgets.QAction(MainWindow) self.actionQuit.setObjectName("actionQuit") self.menuFile.addAction(self.actionNew_Analysis) self.menuFile.addAction(self.actionOpen_Analysis) self.menuFile.addAction(self.actionImport_File) self.menuFile.addAction(self.actionExport_File) self.menuFile.addAction(self.actionQuit) self.menuTemporal.addSeparator() self.menuTemporal.addAction(self.actionPTHreshold) self.menuTemporal.addAction(self.actionTFCE) self.menuTemporal.addAction(self.actionWindow) self.menuT_TESTS.addSeparator() self.menuT_TESTS.addAction(self.menuTemporal.menuAction()) self.menuT_TESTS.addAction(self.actionSpatio_Temporal_2) self.menuStatistics.addAction(self.actionSpatio_Temporal) self.menuStatistics.addAction(self.menuT_TESTS.menuAction()) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuEdit.menuAction()) self.menubar.addAction(self.menuData.menuAction()) self.menubar.addAction(self.menuGraphics.menuAction()) self.menubar.addAction(self.menuStatistics.menuAction()) self.menubar.addAction(self.menuResults.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.retranslateUi(MainWindow) self.actionQuit.triggered.connect(MainWindow.close) self.form1 = ttestwindow() #self.Filedial = QtWidgets.QFileDialog.getExistingDirectory(self, "Find Files", # QtCore.QDir.currentPath()) self.actionPTHreshold.triggered.connect(self.form1.show) QtCore.QMetaObject.connectSlotsByName(MainWindow)
class ProjectWidget(QWidget): """ A widget for displaying & editing properties of objects etc. Also see the properties this likes to display: also see: supertux/property.py """ def __init__(self, parent): super().__init__(parent) self.items = [] self.addon = None self.vbox = QVBoxLayout() self.vbox.setSpacing(0) self.vbox.setContentsMargins(0, 0, 0, 0) self.heading_label = QLabel("No project") self.label = QLabel( "Create a project by selecting File > New > Project...") self.vbox.addWidget(self.heading_label) self.vbox.addWidget(self.label) self.setLayout(self.vbox) def init_gui(self): # Clear from previous: self.heading_label.setVisible(False) self.label.setVisible(False) self.toolbar = QToolBar() self.toolbar.setStyleSheet('QToolBar{spacing:0px;}') package_icon = QIcon("data/images/icons16/addon_package-16.png") add_icon = QIcon("data/images/supertux/plus.png") self.toolbar.addAction(package_icon, 'Package add-on...', self.package_addon) self.toolbar.addAction(add_icon, "Add content...", self.add_content) self.tree_view = QTreeView() self.vbox.addWidget(self.toolbar) self.model = QFileSystemModel() # self.data = [ # ("SuperTux addon", [ # ("levels", []), # ("images", []), # ("sounds", []), # ("music", []), # ("scripts", []), # ("metadata", []) # ])] # self.model = QStandardItemModel() # self.add_items(self.model, self.data) self.tree_view.setModel(self.model) self.tree_view.doubleClicked.connect(self.on_tree_view_double_click) self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view.customContextMenuRequested.connect(self.on_context_menu) self.vbox.addWidget(self.tree_view) self.layout = QFormLayout() self.vbox.addLayout(self.layout) self.setLayout(self.vbox) self.setMinimumWidth(300) # Called in many cases. This should have functions connected # which cause the changes in the widget to be applied # Called by hitting "Apply", "Ok" or "Finish" self.call_signal = Signal() self.call_signal.connect(self.call_callbacks) def call_callbacks(self, *args): for item in self.items: if item.callback is not None: item.callback(item.get_value()) def add_callback(self, callback): """Adds a callback to the callback signal""" self.call_signal.connect(callback) def add_items(self, parent, elements): for text, children in elements: item = QStandardItem(text) parent.appendRow(item) if children: self.add_items(item, children) def call(self): self.call_signal(*self.get_values()) def on_tree_view_double_click(self, item): print("double-clicked!") def on_context_menu(self, position): menu = QMenu() menu.addAction(self.tr("Add image...")) menu.addAction(self.tr("Add sound...")) menu.addAction(self.tr("Add level...")) menu.addAction(self.tr("Add script...")) menu.exec_(self.tree_view.viewport().mapToGlobal(position)) def set_project_directory(self, project_dir): self.tree_view.setRootIndex(self.model.setRootPath(project_dir)) def set_addon(self, addon): self.addon = addon # We now have an add-on set, initialize the GUI self.init_gui() def package_addon(self): print("Package add-on!") def add_content(self): print("Add content to add-on!")
class SearchFileWidget(QWidget): language_filter_change = pyqtSignal(list) def __init__(self): QWidget.__init__(self) self._refreshing = False self.fileModel = None self.proxyFileModel = None self.videoModel = None self._state = None self.timeLastSearch = QTime.currentTime() self.ui = Ui_SearchFileWidget() self.setup_ui() def set_state(self, state): self._state = state self._state.login_status_changed.connect(self.on_login_state_changed) self._state.interface_language_changed.connect( self.on_interface_language_changed) def get_state(self): return self._state def setup_ui(self): self.ui.setupUi(self) settings = QSettings() self.ui.splitter.setSizes([600, 1000]) self.ui.splitter.setChildrenCollapsible(False) # Set up folder view lastDir = settings.value("mainwindow/workingDirectory", QDir.homePath()) log.debug('Current directory: {currentDir}'.format(currentDir=lastDir)) self.fileModel = QFileSystemModel(self) self.fileModel.setFilter(QDir.AllDirs | QDir.Dirs | QDir.Drives | QDir.NoDotAndDotDot | QDir.Readable | QDir.Executable | QDir.Writable) self.fileModel.iconProvider().setOptions( QFileIconProvider.DontUseCustomDirectoryIcons) self.fileModel.setRootPath(QDir.rootPath()) self.fileModel.directoryLoaded.connect(self.onFileModelDirectoryLoaded) self.proxyFileModel = QSortFilterProxyModel(self) self.proxyFileModel.setSortRole(Qt.DisplayRole) self.proxyFileModel.setSourceModel(self.fileModel) self.proxyFileModel.sort(0, Qt.AscendingOrder) self.proxyFileModel.setSortCaseSensitivity(Qt.CaseInsensitive) self.ui.folderView.setModel(self.proxyFileModel) self.ui.folderView.setHeaderHidden(True) self.ui.folderView.hideColumn(3) self.ui.folderView.hideColumn(2) self.ui.folderView.hideColumn(1) index = self.fileModel.index(lastDir) proxyIndex = self.proxyFileModel.mapFromSource(index) self.ui.folderView.scrollTo(proxyIndex) self.ui.folderView.expanded.connect(self.onFolderViewExpanded) self.ui.folderView.clicked.connect(self.onFolderTreeClicked) self.ui.buttonFind.clicked.connect(self.onButtonFind) self.ui.buttonRefresh.clicked.connect(self.onButtonRefresh) # Set up introduction self.showInstructions() # Set up video view self.ui.filterLanguageForVideo.set_unknown_text(_('All languages')) self.ui.filterLanguageForVideo.selected_language_changed.connect( self.on_language_combobox_filter_change) # self.ui.filterLanguageForVideo.selected_language_changed.connect(self.onFilterLanguageVideo) self.videoModel = VideoModel(self) self.ui.videoView.setHeaderHidden(True) self.ui.videoView.setModel(self.videoModel) self.ui.videoView.activated.connect(self.onClickVideoTreeView) self.ui.videoView.clicked.connect(self.onClickVideoTreeView) self.ui.videoView.customContextMenuRequested.connect(self.onContext) self.videoModel.dataChanged.connect(self.subtitlesCheckedChanged) self.language_filter_change.connect( self.videoModel.on_filter_languages_change) self.ui.buttonSearchSelectVideos.clicked.connect( self.onButtonSearchSelectVideos) self.ui.buttonSearchSelectFolder.clicked.connect( self.onButtonSearchSelectFolder) self.ui.buttonDownload.clicked.connect(self.onButtonDownload) self.ui.buttonPlay.clicked.connect(self.onButtonPlay) self.ui.buttonIMDB.clicked.connect(self.onViewOnlineInfo) self.ui.videoView.setContextMenuPolicy(Qt.CustomContextMenu) # Drag and Drop files to the videoView enabled self.ui.videoView.__class__.dragEnterEvent = self.dragEnterEvent self.ui.videoView.__class__.dragMoveEvent = self.dragEnterEvent self.ui.videoView.__class__.dropEvent = self.dropEvent self.ui.videoView.setAcceptDrops(1) # FIXME: ok to drop this connect? # self.ui.videoView.clicked.connect(self.onClickMovieTreeView) self.retranslate() def retranslate(self): introduction = '<p align="center"><h2>{title}</h2></p>' \ '<p><b>{tab1header}</b><br/>{tab1content}</p>' \ '<p><b>{tab2header}</b><br/>{tab2content}</p>'\ '<p><b>{tab3header}</b><br/>{tab3content}</p>'.format( title=_('How To Use {title}').format(title=PROJECT_TITLE), tab1header=_('1st Tab:'), tab2header=_('2nd Tab:'), tab3header=_('3rd Tab:'), tab1content=_('Select, from the Folder Tree on the left, the folder which contains the videos ' 'that need subtitles. {project} will then try to automatically find available ' 'subtitles.').format(project=PROJECT_TITLE), tab2content=_('If you don\'t have the videos in your machine, you can search subtitles by ' 'introducing the title/name of the video.').format(project=PROJECT_TITLE), tab3content=_('If you have found some subtitle somewhere else that is not in {project}\'s database, ' 'please upload those subtitles so next users will be able to ' 'find them more easily.').format(project=PROJECT_TITLE)) self.ui.introductionHelp.setHtml(introduction) @pyqtSlot(Language) def on_interface_language_changed(self, language): self.ui.retranslateUi(self) self.retranslate() @pyqtSlot(str) def onFileModelDirectoryLoaded(self, path): settings = QSettings() lastDir = settings.value('mainwindow/workingDirectory', QDir.homePath()) qDirLastDir = QDir(lastDir) qDirLastDir.cdUp() if qDirLastDir.path() == path: index = self.fileModel.index(lastDir) proxyIndex = self.proxyFileModel.mapFromSource(index) self.ui.folderView.scrollTo(proxyIndex) self.ui.folderView.setCurrentIndex(proxyIndex) @pyqtSlot(int, str) def on_login_state_changed(self, state, message): log.debug( 'on_login_state_changed(state={state}, message={message}'.format( state=state, message=message)) if state in (State.LOGIN_STATUS_LOGGED_OUT, State.LOGIN_STATUS_BUSY): self.ui.buttonSearchSelectFolder.setEnabled(False) self.ui.buttonSearchSelectVideos.setEnabled(False) self.ui.buttonFind.setEnabled(False) elif state == State.LOGIN_STATUS_LOGGED_IN: self.ui.buttonSearchSelectFolder.setEnabled(True) self.ui.buttonSearchSelectVideos.setEnabled(True) self.ui.buttonFind.setEnabled( self.get_current_selected_folder() is not None) else: log.warning('unknown state') @pyqtSlot(Language) def on_language_combobox_filter_change(self, language): if language.is_generic(): self.language_filter_change.emit( self.get_state().get_permanent_language_filter()) else: self.language_filter_change.emit([language]) def on_permanent_language_filter_change(self, languages): selected_language = self.ui.filterLanguageForVideo.get_selected_language( ) if selected_language.is_generic(): self.language_filter_change.emit(languages) @pyqtSlot() def subtitlesCheckedChanged(self): subs = self.videoModel.get_checked_subtitles() if subs: self.ui.buttonDownload.setEnabled(True) else: self.ui.buttonDownload.setEnabled(False) def showInstructions(self): self.ui.stackedSearchResult.setCurrentWidget(self.ui.pageIntroduction) def hideInstructions(self): self.ui.stackedSearchResult.setCurrentWidget(self.ui.pageSearchResult) @pyqtSlot(QModelIndex) def onFolderTreeClicked(self, proxyIndex): """What to do when a Folder in the tree is clicked""" if not proxyIndex.isValid(): return index = self.proxyFileModel.mapToSource(proxyIndex) settings = QSettings() folder_path = self.fileModel.filePath(index) settings.setValue('mainwindow/workingDirectory', folder_path) # self.ui.buttonFind.setEnabled(self.get_state().) def get_current_selected_folder(self): proxyIndex = self.ui.folderView.currentIndex() index = self.proxyFileModel.mapToSource(proxyIndex) folder_path = self.fileModel.filePath(index) if not folder_path: return None return folder_path def get_current_selected_item_videomodel(self): current_index = self.ui.videoView.currentIndex() return self.videoModel.getSelectedItem(current_index) @pyqtSlot() def onButtonFind(self): now = QTime.currentTime() if now < self.timeLastSearch.addMSecs(500): return folder_path = self.get_current_selected_folder() settings = QSettings() settings.setValue('mainwindow/workingDirectory', folder_path) self.search_videos([folder_path]) self.timeLastSearch = QTime.currentTime() @pyqtSlot() def onButtonRefresh(self): currentPath = self.get_current_selected_folder() if not currentPath: settings = QSettings() currentPath = settings.value('mainwindow/workingDirectory', QDir.homePath()) self._refreshing = True self.ui.folderView.collapseAll() currentPath = self.get_current_selected_folder() if not currentPath: settings = QSettings() currentPath = settings.value('mainwindow/workingDirectory', QDir.homePath()) index = self.fileModel.index(currentPath) self.ui.folderView.scrollTo(self.proxyFileModel.mapFromSource(index)) @pyqtSlot(QModelIndex) def onFolderViewExpanded(self, proxyIndex): if self._refreshing: expandedPath = self.fileModel.filePath( self.proxyFileModel.mapToSource(proxyIndex)) if expandedPath == QDir.rootPath(): currentPath = self.get_current_selected_folder() if not currentPath: settings = QSettings() currentPath = settings.value('mainwindow/workingDirectory', QDir.homePath()) index = self.fileModel.index(currentPath) self.ui.folderView.scrollTo( self.proxyFileModel.mapFromSource(index)) self._refreshing = False @pyqtSlot() def onButtonSearchSelectFolder(self): settings = QSettings() path = settings.value('mainwindow/workingDirectory', QDir.homePath()) folder_path = QFileDialog.getExistingDirectory( self, _('Select the directory that contains your videos'), path) if folder_path: settings.setValue('mainwindow/workingDirectory', folder_path) self.search_videos([folder_path]) @pyqtSlot() def onButtonSearchSelectVideos(self): settings = QSettings() currentDir = settings.value('mainwindow/workingDirectory', QDir.homePath()) fileNames, t = QFileDialog.getOpenFileNames( self, _('Select the video(s) that need subtitles'), currentDir, SELECT_VIDEOS) if fileNames: settings.setValue('mainwindow/workingDirectory', QFileInfo(fileNames[0]).absolutePath()) self.search_videos(fileNames) def search_videos(self, paths): if not self.get_state().connected(): QMessageBox.about( self, _("Error"), _('You are not connected to the server. Please reconnect first.' )) return self.ui.buttonFind.setEnabled(False) self._search_videos_raw(paths) self.ui.buttonFind.setEnabled(True) def _search_videos_raw(self, paths): # FIXME: must pass mainwindow as argument to ProgressCallbackWidget callback = ProgressCallbackWidget(self) callback.set_title_text(_("Scanning...")) callback.set_label_text(_("Scanning files")) callback.set_finished_text(_("Scanning finished")) callback.set_block(True) try: local_videos, local_subs = scan_videopaths(paths, callback=callback, recursive=True) except OSError: callback.cancel() QMessageBox.warning(self, _('Error'), _('Some directories are not accessible.')) if callback.canceled(): return callback.finish() log.debug("Videos found: %s" % local_videos) log.debug("Subtitles found: %s" % local_subs) self.hideInstructions() QCoreApplication.processEvents() if not local_videos: QMessageBox.about(self, _("Scan Results"), _("No video has been found!")) return total = len(local_videos) # FIXME: must pass mainwindow as argument to ProgressCallbackWidget # callback = ProgressCallbackWidget(self) # callback.set_title_text(_("Asking Server...")) # callback.set_label_text(_("Searching subtitles...")) # callback.set_updated_text(_("Searching subtitles ( %d / %d )")) # callback.set_finished_text(_("Search finished")) callback.set_block(True) callback.set_range(0, total) callback.show() callback.set_range(0, 2) download_callback = callback.get_child_progress(0, 1) # videoSearchResults = self.get_state().get_OSDBServer().SearchSubtitles("", videos_piece) remote_subs = self.get_state().get_OSDBServer().search_videos( videos=local_videos, callback=download_callback) self.videoModel.set_videos(local_videos) # self.onFilterLanguageVideo(self.ui.filterLanguageForVideo.get_selected_language()) if remote_subs is None: QMessageBox.about( self, _("Error"), _("Error contacting the server. Please try again later")) callback.finish() # TODO: CHECK if our local subtitles are already in the server, otherwise suggest to upload # self.OSDBServer.CheckSubHash(sub_hashes) @pyqtSlot() def onButtonPlay(self): settings = QSettings() programPath = settings.value('options/VideoPlayerPath', '') parameters = settings.value('options/VideoPlayerParameters', '') if programPath == '': QMessageBox.about( self, _('Error'), _('No default video player has been defined in Settings.')) return selected_subtitle = self.get_current_selected_item_videomodel() if isinstance(selected_subtitle, SubtitleFileNetwork): selected_subtitle = selected_subtitle.get_subtitles()[0] if isinstance(selected_subtitle, LocalSubtitleFile): subtitle_file_path = selected_subtitle.get_filepath() elif isinstance(selected_subtitle, RemoteSubtitleFile): subtitle_file_path = QDir.temp().absoluteFilePath( 'subdownloader.tmp.srt') log.debug( 'Temporary subtitle will be downloaded into: {temp_path}'. format(temp_path=subtitle_file_path)) # FIXME: must pass mainwindow as argument to ProgressCallbackWidget callback = ProgressCallbackWidget(self) callback.set_title_text(_('Playing video + sub')) callback.set_label_text(_('Downloading files...')) callback.set_finished_text(_('Downloading finished')) callback.set_block(True) callback.set_range(0, 100) callback.show() try: subtitle_stream = selected_subtitle.download( self.get_state().get_OSDBServer(), callback=callback) except ProviderConnectionError: log.debug('Unable to download subtitle "{}"'.format( selected_subtitle.get_filename()), exc_info=True) QMessageBox.about( self, _('Error'), _('Unable to download subtitle "{subtitle}"').format( subtitle=selected_subtitle.get_filename())) callback.finish() return callback.finish() write_stream(subtitle_stream, subtitle_file_path) video = selected_subtitle.get_parent().get_parent().get_parent() def windows_escape(text): return '"{text}"'.format(text=text.replace('"', '\\"')) params = [windows_escape(programPath)] for param in parameters.split(' '): param = param.format(video.get_filepath(), subtitle_file_path) if platform.system() in ('Windows', 'Microsoft'): param = windows_escape(param) params.append(param) pid = None log.info('Running this command: {params}'.format(params=params)) try: log.debug('Trying os.spawnvpe ...') pid = os.spawnvpe(os.P_NOWAIT, programPath, params, os.environ) log.debug('... SUCCESS. pid={pid}'.format(pid=pid)) except AttributeError: log.debug('... FAILED', exc_info=True) except Exception as e: log.debug('... FAILED', exc_info=True) if pid is None: try: log.debug('Trying os.fork ...') pid = os.fork() if not pid: log.debug('... SUCCESS. pid={pid}'.format(pid=pid)) os.execvpe(os.P_NOWAIT, programPath, params, os.environ) except: log.debug('... FAIL', exc_info=True) if pid is None: QMessageBox.about(self, _('Error'), _('Unable to launch videoplayer')) @pyqtSlot(QModelIndex) def onClickVideoTreeView(self, index): data_item = self.videoModel.getSelectedItem(index) if isinstance(data_item, SubtitleFile): self.ui.buttonPlay.setEnabled(True) else: self.ui.buttonPlay.setEnabled(False) if isinstance(data_item, VideoFile): video = data_item if True: # video.getMovieInfo(): self.ui.buttonIMDB.setEnabled(True) self.ui.buttonIMDB.setIcon(QIcon(':/images/info.png')) self.ui.buttonIMDB.setText(_('Movie Info')) elif isinstance(data_item, RemoteSubtitleFile): self.ui.buttonIMDB.setEnabled(True) self.ui.buttonIMDB.setIcon( QIcon(':/images/sites/opensubtitles.png')) self.ui.buttonIMDB.setText(_('Subtitle Info')) else: self.ui.buttonIMDB.setEnabled(False) def onContext(self, point): # FIXME: code duplication with Main.onContext and/or SearchNameWidget and/or SearchFileWidget menu = QMenu('Menu', self) listview = self.ui.videoView index = listview.currentIndex() data_item = listview.model().getSelectedItem(index) if data_item is not None: if isinstance(data_item, VideoFile): video = data_item movie_info = video.getMovieInfo() if movie_info: subWebsiteAction = QAction(QIcon(":/images/info.png"), _("View IMDB info"), self) subWebsiteAction.triggered.connect(self.onViewOnlineInfo) else: subWebsiteAction = QAction(QIcon(":/images/info.png"), _("Set IMDB info..."), self) subWebsiteAction.triggered.connect(self.onSetIMDBInfo) menu.addAction(subWebsiteAction) elif isinstance(data_item, SubtitleFile): downloadAction = QAction(QIcon(":/images/download.png"), _("Download"), self) # Video tab, TODO:Replace me with a enum downloadAction.triggered.connect(self.onButtonDownload) playAction = QAction(QIcon(":/images/play.png"), _("Play video + subtitle"), self) playAction.triggered.connect(self.onButtonPlay) menu.addAction(playAction) subWebsiteAction = QAction( QIcon(":/images/sites/opensubtitles.png"), _("View online info"), self) menu.addAction(downloadAction) subWebsiteAction.triggered.connect(self.onViewOnlineInfo) menu.addAction(subWebsiteAction) elif isinstance(data_item, Movie): subWebsiteAction = QAction(QIcon(":/images/info.png"), _("View IMDB info"), self) subWebsiteAction.triggered.connect(self.onViewOnlineInfo) menu.addAction(subWebsiteAction) # Show the context menu. menu.exec_(listview.mapToGlobal(point)) def onButtonDownload(self): # We download the subtitle in the same folder than the video subs = self.videoModel.get_checked_subtitles() replace_all = False skip_all = False if not subs: QMessageBox.about(self, _("Error"), _("No subtitles selected to be downloaded")) return total_subs = len(subs) answer = None success_downloaded = 0 # FIXME: must pass mainwindow as argument to ProgressCallbackWidget callback = ProgressCallbackWidget(self) callback.set_title_text(_("Downloading...")) callback.set_label_text(_("Downloading files...")) callback.set_updated_text(_("Downloading subtitle {0} ({1}/{2})")) callback.set_finished_text( _("{0} from {1} subtitles downloaded successfully")) callback.set_block(True) callback.set_range(0, total_subs) callback.show() for i, sub in enumerate(subs): if callback.canceled(): break destinationPath = self.get_state().getDownloadPath(self, sub) if not destinationPath: break log.debug("Trying to download subtitle '%s'" % destinationPath) callback.update(i, QFileInfo(destinationPath).fileName(), i + 1, total_subs) # Check if we have write permissions, otherwise show warning window while True: # If the file and the folder don't have write access. if not QFileInfo( destinationPath).isWritable() and not QFileInfo( QFileInfo(destinationPath).absoluteDir().path() ).isWritable(): warningBox = QMessageBox( _("Error write permission"), _("%s cannot be saved.\nCheck that the folder exists and you have write-access permissions." ) % destinationPath, QMessageBox.Warning, QMessageBox.Retry | QMessageBox.Default, QMessageBox.Discard | QMessageBox.Escape, QMessageBox.NoButton, self) saveAsButton = warningBox.addButton( _("Save as..."), QMessageBox.ActionRole) answer = warningBox.exec_() if answer == QMessageBox.Retry: continue elif answer == QMessageBox.Discard: break # Let's get out from the While true # If we choose the SAVE AS elif answer == QMessageBox.NoButton: fileName, t = QFileDialog.getSaveFileName( self, _("Save subtitle as..."), destinationPath, 'All (*.*)') if fileName: destinationPath = fileName else: # If we have write access we leave the while loop. break # If we have chosen Discard subtitle button. if answer == QMessageBox.Discard: continue # Continue the next subtitle optionWhereToDownload = QSettings().value( "options/whereToDownload", "SAME_FOLDER") # Check if doesn't exists already, otherwise show fileExistsBox # dialog if QFileInfo(destinationPath).exists( ) and not replace_all and not skip_all and optionWhereToDownload != "ASK_FOLDER": # The "remote filename" below is actually not the real filename. Real name could be confusing # since we always rename downloaded sub to match movie # filename. fileExistsBox = QMessageBox( QMessageBox.Warning, _("File already exists"), _("Local: {local}\n\nRemote: {remote}\n\nHow would you like to proceed?" ).format(local=destinationPath, remote=QFileInfo(destinationPath).fileName()), QMessageBox.NoButton, self) skipButton = fileExistsBox.addButton(_("Skip"), QMessageBox.ActionRole) # skipAllButton = fileExistsBox.addButton(_("Skip all"), QMessageBox.ActionRole) replaceButton = fileExistsBox.addButton( _("Replace"), QMessageBox.ActionRole) replaceAllButton = fileExistsBox.addButton( _("Replace all"), QMessageBox.ActionRole) saveAsButton = fileExistsBox.addButton(_("Save as..."), QMessageBox.ActionRole) cancelButton = fileExistsBox.addButton(_("Cancel"), QMessageBox.ActionRole) fileExistsBox.exec_() answer = fileExistsBox.clickedButton() if answer == replaceAllButton: # Don't ask us again (for this batch of files) replace_all = True elif answer == saveAsButton: # We will find a uniqiue filename and suggest this to user. # add .<lang> to (inside) the filename. If that is not enough, start adding numbers. # There should also be a preferences setting "Autorename # files" or similar ( =never ask) FIXME suggBaseName, suggFileExt = os.path.splitext( destinationPath) fNameCtr = 0 # Counter used to generate a unique filename suggestedFileName = suggBaseName + '.' + \ sub.get_language().xxx() + suggFileExt while (os.path.exists(suggestedFileName)): fNameCtr += 1 suggestedFileName = suggBaseName + '.' + \ sub.get_language().xxx() + '-' + \ str(fNameCtr) + suggFileExt fileName, t = QFileDialog.getSaveFileName( None, _("Save subtitle as..."), suggestedFileName, 'All (*.*)') if fileName: destinationPath = fileName else: # Skip this particular file if no filename chosen continue elif answer == skipButton: continue # Skip this particular file # elif answer == skipAllButton: # count += percentage # skip_all = True # Skip all files already downloaded # continue elif answer == cancelButton: break # Break out of DL loop - cancel was pushed QCoreApplication.processEvents() # FIXME: redundant update? callback.update(i, QFileInfo(destinationPath).fileName(), i + 1, total_subs) try: if not skip_all: log.debug("Downloading subtitle '%s'" % destinationPath) download_callback = ProgressCallback() # FIXME data_stream = sub.download( provider_instance=self.get_state().get_OSDBServer(), callback=download_callback, ) write_stream(data_stream, destinationPath) except Exception as e: log.exception('Unable to Download subtitle {}'.format( sub.get_filename())) QMessageBox.about( self, _("Error"), _("Unable to download subtitle %s") % sub.get_filename()) callback.finish(success_downloaded, total_subs) def onViewOnlineInfo(self): # FIXME: code duplication with Main.onContext and/or SearchNameWidget and/or SearchFileWidget # Tab for SearchByHash TODO:replace this 0 by an ENUM value listview = self.ui.videoView index = listview.currentIndex() data_item = self.videoModel.getSelectedItem(index) if isinstance(data_item, VideoFile): video = data_item movie_info = video.getMovieInfo() if movie_info: imdb = movie_info["IDMovieImdb"] if imdb: webbrowser.open("http://www.imdb.com/title/tt%s" % imdb, new=2, autoraise=1) elif isinstance(data_item, RemoteSubtitleFile): sub = data_item webbrowser.open(sub.get_link(), new=2, autoraise=1) elif isinstance(data_item, Movie): movie = data_item imdb = movie.IMDBId if imdb: webbrowser.open("http://www.imdb.com/title/tt%s" % imdb, new=2, autoraise=1) @pyqtSlot() def onSetIMDBInfo(self): #FIXME: DUPLICATED WITH SEARCHNAMEWIDGET QMessageBox.about(self, _("Info"), "Not implemented yet. Sorry...")
class MainWidget(QWidget): def __init__(self): super().__init__() self.left = 10 self.top = 10 self.width = 400 self.height = 500 self.leftPanelWidth = 250 self.processed_image: Segmented_image = None self.initUI() def initUI(self): self.setGeometry(self.left, self.top, self.width, self.height) self.model = QFileSystemModel() self.model.setRootPath( r'C:\Users\kkozi\Documents\WORKSPACE\pomwj_projekt\data ') self.model.setReadOnly(True) tmpIdx = self.model.index( r'C:\Users\kkozi\Documents\WORKSPACE\pomwj_projekt\data') self.tree = QTreeView() self.tree.setModel(self.model) self.tree.doubleClicked.connect(self.SetProcessedImage) self.tree.setRootIndex(tmpIdx) self.img = QPixmap( r'C:\Users\kkozi\Documents\WORKSPACE\pomwj_projekt\data\no_image.jpg' ) self.imgLabel = QLabel() self.imgLabel.setAlignment(Qt.AlignCenter) self.imgLabel.setContentsMargins(30, 0, 0, 30) self.imgLabel.setStyleSheet("text-align: right; color: white;") self.imgLabel.setPixmap(self.img) splitter = QSplitter(Qt.Horizontal) splitter.addWidget(self.tree) splitter.addWidget(self.imgLabel) self.processing_wdg = Processing_data_widget() self.processing_wdg.process_btn.clicked.connect(self.MakeSegmentation) downLayout = QHBoxLayout() downLayout.addWidget(splitter) downLayout.addWidget(self.processing_wdg) mainLayout = QVBoxLayout(self) mainLayout.addLayout(downLayout) def SetProcessedImage(self, index): try: path = self.model.filePath(index) self.processed_image = Segmented_image() self.processed_image.SetImage(path) self.processing_wdg.SetFileParams( path, self.processed_image.GetColorType()) if self.ImgIsRGB(): self.processing_wdg.SetConvertBtnActive() self.processing_wdg.convert_btn.clicked.connect( self.ConvertToHSV) else: self.processing_wdg.SetConvertBtnDisactive() self.processing_wdg.process_btn.setDisabled(False) self.ShowSelectedImage() if not self.processed_image.IsSetImage(): QMessageBox.information(self, "Segmented_image Viewer", "Cannot load %s." % 'image') except FileFormatError as ex: QMessageBox.information(self, 'Format no supported', '{0}'.format(str(ex.message)), QMessageBox.Ok) def ShowSelectedImage(self): self.img = QPixmap.fromImage(self.processed_image.GetQImageFromImage()) self.img = self.img.scaled(self.imgLabel.width() * 0.9, self.imgLabel.height() * 0.9, Qt.KeepAspectRatio) self.imgLabel.setPixmap(self.img) self.imgLabel.resize(self.width * 0.95, self.height * 0.95) def MakeSegmentation(self): progress_dialog = QProgressDialog() segmentation = Segmentation(self.processed_image) progress_dialog.setValue(10) seg_img = segmentation.makeSegment(self.processing_wdg.GetMinObjSize(), self.processing_wdg.GetThrDown(), self.processing_wdg.GetThrUp()) progress_dialog.setValue(30) self.processed_image = Segmented_image.FromSITKImage(seg_img) progress_dialog.setValue(50) self.processing_wdg.SetCellsNumResult(segmentation.GetCellsNum()) progress_dialog.setValue(80) self.ShowSelectedImage() progress_dialog.setValue(100) progress_dialog.close() def resizeEvent(self, event): self.img = self.img.scaled(self.imgLabel.width() * 0.9, self.imgLabel.height() * 0.9, Qt.KeepAspectRatio) self.imgLabel.setPixmap(self.img) self.imgLabel.resize(self.width * 0.95, self.height * 0.95) def ImgIsRGB(self): if self.processed_image.colorType == 'RGB': return True else: return False def ConvertToHSV(self): progress_dialog = QProgressDialog() self.processing_wdg.SetConvertBtnDisactive() image = self.processed_image.ConvertToHSV() self.processed_image = Segmented_image.FromSITKImage(image) self.ShowSelectedImage() progress_dialog.close()
parser = QCommandLineParser() parser.setApplicationDescription("Qt Dir View Example") parser.addHelpOption() parser.addVersionOption() dontUseCustomDirectoryIconsOption = QCommandLineOption('c', "Set QFileIconProvider.DontUseCustomDirectoryIcons") parser.addOption(dontUseCustomDirectoryIconsOption) parser.addPositionalArgument('directory', "The directory to start in.") parser.process(app) try: rootPath = parser.positionalArguments().pop(0) except IndexError: rootPath = None model = QFileSystemModel() model.setRootPath('') if parser.isSet(dontUseCustomDirectoryIconsOption): model.iconProvider().setOptions( QFileIconProvider.DontUseCustomDirectoryIcons) tree = QTreeView() tree.setModel(model) if rootPath is not None: rootIndex = model.index(QDir.cleanPath(rootPath)) if rootIndex.isValid(): tree.setRootIndex(rootIndex) # Demonstrating look and feel features. tree.setAnimated(False) tree.setIndentation(20) tree.setSortingEnabled(True)
def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) pasteBox = QHBoxLayout() self.textLine = QLineEdit() self.textLine.setToolTip('Current Director/selected File') self.pasteButton = QToolButton() self.pasteButton.setEnabled(False) self.pasteButton.setText('Paste') self.pasteButton.setToolTip( 'Copy file from copy path to current directory/file') self.pasteButton.clicked.connect(self.paste) self.pasteButton.hide() pasteBox.addWidget(self.textLine) pasteBox.addWidget(self.pasteButton) self.copyBox = QFrame() hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.copyLine = QLineEdit() self.copyLine.setToolTip('File path to copy from, when pasting') self.copyButton = QToolButton() self.copyButton.setText('Copy') self.copyButton.setToolTip('Record current file as copy path') self.copyButton.clicked.connect(self.recordCopyPath) hbox.addWidget(self.copyButton) hbox.addWidget(self.copyLine) self.copyBox.setLayout(hbox) self.copyBox.hide() self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.rootPathChanged.connect(self.folderChanged) self.list = QListView() self.list.setModel(self.model) self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.listClicked) self.list.activated.connect(self._getPathActivated) self.list.setAlternatingRowColors(True) self.list.hide() self.table = QTableView() self.table.setModel(self.model) self.table.resize(640, 480) self.table.clicked[QModelIndex].connect(self.listClicked) self.table.activated.connect(self._getPathActivated) self.table.setAlternatingRowColors(True) header = self.table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.setSectionResizeMode(3, QHeaderView.ResizeToContents) header.swapSections(1, 3) header.setSortIndicator(1, Qt.AscendingOrder) self.table.setSortingEnabled(True) self.table.setColumnHidden(2, True) # type self.table.verticalHeader().setVisible(False) # row count header self.cb = QComboBox() self.cb.currentIndexChanged.connect(self.filterChanged) self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS) self.cb.setMinimumHeight(30) self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2 = QToolButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setMinimumSize(60, 30) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.button2.clicked.connect(self.onJumpClicked) self.button3 = QToolButton() self.button3.setText('Add Jump') self.button3.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button3.setMinimumSize(60, 30) self.button3.setToolTip('Add current directory to jump button list') self.button3.clicked.connect(self.onActionClicked) self.settingMenu = QMenu(self) self.button2.setMenu(self.settingMenu) hbox = QHBoxLayout() hbox.addWidget(self.button2) hbox.addWidget(self.button3) hbox.insertStretch(2, stretch=0) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addLayout(pasteBox) windowLayout.addWidget(self.copyBox) windowLayout.addWidget(self.list) windowLayout.addWidget(self.table) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show()
class AssetBrowser(QMainWindow, Ui_MainWindow, PlaygroundModule): Name = "asset_browser" def __init__(self, module_manager): super(AssetBrowser, self).__init__() self.setupUi(self) self.init_module(module_manager) self.dir_model = QFileSystemModel() self.dir_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dir_model.setReadOnly(False) self.dir_view.setModel(self.dir_model) self.dir_view.hideColumn(1) self.dir_view.hideColumn(2) self.dir_view.hideColumn(3) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.file_model.setReadOnly(False) self.file_view.setModel(self.file_model) self.dock = self.modules_manager.new_docked(self, self.Name, "Asset browser", Qt.BottomDockWidgetArea) self.modules_manager.main_window.splitDockWidget(self.dock, self.modules_manager["asset_view"].dock, Qt.Horizontal) def on_open_project(self, project): project_dir = project.project_dir path = os.path.join(project_dir) self.dir_model.setRootPath(path) self.file_model.setRootPath(path) self.dir_view.setRootIndex(self.dir_model.index(path)) self.file_view.setRootIndex(self.file_model.index(path)) def dir_clicked(self, idx): path = self.dir_model.fileInfo(idx).absoluteFilePath() self.file_view.setRootIndex(self.file_model.setRootPath(path)) def file_doubleclicked(self, idx): fileinfo = self.file_model.fileInfo(idx) path = fileinfo.absoluteFilePath() ext = fileinfo.suffix() asset_name = path.replace(self.project_manager.project_dir, '').replace('/src/', '').split('.')[0] self.modules_manager.open_asset(path, asset_name, ext) def file_clicked(self, idx): fileinfo = self.file_model.fileInfo(idx) path = fileinfo.absoluteFilePath() ext = fileinfo.suffix() asset_name = path.replace(self.project_manager.project_dir, '').replace('/src/', '').split('.')[0] self.modules_manager.show_asset(path, asset_name, ext)
def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) QtAds.CDockManager.setConfigFlag( QtAds.CDockManager.OpaqueSplitterResize, True) QtAds.CDockManager.setConfigFlag( QtAds.CDockManager.XmlCompressionEnabled, False) QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True) self.dock_manager = QtAds.CDockManager(self) # Set central widget text_edit = QPlainTextEdit() text_edit.setPlaceholderText( "This is the central editor. Enter your text here.") central_dock_widget = QtAds.CDockWidget("CentralWidget") central_dock_widget.setWidget(text_edit) central_dock_area = self.dock_manager.setCentralWidget( central_dock_widget) central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas) # create other dock widgets file_tree = QTreeView() file_tree.setFrameShape(QFrame.NoFrame) file_model = QFileSystemModel(file_tree) file_model.setRootPath(QDir.currentPath()) file_tree.setModel(file_model) data_dock_widget = QtAds.CDockWidget("File system") data_dock_widget.setWidget(file_tree) data_dock_widget.resize(150, 250) data_dock_widget.setMinimumSize(100, 250) file_area = self.dock_manager.addDockWidget( QtAds.DockWidgetArea.LeftDockWidgetArea, data_dock_widget, central_dock_area) self.menuView.addAction(data_dock_widget.toggleViewAction()) table = QTableWidget() table.setColumnCount(3) table.setRowCount(10) table_dock_widget = QtAds.CDockWidget("Table") table_dock_widget.setWidget(table) table_dock_widget.setMinimumSizeHintMode( QtAds.CDockWidget.MinimumSizeHintFromDockWidget) table_dock_widget.resize(250, 150) table_dock_widget.setMinimumSize(200, 150) self.dock_manager.addDockWidget( QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, file_area) self.menuView.addAction(table_dock_widget.toggleViewAction()) properties_table = QTableWidget() properties_table.setColumnCount(3) properties_table.setRowCount(10) properties_dock_widget = QtAds.CDockWidget("Properties") properties_dock_widget.setWidget(properties_table) properties_dock_widget.setMinimumSizeHintMode( QtAds.CDockWidget.MinimumSizeHintFromDockWidget) properties_dock_widget.resize(250, 150) properties_dock_widget.setMinimumSize(200, 150) self.dock_manager.addDockWidget( QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area) self.menuView.addAction(properties_dock_widget.toggleViewAction()) self.create_perspective_ui()
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'Qtvcp File System View' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self._last = 0 if INFO.PROGRAM_PREFIX is not None: self.user_path = os.path.expanduser(INFO.PROGRAM_PREFIX) else: self.user_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files')) user = os.path.split(os.path.expanduser('~'))[-1] self.media_path = (os.path.join('/media', user)) temp = [('User', self.user_path), ('Media', self.media_path)] self._jumpList = OrderedDict(temp) self.currentPath = None self.currentFolder = None self.PREFS_ = None self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) pasteBox = QHBoxLayout() self.textLine = QLineEdit() self.textLine.setToolTip('Current Director/selected File') self.pasteButton = QToolButton() self.pasteButton.setEnabled(False) self.pasteButton.setText('Paste') self.pasteButton.setToolTip( 'Copy file from copy path to current directory/file') self.pasteButton.clicked.connect(self.paste) self.pasteButton.hide() pasteBox.addWidget(self.textLine) pasteBox.addWidget(self.pasteButton) self.copyBox = QFrame() hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.copyLine = QLineEdit() self.copyLine.setToolTip('File path to copy from, when pasting') self.copyButton = QToolButton() self.copyButton.setText('Copy') self.copyButton.setToolTip('Record current file as copy path') self.copyButton.clicked.connect(self.recordCopyPath) hbox.addWidget(self.copyButton) hbox.addWidget(self.copyLine) self.copyBox.setLayout(hbox) self.copyBox.hide() self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.rootPathChanged.connect(self.folderChanged) self.list = QListView() self.list.setModel(self.model) self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.listClicked) self.list.activated.connect(self._getPathActivated) self.list.setAlternatingRowColors(True) self.list.hide() self.table = QTableView() self.table.setModel(self.model) self.table.resize(640, 480) self.table.clicked[QModelIndex].connect(self.listClicked) self.table.activated.connect(self._getPathActivated) self.table.setAlternatingRowColors(True) header = self.table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.setSectionResizeMode(3, QHeaderView.ResizeToContents) header.swapSections(1, 3) header.setSortIndicator(1, Qt.AscendingOrder) self.table.setSortingEnabled(True) self.table.setColumnHidden(2, True) # type self.table.verticalHeader().setVisible(False) # row count header self.cb = QComboBox() self.cb.currentIndexChanged.connect(self.filterChanged) self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS) self.cb.setMinimumHeight(30) self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2 = QToolButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setMinimumSize(60, 30) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.button2.clicked.connect(self.onJumpClicked) self.button3 = QToolButton() self.button3.setText('Add Jump') self.button3.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button3.setMinimumSize(60, 30) self.button3.setToolTip('Add current directory to jump button list') self.button3.clicked.connect(self.onActionClicked) self.settingMenu = QMenu(self) self.button2.setMenu(self.settingMenu) hbox = QHBoxLayout() hbox.addWidget(self.button2) hbox.addWidget(self.button3) hbox.insertStretch(2, stretch=0) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addLayout(pasteBox) windowLayout.addWidget(self.copyBox) windowLayout.addWidget(self.list) windowLayout.addWidget(self.table) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.user_path, str, 'BOOK_KEEPING') self.updateDirectoryView(last_path) LOG.debug("lAST FILE PATH: {}".format(last_path)) # get all the saved jumplist paths temp = self.PREFS_.getall('FILEMANAGER_JUMPLIST') self._jumpList.update(temp) else: LOG.debug("lAST FILE PATH: {}".format(self.user_path)) self.updateDirectoryView(self.user_path) # install jump paths into toolbutton menu for i in self._jumpList: axisButton = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' axisButton.triggered.connect( lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(axisButton) ######################### # callbacks ######################### # add shown text and hidden filter data from the INI def fillCombobox(self, data): for i in data: self.cb.addItem(i[0], i[1]) def folderChanged(self, data): data = os.path.normpath(data) self.currentFolder = data self.textLine.setText(data) def updateDirectoryView(self, path, quiet=False): if os.path.exists(path): self.list.setRootIndex(self.model.setRootPath(path)) self.table.setRootIndex(self.model.setRootPath(path)) else: LOG.debug( "Set directory view error - no such path {}".format(path)) if not quiet: STATUS.emit( 'error', LOW_ERROR, "File Manager error - No such path: {}".format(path)) # retrieve selected filter (it's held as QT.userData) def filterChanged(self, index): userdata = self.cb.itemData(index) self.model.setNameFilters(userdata) def listClicked(self, index): # the signal passes the index of the clicked item dir_path = os.path.normpath(self.model.filePath(index)) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path self.textLine.setText(self.currentPath) return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) self.table.setRootIndex(root_index) def onUserClicked(self): self.showUserDir() def onMediaClicked(self): self.showMediaDir() # jump directly to a saved path shown on the button def onJumpClicked(self): data = self.button2.text() if data.upper() == 'MEDIA': self.showMediaDir() elif data.upper() == 'USER': self.showUserDir() else: temp = self._jumpList.get(data) if temp is not None: self.updateDirectoryView(temp) else: STATUS.emit('error', linuxcnc.OPERATOR_ERROR, 'file jumopath: {} not valid'.format(data)) log.debug('file jumopath: {} not valid'.format(data)) # jump directly to a saved path from the menu def jumpTriggered(self, data): if data.upper() == 'MEDIA': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to Media directory.\nLong press for Options.') self.showMediaDir() elif data.upper() == 'USER': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.showUserDir() else: self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to directory:\n{}'.format( self._jumpList.get(data))) self.updateDirectoryView(self._jumpList.get(data)) # add a jump list path def onActionClicked(self): i = self.currentFolder try: self._jumpList[i] = i except Exception as e: print(e) button = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' button.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(button) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def _getPathActivated(self): if self.list.isVisible(): row = self.list.selectionModel().currentIndex() else: row = self.table.selectionModel().currentIndex() self.listClicked(row) fname = self.currentPath if fname is None: return if fname: self.load(fname) def recordCopyPath(self): data, isFile = self.getCurrentSelected() if isFile: self.copyLine.setText(os.path.normpath(data)) self.pasteButton.setEnabled(True) else: self.copyLine.setText('') self.pasteButton.setEnabled(False) STATUS.emit('error', OPERATOR_ERROR, 'Can only copy a file, not a folder') def paste(self): res = self.copyFile(self.copyLine.text(), self.textLine.text()) if res: self.copyLine.setText('') self.pasteButton.setEnabled(False) ######################## # helper functions ######################## def showList(self, state=True): if state: self.table.hide() self.list.show() else: self.table.show() self.list.hide() def showTable(self, state=True): self.showList(not state) def showCopyControls(self, state): if state: self.copyBox.show() self.pasteButton.show() else: self.copyBox.hide() self.pasteButton.hide() def showMediaDir(self, quiet=False): self.updateDirectoryView(self.media_path, quiet) def showUserDir(self, quiet=False): self.updateDirectoryView(self.user_path, quiet) def copyFile(self, s, d): try: shutil.copy(s, d) return True except Exception as e: LOG.error("Copy file error: {}".format(e)) STATUS.emit('error', OPERATOR_ERROR, "Copy file error: {}".format(e)) return False @pyqtSlot(float) @pyqtSlot(int) def scroll(self, data): if data > self._last: self.up() elif data < self._last: self.down() self._last = data # moves the selection up # used with MPG scrolling def up(self): self.select_row('up') # moves the selection down # used with MPG scrolling def down(self): self.select_row('down') def select_row(self, style='down'): style = style.lower() if self.list.isVisible(): i = self.list.rootIndex() selectionModel = self.list.selectionModel() else: i = self.table.rootIndex() selectionModel = self.table.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(i) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows - 1: row += 1 else: row = self.rows - 1 else: return top = self.model.index(row, 0, i) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) # returns the current highlighted (selected) path as well as # whether it's a file or not. def getCurrentSelected(self): if self.list.isVisible(): selectionModel = self.list.selectionModel() else: selectionModel = self.table.selectionModel() index = selectionModel.currentIndex() dir_path = self.model.filePath(index) if self.model.fileInfo(index).isFile(): return (dir_path, True) else: return (dir_path, False) # This can be class patched to do something else def load(self, fname=None): try: if fname is None: self._getPathActivated() return self.recordBookKeeping() ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') except Exception as e: LOG.error("Load file error: {}".format(e)) STATUS.emit('error', NML_ERROR, "Load file error: {}".format(e)) # This can be class patched to do something else def recordBookKeeping(self): fname = self.currentPath if fname is None: return if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING') # when qtvcp closes this gets called # record jump list paths def closing_cleanup__(self): if self.PREFS_: for i, key in enumerate(self._jumpList): if i in (0, 1): continue self.PREFS_.putpref(key, self._jumpList.get(key), str, 'FILEMANAGER_JUMPLIST')
class Directory(QTreeView): def __init__(self, callback, app=None, palette=None): super().__init__() directoryFont = QFont() self.app = app self.palette = palette directoryFont.setFamily(editor["directoryFont"]) directoryFont.setPointSize(editor["directoryFontSize"]) self.open_callback = callback self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.openMenu) self.setFont(directoryFont) self.layout = QHBoxLayout() self.model = QFileSystemModel() self.setModel(self.model) self.model.setRootPath(QDir.rootPath()) self.setMaximumWidth(300) self.setIndentation(10) self.setAnimated(True) self.newFile() self.setSortingEnabled(True) self.setWindowTitle("Dir View") self.hideColumn(1) self.resize(200, 600) self.hideColumn(2) self.confirmation = MessageBox() self.hideColumn(3) # self.layout.addWidget(self) self.doubleClicked.connect(self.openFile) def newFile(self): self.newAct = QAction('New') self.newAct.setStatusTip('Create a new file') self.newAct.triggered.connect(lambda: print("new file created lol")) def openMenu(self, position): indexes = self.selectedIndexes() if len(indexes) > 0: level = 0 index = indexes[0] while index.parent().isValid(): index = index.parent() level += 1 menu = QMenu() menu.addAction( self.newAct ) # TODO: Add more context menu stuff and make them functional menu.exec_(self.viewport().mapToGlobal(position)) def focusInEvent(self, event): # If we are focused then we change the selected item highlighting color self.focused = True self.palette.setColor(QPalette.Highlight, QColor(editor["HighlightColor"]).lighter()) self.app.setPalette(self.palette) def focusOutEvent(self, event): # If we un focus from the QTreeView then we make the highlighted item color white self.palette.setColor( QPalette.Highlight, QColor(editor["UnfocusedHighlightColor"]).lighter()) # self.clearSelection() Uncomment this if you want to remove all highlighting when unfocused self.app.setPalette(self.palette) def openDirectory(self, path): self.setRootIndex(self.model.index(path)) def openFile(self, signal): file_path = self.model.filePath(signal) self.open_callback(file_path) return file_path def keyPressEvent(self, event): key = event.key() if key == Qt.Key_Delete: try: self.fileObject = self.selectedIndexes()[0] fileName = self.model.filePath(self.fileObject) self.confirmation.run("Are you sure you want to delete ", str(fileName)) except IndexError: print("No file selected")
class LocalPathView(QTreeView): def __init__ (self): super(LocalPathView, self).__init__() self._model = QFileSystemModel() self._model.setFilter(QDir.Dirs | QDir.Drives | QDir.NoDotAndDotDot | QDir.AllDirs) self._model.setRootPath('') self.setModel(self._model ) self.hideColumn(1); # removing Size Column self.hideColumn(2); # removing Type Column self.setAnimated(False) self.setSortingEnabled(True) self.header().setSortIndicator(0, Qt.AscendingOrder) width = self.size().width() >> 1 self.setColumnWidth(0, width*0.7) self.setColumnWidth(1, width*0.3) index = self._model.index(QDir.currentPath()) self.selectionModel().setCurrentIndex(index, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.expand(index) self.scrollTo(index) @property def selectedDir(self): return self._model.filePath(self.selectionModel().selectedIndexes()[0])