예제 #1
1
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')]
예제 #2
0
class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 file system view - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.initUI()

    def tree_cilcked(self, Qmodelidx):
        print(self.model.filePath(Qmodelidx))
        print(self.model.fileName(Qmodelidx))
        print(self.model.fileInfo(Qmodelidx))

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        # 这里得到目录结构
        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        # 这里过滤,只显示 py 文件
        mf = self.model.setNameFilters(['*.py'])
        self.model.setNameFilterDisables(False)
        # 这里做展示
        self.tree = QTreeView()
        self.tree.setModel(self.model)
        # self.tree.setRootIndex(self.model.index(QDir.currentPath()))
        self.tree.setRootIndex(self.model.index('g:\l'))
        self.tree.doubleClicked.connect(self.tree_cilcked)
        # 这里隐藏了目录信息展示
        for i in [1, 2, 3]:
            self.tree.setColumnHidden(i, True)
        # 缩进
        self.tree.setIndentation(10)
        self.tree.setWindowTitle("Dir View")
        self.tree.resize(640, 480)
        windowLayout = QVBoxLayout()
        windowLayout.addWidget(self.tree)
        self.setLayout(windowLayout)
        self.show()
예제 #3
0
class Explorer(QWidget):
    def __init__(self, rootdir=QDir.rootPath()):
        QWidget.__init__(self)
        self.treeview = QTreeView()
        self.listview = QListView()
        self.path = rootdir
        self.filename = ''
        self.filepath = rootdir
        self.canvas = None
        self.col_selector = None

        self.header = ''
        self.xcol = [1]
        self.ycol = [1]
        self.ncols = 0

        self.dirModel = QFileSystemModel()
        self.dirModel.setRootPath(self.path)
        self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)

        self.fileModel = QFileSystemModel()
        self.fileModel.setRootPath(self.filepath)
        self.fileModel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
        self.fileModel.setNameFilters(['*.txt'])
        self.fileModel.setNameFilterDisables(0)

        self.treeview.setModel(self.dirModel)
        self.listview.setModel(self.fileModel)
        for i in [1, 2, 3]: self.treeview.setColumnHidden(i, True)
        self.treeview.setHeaderHidden(True)

        self.treeview.setRootIndex(self.dirModel.index(self.path))
        self.listview.setRootIndex(self.fileModel.index(self.path))

        self.treeview.clicked.connect(self.on_clicked)
        self.listview.selectionModel().currentChanged.connect(self.file_selected)
        self.listview.selectionModel().currentChanged.connect(lambda: self.canvas.update_plot(self))
        self.listview.selectionModel().currentChanged.connect(lambda: self.col_selector.update_range(self.ncols))

    def on_clicked(self, index):
        self.path = self.dirModel.fileInfo(index).absoluteFilePath()
        self.listview.setRootIndex(self.fileModel.setRootPath(self.path))

    def file_selected(self, index):
        self.filename = self.fileModel.fileName(index)
        self.filepath = self.fileModel.filePath(index)
        self.load_file()

    def load_file(self):
        try:
            if self.filepath.endswith('.txt'):
                with open(self.filepath, 'r') as file:
                        self.header, self.xcol, self.ycol = '', [], []
                        for ln in file:
                            if ln.startswith('#'):
                                self.header += ln[2:]
                            else:
                                cols = ln.split('\t')
                                self.xcol.append(float(cols[0]))
                                self.ycol.append(float(cols[self.col_selector.sp.value()]))
                        self.ncols = len(cols)
                        self.col_selector.update_range(self.ncols)
        except:
            self.header, self.xcol, self.ycol = '', [0], [0]

    def update_rootdir(self, rootdir):
        self.path = rootdir
        self.treeview.setRootIndex(self.dirModel.index(self.path))
        self.listview.setRootIndex(self.fileModel.index(self.path))
예제 #4
0
class OperacaoLogistica(QDialog):
    #TODO: Acertar formatação na listagem de items por SIMAFIC
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowMinMaxButtonsHint
                            | Qt.WindowCloseButtonHint)
        self.setWindowTitle('Operação Logística')
        self.setMinimumSize(QSize(h_size, v_size))
        self.setWindowIcon(QIcon(main_icon))

        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)

        #Pedido Input Field
        self.proxy_list_result_id = QSortFilterProxyModel()
        self.numero_pedido = QLineEdit(self)
        self.numero_pedido.setPlaceholderText("Insira o Número do Pedido")
        self.numero_pedido.textChanged.connect(
            lambda wildcard: self.proxy_list_result_id.setFilterWildcard(
                wildcard))

        #Voltar Btn
        self.voltar_btn = QPushButton(self)
        #self.voltar_btn.setStyleSheet('background-color: rgb(0,0,255); color: #fff')
        self.voltar_btn.setText('Voltar')
        self.voltar_btn.clicked.connect(self.goMainWindow)
        self.close()

        #Adicionar Cores no StyleSheet
        colors = ['##393318', '  ##fff']
        self.pedidos = services.get_all_pedidos()
        self.item_result = None
        self.item_escolhido = None

        self.id_pedido_list = QListView()
        self.simafics_do_id = QListWidget()
        #self.simafics_do_id.setHidden(True)
        self.createPedidoIdList()

        self.id_pedido_list.clicked.connect(
            lambda id_pedido: self.createListaSimafics(id_pedido))
        self.simafics_do_id.itemDoubleClicked.connect(
            lambda pedido: self.simaficSelecionado(pedido))

        self.pedidos_label = QLabel()
        self.pedidos_label.setBuddy(self.id_pedido_list)
        self.simafic_label = QLabel()
        self.simafic_label.setBuddy(self.simafics_do_id)

        self.itensTree = PedidoItensTree()
        self.treeItensTV = QTreeView()
        self.treeItensTV.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.treeItensTV.setAlternatingRowColors(True)
        self.treeItensTV.setRootIsDecorated(True)
        self.treeItensTV.doubleClicked.connect(self.simaficSelecionado)
        self.treeItensTV.setColumnHidden(8, True)

        if len(self.pedidos) <= 0:
            self.pedidos_label.setText(
                "É necessário adicionar um pedido na tela de cadastro.")
            self.pedidos_label.setStyleSheet("QLabel { color: red; }")
        else:
            self.pedidos_label.setText("Listagem de Pedidos:")
            self.pedidos_label.setStyleSheet("QLabel { color: black; }")
            self.simafic_label.setText(
                "Selecione um pedido para ver a listagem de Itens por SIMAFIC:"
            )
            self.simafic_label.setStyleSheet("QLabel { color: red; }")

        layout = QGridLayout()
        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 4)
        layout.addWidget(self.numero_pedido, 0, 0)
        layout.addWidget(self.voltar_btn, 0, 1)
        layout.addWidget(self.pedidos_label, 1, 0)
        layout.addWidget(self.simafic_label, 1, 1)
        layout.addWidget(self.id_pedido_list, 2, 0)
        layout.addWidget(self.treeItensTV, 2, 1)
        #layout.addWidget(self.simafics_do_id, 2,1)
        self.setLayout(layout)

    def createPedidoIdList(self):
        print('def createPedidoIdList(self):')
        onlyids = set()
        pedidosbyid = []
        pedidosCompletos = []
        self.proxy_list_result_id = QSortFilterProxyModel()
        for obj in self.pedidos:
            if obj.id_pedido not in onlyids:
                pedidosbyid.append(obj)
                onlyids.add(obj.id_pedido)

        self.pedidoId_model = QStringListModel(onlyids, self)
        self.proxy_list_result_id.setSourceModel(self.pedidoId_model)
        self.id_pedido_list.setModel(self.proxy_list_result_id)
        self.id_pedido_list.setAlternatingRowColors(True)
        self.id_pedido_list.setEditTriggers(QAbstractItemView.NoEditTriggers)

    def createListaSimafics(self, id_pedido):

        pedido = id_pedido.data()
        self.pedidosModel = self.itensTree.createPedidosModel(self.itensTree)
        self.treeItensTV.setModel(self.pedidosModel)
        print('def listaSimafics(self, id_pedido): {id_pedido}'.format(
            id_pedido=pedido))
        self.item_result = None
        self.item_result = [x for x in self.pedidos if x.id_pedido == pedido]
        self.simafics_do_id.clear()
        self.pedidosModel.beginResetModel
        self.pedidosModel.modelReset
        self.pedidosModel.endResetModel

        for idx, item in enumerate(self.item_result):
            print(item)
            self.itensTree.addItens(
                self.pedidosModel, item.cod_simafic, item.desc,
                item.qty_scanneada, item.qty_total, item.nome_responsavel,
                item.id_caixa, item.time_updated.strftime("%d/%m/%y %H:%M:%S"),
                item.id_pedido, item)

        self.simafic_label.setText(
            "Listagem de Itens do pedido {} por SIMAFIC:".format(pedido))
        self.simafic_label.setStyleSheet("QLabel { color: black; }")

        #self.simafics_do_id.setHidden(False)

    def simaficSelecionado(self, item):
        print(item.column(), item.row())
        simafic_escolhido = self.treeItensTV.model().index(item.row(),
                                                           0).data()
        id_pedido = self.treeItensTV.model().index(item.row(), 7).data()
        self.item_escolhido = [
            x for x in self.item_result
            if x.cod_simafic == simafic_escolhido and x.id_pedido == id_pedido
        ]
        self.cams = ItemScanner(self.item_escolhido[0])
        self.cams.show()
        self.close()

    def goMainWindow(self):
        self.cams = mainView
        self.cams.show()
        self.close()

    def goScan(self):
        self.cams = ItemScanner("Eu sou o Pedido", "Eu sou o Simafic",
                                "Eu sou a Descrição", "300")
        self.cams.show()
        self.close()
예제 #5
0
파일: navigation.py 프로젝트: lheido/Mojuru
class Navigation(QWidget):
    """
    Navigation class definition.
    
    Provide a combobox to switch on each opened directories and display it into
    a tree view
    
    Provide 2 useful function (to use in alter module):
      - add_action(name, shortcut, callback)
         - callback take 2 arguments : file_info and parent
      - add_separator()
    
    """
    
    SETTINGS_DIRECTORIES = 'navigation_dirs'
    SETTINGS_CURRENT_DIR = 'navigation_current_dir'
    
    onFileItemActivated = pyqtSignal(QFileInfo, name="onFileItemActivated")
    onDirItemActivated = pyqtSignal(QFileInfo, name="onDirItemActivated")
    
    def __init__(self, parent=None):
        super(Navigation, self).__init__(parent)
        self.setObjectName("Navigation")
        
        self.layout = QVBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0,0,0,0)
        
        self.menu_button = QPushButton('Select directory', self)
        self.menu_button.setFlat(True)
#        self.menu_button.clicked.connect(self.on_menu_button_clicked)
        self.menu = QMenu(self)
        self.menu_button.setMenu(self.menu)
        self.menu_directories = QMenu(self)
        self.menu_directories.setTitle('Directories')
        self.menu_add_action(
            'Open directory', self.open_directory, None, QKeySequence.Open)
        self.menu_add_separator()
        self.menu_add_action('Refresh', self.reset, None, QKeySequence.Refresh)
        # @TODO invoke_all
        self.menu_add_separator()
        self.menu.addMenu(self.menu_directories)
        
        self.tree = QTreeView(self)
        self.model = FileSystemModel(self)
        self.tree.setModel(self.model)
        self.tree.setColumnHidden(1, True)
        self.tree.setColumnHidden(2, True)
        self.tree.setColumnHidden(3, True)
        self.tree.setHeaderHidden(True)
        # only to expand directory or activated with one click
        self.tree.clicked.connect(self.on_item_clicked)
        # else, for file use activated signal
        self.tree.activated.connect(self.on_item_activated)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.on_context_menu)
        
        self.widgets = collections.OrderedDict()
        self.widgets['menu_button'] = self.menu_button
        self.widgets['tree'] = self.tree
        
        # @ToDo: Alter.invoke_all('add_widget', self.widgets)
        
        for name, widget in self.widgets.items():
            if name == 'menu_button':
                self.layout.addWidget(widget, 0, Qt.AlignLeft)
            else:
                self.layout.addWidget(widget)
        
        self.context_menu = QMenu(self)
        self.add_action('New file', QKeySequence.New, 
                        FileSystemHelper.new_file)
        self.add_action('New Directory', '', 
                        FileSystemHelper.new_directory)
        self.add_separator()
        self.add_action('Rename', '', FileSystemHelper.rename)
        self.add_action('Copy', QKeySequence.Copy, FileSystemHelper.copy)
        self.add_action('Cut', QKeySequence.Cut, FileSystemHelper.cut)
        self.add_action('Paste', QKeySequence.Paste, FileSystemHelper.paste)
        self.add_separator()
        self.add_action('Delete', QKeySequence.Delete, 
                        FileSystemHelper.delete)
        
        # @ToDo Alter.invoke_all('navigation_add_action', self)
        
        #restore previous session and data
        dirs = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_DIRECTORIES, None, True)
        for directory_path in dirs:
            name = os.path.basename(directory_path)
            self.menu_add_directory(name, directory_path)
        current_dir = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_CURRENT_DIR, '')
        if current_dir:
            for action in self.menu_directories.actions():
                if action.data() == current_dir:
                    action.trigger()
        
        self.menu_button.setFocusPolicy(Qt.NoFocus)
        self.menu_button.setFocusProxy(self.tree)
    
    def reset(self, file_info):
        self.model.beginResetModel()
        current_dir = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_CURRENT_DIR, '')
        if current_dir:
            for action in self.menu_directories.actions():
                if action.data() == current_dir:
                    action.trigger()
    
    def on_menu_button_clicked(self):
        pos = self.mapToGlobal(self.menu_button.pos())
        menu_width = self.menu.sizeHint().width()
        pos.setY(pos.y() + self.menu_button.height())
#        pos.setX(pos.x() + self.menu_button.width() - menu_width)
        if len(self.menu.actions()) > 0:
            self.menu.exec(pos)
    
    def menu_add_action(self, name, callback, data=None, shortcut=None, icon=None):
        action = QAction(name, self)
        if icon:
            action.setIcon(icon)
        if shortcut:
            action.setShortcut(shortcut)
            action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        if data:
            action.setData(data)
        action.triggered.connect(callback)
        self.addAction(action)
        self.menu.addAction(action)
    
    def menu_add_directory(self, name, data):
        action = QAction(name, self)
        action.setData(data)
        action.triggered.connect(self.on_menu_action_triggered)
        self.menu_directories.addAction(action)
        return action
    
    def menu_add_separator(self):
        self.menu.addSeparator()
    
    def add_action(self, name, shortcut, callback, icon = None):
        """
        Ajoute une action au context menu et au widget navigation lui même.
        Créer une fonction à la volé pour fournir des arguments aux fonctions
        associé aux actions.
        """
        action = QAction(name, self)
        if icon:
            action.setIcon(icon)
        action.setShortcut(shortcut)
        action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        action.triggered.connect(self.__wrapper(callback))
        self.addAction(action)
        self.context_menu.addAction(action)
    
    def add_separator(self):
        """Simple abstraction of self.context_menu.addSeparator()"""
        self.context_menu.addSeparator()
    
    def __wrapper(self, callback):
        def __new_function():
            """
            __new_function représente la forme de tous les callbacks connecté
            à une action pour pouvoir utiliser les raccourcis en même temps que
            le menu contextuel.
            """
            action = self.sender()
            file_info = action.data()
            if not file_info:
                indexes = self.tree.selectedIndexes()
                if indexes:
                    model_index = indexes[0]
                    file_info = self.model.fileInfo(model_index)
                    callback(file_info, self)
                elif action.shortcut() == QKeySequence.New:
                    file_info = self.model.fileInfo(self.tree.rootIndex())
                    callback(file_info, self)
            else:
                callback(file_info, self)
                action.setData(None)
        return __new_function
    
    def question(self, text, informative_text = None):
        message_box = QMessageBox(self)
        message_box.setText(text)
        if informative_text:
            message_box.setInformativeText(informative_text)
        message_box.setStandardButtons(
            QMessageBox.No | QMessageBox.Yes)
        message_box.setDefaultButton(QMessageBox.No)
        return message_box.exec()
    
    def on_context_menu(self, point):
        model_index = self.tree.indexAt(point)
        file_info = self.model.fileInfo(model_index)
        # pour chaque action on met a jour les data (file_info)
        # puis on altère les actions (ex enabled)
        for action in self.context_menu.actions():
            if not action.isSeparator():
                action.setData(file_info)
                action.setEnabled(model_index.isValid())
                if action.shortcut() == QKeySequence.New:
                    action.setEnabled(True)
                    if not model_index.isValid():
                        file_info = self.model.fileInfo(self.tree.rootIndex())
                        action.setData(file_info)
                if action.shortcut() == QKeySequence.Paste:
                    enable = FileSystemHelper.ready() and model_index.isValid()
                    action.setEnabled(enable)
                if action.shortcut() == QKeySequence.Delete:
                    # remove directory only if is an empty directory
                    if model_index.isValid() and file_info.isDir():
                        path = file_info.absoluteFilePath()
                        # QDir(path).count() always contains '.' and '..'
                        action.setEnabled(QDir(path).count() == 2)
                # @ToDo 
                #Alter.invoke_all(
                #    'navigation_on_menu_action', 
                #    model_index, file_info, action, self)
        if len(self.context_menu.actions()) > 0:
            self.context_menu.exec(self.tree.mapToGlobal(point))
        # reset action data, sinon y a des problèmes dans _new_function
        for action in self.context_menu.actions():
            action.setData(None)
    
    def on_item_activated(self, index):
        qFileInfo = self.model.fileInfo(index)
        if qFileInfo.isDir():
            self.onDirItemActivated.emit(qFileInfo)
        else:
            self.onFileItemActivated.emit(qFileInfo)
    
    def on_item_clicked(self, index):
        qFileInfo = self.model.fileInfo(index)
        if qFileInfo.isDir():
            self.onDirItemActivated.emit(qFileInfo)
            self.tree.setExpanded(index, not self.tree.isExpanded(index))
        else:
            self.onFileItemActivated.emit(qFileInfo)
    
    def open_directory(self):
        project = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_CURRENT_DIR, '')
        path = QFileDialog.getExistingDirectory(self, "Open Directory", project)
        if path:
            name = os.path.basename(path)
            action = self.menu_add_directory(name, path)
            self.save_directories_path()
            action.trigger()
    
    def on_menu_action_triggered(self):
        action = self.sender()
        path = action.data()
        if path:
            self.model.setRootPath(path)
            self.tree.setRootIndex(self.model.index(path))
            self.menu_button.setText(os.path.basename(path))
            self.save_current_dir(path)
    
    def save_directories_path(self):
        ModuleManager.core['settings'].Settings.set_value(
            self.SETTINGS_DIRECTORIES,
            [action.data() for action in self.menu_directories.actions()]    
        )
    
    def save_current_dir(self, path):
        ModuleManager.core['settings'].Settings.set_value(
            self.SETTINGS_CURRENT_DIR,
            path
        )
예제 #6
0
class Watch(QWidget):
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)
        self.initUI()
        self.initVariables()

    def initUI(self):
        mainlayout = QFormLayout()
        self.model = CheckableDirModel()
        #self.model = QFileSystemModel()

        self.tree = QTreeView()
        self.tree.setModel(self.model)

        self.tree.setAnimated(False)
        self.tree.setIndentation(20)
        self.tree.setColumnHidden(1, True)
        self.tree.setColumnHidden(2, True)
        self.tree.setColumnHidden(3, True)
        self.tree.setSortingEnabled(False)
        self.tree.setHeaderHidden(True)
        self.model.updateCheckBoxSignal.connect(self.updateCheckBoxes)

        buttonLayout = QHBoxLayout()
        self.applyButton = QPushButton("Apply", self)
        self.applyButton.clicked.connect(self.apply)
        self.applyButton.setEnabled(False)
        self.resetButton = QPushButton("Reset", self)
        hspacer = QWidget()
        hspacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        buttonLayout.addWidget(hspacer)
        buttonLayout.addWidget(self.applyButton)
        buttonLayout.addWidget(self.resetButton)

        vspacer = QWidget()
        vspacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        # Add to layout
        mainlayout.addRow(self.tree)
        mainlayout.addRow(vspacer)
        mainlayout.addRow(buttonLayout)
        self.setLayout(mainlayout)

    def initVariables(self):
        settings = readSettingItems(['Watched'])
        if 'Watched' in settings.keys():
            if len(settings['Watched']):
                self.watchList = settings['Watched']
                if len(self.watchList):
                    for watchItem in self.watchList:
                        tempPath = watchItem[0]
                        tempIndex = self.model.index(tempPath, 0)
                        retData = self.model.filePath(tempIndex)
                        # Set checkbox
                        if len(retData):
                            self.model.setData(tempIndex, watchItem[1], Qt.CheckStateRole)
                            # Expand path
                            while tempIndex.parent().isValid():
                                tempIndex = tempIndex.parent()
                                self.tree.expand(tempIndex)

            else:
                self.watchList = []

    def updateCheckBoxes(self, index, value):
        changeFlag = False
        fullpath = self.model.filePath(index)
        newWatchMission = [fullpath, value]
        if newWatchMission in self.watchList:
            pass
        else:
            if len(self.watchList):
                tempList = list(filter(lambda x: fullpath in x, self.watchList))
                if len(tempList) == 1:
                    tempMissionIndex = self.watchList.index(tempList[0])
                    if value == 0:
                        self.watchList.pop(tempMissionIndex)
                    else:
                        self.watchList[tempMissionIndex] = newWatchMission
                elif len(tempList) == 0:
                    if value != 0:
                        self.watchList.append(newWatchMission)
                changeFlag = True
        self.applyButton.setEnabled(changeFlag)
        # to do: update checkboxes states: 0, 1, 2.

    def apply(self):
        data = {'Watched': self.watchList }
        writeSettingItems(data)
        self.applyButton.setEnabled(False)
예제 #7
0
파일: gui.py 프로젝트: solubrew/Pyffice
class mainWindow(QMainWindow):#											||
	def __init__(self):#												||
		QMainWindow.__init__(self)#										||
		pxcfg = here+'/gui.yaml'
		self.config = monk.stone(pxcfg).
		self.setAttribute(Qt.WA_DeleteOnClose)#							||
		self.setWindowTitle("Pyffice 0.0.0.0.0.0")#						||
		self.setStyleSheet(open(qss, "r").read())#						||
		self.setAutoFillBackground(True)#								||
		self.loadMenu()#												||
		self.setLayout()#												||
		self.loadApp()#													||
	def buildMenu():
		pass
	def desktopMenu(self, application, cfg=None):
		#dynamically build menu from config file
		dtmcfg = self.config['menu']
		for item in cfg.keys():
			self.menu = QMenu(dtmcfg[item]['name'], application)
	def loadMenu(self):#												||
		menu = self.desktopMenu(self)# this sends the desktop object (self) to the menu object
		for mu in menu.__dir__():#										||dynamically add
			obj = getattr(menu, mu)#									||menu items to the
			if isinstance(obj, QMenu):#									||layout
				self.menuBar().addMenu(obj)#							||
	def setLayout(self):#												||
		self.main_widget = QWidget(self)
		self.l = QHBoxLayout(self.main_widget)
#		tbar = docAddBar()
#		l.addWidget(tbar.toolbar)
	def loadApp(self):#													||
		''
		app = alpr.App()
		self.formulaBar()
		self.createLayout()
		self.l.addWidget(app)
		self.main_widget.setFocus()
		self.setCentralWidget(self.main_widget)
		windowLayout = QBoxLayout(QBoxLayout.LeftToRight)
		self.treeview.setFixedWidth=200
		windowLayout.addWidget(self.treeview)
		windowLayout.addWidget(self.tabwidget)
		self.setLayout(windowLayout)
		self.show()
		return self
		self.functionBar = QToolBar()
		self.addToolBar(self.functionBar)
		self.functionInput = QLineEdit()
		self.functionBar.addWidget(self.functionInput)
		self.formulaBar = QToolBar()
		self.addToolBar(self.formulaBar)
		self.formulaInput = QLineEdit()
		self.formulaBar.addWidget(self.formulaInput)
		self.statusBar().showMessage('Pyffice is about to Live')
	def fileQuit(self):
		self.close()
	def closeEvent(self, ce):
		self.fileQuit()

	def treeView(self,):
		self.treeview = QTreeView()
		self.treeview.setModel(model)

		self.treeview.setRootIndex(model.index(QDir.homePath()))

		self.treeview.setColumnWidth(0,50)
		self.treeview.setColumnHidden(1, True)
		self.treeview.setColumnHidden(2, True)
		self.treeview.setColumnHidden(3, True)
		self.treeview.setFixedWidth(200)
		self.treeview.setAnimated(False)
		self.treeview.setIndentation(20)
		self.treeview.setSortingEnabled(True)
		return self
	def setupContextMenu(self):
		'I believe this should setup the right click menu'
		self.addAction(self.cell_addAction)
		self.addAction(self.cell_subAction)
		self.addAction(self.cell_mulAction)
		self.addAction(self.cell_divAction)
		self.addAction(self.cell_sumAction)
		self.addAction(self.firstSeparator)
		self.addAction(self.colorAction)
		self.addAction(self.fontAction)
		self.addAction(self.secondSeparator)
		self.addAction(self.clearAction)
		self.setContextMenuPolicy(Qt.ActionsContextMenu)
		return self
	def formulaBar(self):
		return self
	def functionBar(self):
		return self
예제 #8
0
파일: main.py 프로젝트: ysglyl/yutools
class YuToolsNoteViewer(QWidget):

    def __init__(self):
        super(YuToolsNoteViewer, self).__init__()

        self.tv_notes = QTreeView(self)
        self.tv_notes.setGeometry(10, 40, 311, 630)
        self.tv_notes.setExpandsOnDoubleClick(False)
        self.tv_notes.clicked.connect(self.click_tv_item)
        self.tv_notes.doubleClicked.connect(self.doubleclick_tv_item)

        self.te_note = QTextEdit(self)
        font_default = QFont()
        font_default.setPointSize(12)
        self.te_note.setFont(font_default)
        self.te_note.setGeometry(330, 40, 451, 630)

        self.btn_add_root = QPushButton(self)
        self.btn_add_root.setText('Add Root')
        self.btn_add_root.setGeometry(10, 10, 75, 23)
        self.btn_add_root.clicked.connect(self.btn_click)

        self.btn_add_sub = QPushButton(self)
        self.btn_add_sub.setText('Add Sub')
        self.btn_add_sub.setDisabled(True)
        self.btn_add_sub.setGeometry(100, 10, 75, 23)
        self.btn_add_sub.clicked.connect(self.btn_click)

        self.btn_add_note = QPushButton(self)
        self.btn_add_note.setText('Add Note')
        self.btn_add_note.setDisabled(True)
        self.btn_add_note.setGeometry(190, 10, 75, 23)
        self.btn_add_note.clicked.connect(self.btn_click)

        self.rb_fonts_small = QRadioButton(self)
        self.rb_fonts_small.setText('Small')
        self.rb_fonts_small.setGeometry(350, 10, 60, 23)
        self.rb_fonts_small.clicked.connect(self.change_font_size)
        self.rb_fonts_normal = QRadioButton(self)
        self.rb_fonts_normal.setText('Normal')
        self.rb_fonts_normal.setGeometry(420, 10, 60, 23)
        self.rb_fonts_normal.clicked.connect(self.change_font_size)
        self.rb_fonts_normal.setChecked(True)
        self.rb_fonts_big = QRadioButton(self)
        self.rb_fonts_big.setText('Big')
        self.rb_fonts_big.setGeometry(490, 10, 60, 23)
        self.rb_fonts_big.clicked.connect(self.change_font_size)
        self.rb_fonts_bigger = QRadioButton(self)
        self.rb_fonts_bigger.setText('Bigger')
        self.rb_fonts_bigger.setGeometry(560, 10, 60, 23)
        self.rb_fonts_bigger.clicked.connect(self.change_font_size)
        self.rb_fonts_biggest = QRadioButton(self)
        self.rb_fonts_biggest.setText('Biggest')
        self.rb_fonts_biggest.setGeometry(630, 10, 60, 23)
        self.rb_fonts_biggest.clicked.connect(self.change_font_size)

        self.btn_save_note = QPushButton(self)
        self.btn_save_note.setText('Save')
        self.btn_save_note.setDisabled(True)
        self.btn_save_note.setGeometry(710, 10, 75, 23)
        self.btn_save_note.clicked.connect(self.btn_click)

        self.select_path = None

        self.init_tree()

    def init_tree(self):
        model = QFileSystemModel()
        path = os.path.dirname(os.path.realpath(__file__)) + os.path.sep + 'notes'
        model.setRootPath(path)
        self.tv_notes.setModel(model)
        self.tv_notes.setRootIndex(model.index(path))
        self.tv_notes.setHeaderHidden(True)
        self.tv_notes.resizeColumnToContents(0)
        self.tv_notes.setColumnHidden(1, True)
        self.tv_notes.setColumnHidden(2, True)
        self.tv_notes.setColumnHidden(3, True)

    def click_tv_item(self, index):
        is_dir = index.model().isDir(index)
        self.select_path = index.model().filePath(index)
        if is_dir:
            self.btn_add_sub.setDisabled(False)
            self.btn_add_note.setDisabled(False)
            self.btn_save_note.setDisabled(True)
            self.te_note.clear()
            self.te_note.setDisabled(True)
        else:
            self.te_note.clear()
            self.btn_add_sub.setDisabled(True)
            self.btn_add_note.setDisabled(True)
            self.btn_save_note.setDisabled(False)
            self.te_note.setDisabled(False)
            file = open(self.select_path, mode='r', encoding='utf-8')
            for line in file.readlines():
                self.te_note.append(line.strip('\n'))
            file.close()

    def doubleclick_tv_item(self, index):
        is_dir = index.model().isDir(index)
        self.select_path = index.model().filePath(index)
        path, ordinary_filename = os.path.split(self.select_path)
        file_name, success = QInputDialog.getText(self, "Title", "File Name:", QLineEdit.Normal,
                                                  ordinary_filename.split('.')[0])
        if success:
            if file_name.strip(' ') == '':
                return
            if is_dir:
                os.rename(self.select_path, path + os.path.sep + file_name.strip(' '))
            else:
                os.rename(self.select_path, path + os.path.sep + file_name.strip(' ') + '.txt')

    def btn_click(self):
        btn = self.sender()
        if btn == self.btn_save_note:
            content = self.te_note.toPlainText()
            lines = content.split('\n')
            file = open(self.select_path, mode='w+', encoding='utf-8')
            for line in lines:
                file.write(line + '\n')
            file.close()
        else:
            file_name, success = QInputDialog.getText(self, "Title", "File Name:", QLineEdit.Normal, '')
            if success:
                if file_name.strip(' ') == '':
                    return
                if btn == self.btn_add_root:
                    path = os.path.dirname(
                        os.path.realpath(__file__)) + os.path.sep + 'notes' + os.path.sep + file_name.strip(' ')
                    if not os.path.exists(path):
                        os.mkdir(path)
                elif btn == self.btn_add_sub:
                    path = self.select_path + os.path.sep + file_name.strip(' ')
                    if not os.path.exists(path):
                        os.mkdir(path)
                elif btn == self.btn_add_note:
                    path = self.select_path + os.path.sep + file_name.strip(' ') + '.txt'
                    if not os.path.exists(path):
                        open(path, mode='w', encoding='utf-8')

    def change_font_size(self):
        rb = self.sender()
        font = QFont()
        if rb == self.rb_fonts_small:
            font.setPointSize(10)
        elif rb == self.rb_fonts_normal:
            font.setPointSize(12)
        elif rb == self.rb_fonts_big:
            font.setPointSize(14)
        elif rb == self.rb_fonts_bigger:
            font.setPointSize(18)
        elif rb == self.rb_fonts_biggest:
            font.setPointSize(20)
        self.te_note.setFont(font)
예제 #9
0
        print('Directory') # Directory 출력
    else:
        path = model.filePath(index)
        label.setPixmap(QPixmap(path))

if __name__ == '__main__':
    app = QApplication(sys.argv)

    tree_view = QTreeView()
    tree_view.show()

    model = QFileSystemModel() # 파일 창 띄우기
    tree_view.setModel(model)

    root_path = "../" # 파일 경로
    model.setRootPath(root_path)
    tree_view.setRootIndex(model.index(root_path))
    tree_view.setColumnWidth(0, 400)
    tree_view.resize(700, 500)

    tree_view.setColumnHidden(1, True) # 두번째 컬럼 숨기기
    tree_view.setColumnHidden(2, True) # 세번째 컬럼 숨기기
    tree_view.setColumnHidden(3, True) # 네번째 컬럼 숨기기

    tree_view.doubleClicked.connect(double_click_event) # 트리 창 더블클릭하면 함수 double_click_event수행

    label = QLabel("label") # label 창 띄우기
    label.resize(600, 400) # label 창 크기 정하기
    label.show() # label 창 보여주기

    app.exec_()
예제 #10
0
class MainWindowClass(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.interface_lng_val = 'Russian'
        if self.interface_lng_val == 'Russian':
            self.setWindowTitle("Графический интерфейс программы OpenFOAM")
        elif self.interface_lng_val == 'English':
            self.setWindowTitle("OpenFOAM_decompose_GUI")

        # Базовые переменные
        self.full_dir = ''
        self.prj_name = ''
        self.con = ''
        self.lock_bool = False
        self.application = ''
        self.object_edit_txt = ''

        # ---------------------------Панель управления подготовкой задачи МСС----------------------------- #

        self.proj_open = QAction(self)
        self.proj_open.setEnabled(True)
        proj_ico = self.style().standardIcon(QStyle.SP_ArrowUp)
        self.proj_open.setIcon(proj_ico)
        if self.interface_lng_val == 'Russian':
            self.proj_open.setToolTip('Открыть проект')
        elif self.interface_lng_val == 'English':
            self.proj_open.setToolTip('Open the project')

        self.lng_chs = QAction(self)
        self.lng_chs.setEnabled(True)
        lng_chs_ico = self.style().standardIcon(
            QStyle.SP_FileDialogDetailedView)
        self.lng_chs.setIcon(lng_chs_ico)
        if self.interface_lng_val == 'Russian':
            self.lng_chs.setToolTip('Выбрать язык интерфейса программы')
        elif self.interface_lng_val == 'English':
            self.lng_chs.setToolTip('Select the interface language')

        self.file_open = QAction(self)
        self.file_open.setEnabled(False)
        file_open_ico = self.style().standardIcon(QStyle.SP_FileIcon)
        self.file_open.setIcon(file_open_ico)
        if self.interface_lng_val == 'Russian':
            self.file_open.setToolTip(
                'Открыть форму создания служебного файла для директории 0')
        elif self.interface_lng_val == 'English':
            self.file_open.setToolTip(
                'Open the form for creating the service file for the directory 0'
            )

        self.toolBar_1 = QToolBar("MyToolBar")
        self.toolBar_1.addAction(self.proj_open)
        self.toolBar_1.addAction(self.lng_chs)
        self.toolBar_1.addAction(self.file_open)

        self.proj_open.triggered.connect(
            lambda: first_toolbar_functions_class.on_proj_open(self))
        self.lng_chs.triggered.connect(
            lambda: first_toolbar_functions_class.on_lng_chs(self))
        self.file_open.triggered.connect(
            lambda: first_toolbar_functions_class.on_0_files_window_chs(self))

        self.addToolBar(self.toolBar_1)

        ###----------------------Панель управления подготовкой РС--------------------------###

        self.msh_open = QAction(self)
        self.msh_open.setEnabled(False)
        msh_ico = self.style().standardIcon(QStyle.SP_FileDialogNewFolder)
        self.msh_open.setIcon(msh_ico)
        if self.interface_lng_val == 'Russian':
            self.msh_open.setToolTip('Открыть форму выбора расчетной сетки')
        elif self.interface_lng_val == 'English':
            self.msh_open.setToolTip('Open the mesh selection form')

        self.msh_run = QAction(self)
        self.msh_run.setEnabled(False)
        msh_ico = self.style().standardIcon(QStyle.SP_ArrowRight)
        self.msh_run.setIcon(msh_ico)
        if self.interface_lng_val == 'Russian':
            self.msh_run.setToolTip('Выполнить генерацию расчетной сетки')
        elif self.interface_lng_val == 'English':
            self.msh_run.setToolTip('Make the mesh generation')

        self.msh_visual = QAction(self)
        self.msh_visual.setEnabled(False)
        msh_visual_ico = self.style().standardIcon(QStyle.SP_MediaSeekForward)
        self.msh_visual.setIcon(msh_visual_ico)
        if self.interface_lng_val == 'Russian':
            self.msh_visual.setToolTip(
                'Выполнить визуализацию расчетной сетки')
        elif self.interface_lng_val == 'English':
            self.msh_visual.setToolTip('Make the mesh visualization')

        self.toolBar_2 = QToolBar()
        self.toolBar_2.addAction(self.msh_open)
        self.toolBar_2.addAction(self.msh_run)
        self.toolBar_2.addAction(self.msh_visual)

        self.msh_open.triggered.connect(
            lambda: second_toolbar_functions_class.on_msh_open(self))
        self.msh_run.triggered.connect(
            lambda: second_toolbar_functions_class.on_msh_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.msh_visual.triggered.connect(
            lambda: second_toolbar_functions_class.on_visual_msh_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.addToolBar(self.toolBar_2)
        self.insertToolBarBreak(self.toolBar_2)

        ###----------------------Панель управления решением задачи МСС--------------------------###

        self.solv_run = QAction(self)
        self.solv_run.setEnabled(False)
        solv_run_ico = self.style().standardIcon(QStyle.SP_DialogNoButton)
        self.solv_run.setIcon(solv_run_ico)
        if self.interface_lng_val == 'Russian':
            self.solv_run.setToolTip('Выполнить решение')
        elif self.interface_lng_val == 'English':
            self.solv_run.setToolTip('Run solution')

        self.solv_stop = QAction(self)
        self.solv_stop.setEnabled(False)
        close_ico = self.style().standardIcon(QStyle.SP_DockWidgetCloseButton)
        self.solv_stop.setIcon(close_ico)
        if self.interface_lng_val == 'Russian':
            self.solv_stop.setToolTip('Остановить процесс решения')
        elif self.interface_lng_val == 'English':
            self.solv_stop.setToolTip('Stop the solution process')

        self.solv_run_vis = QAction(self)
        self.solv_run_vis.setEnabled(False)
        solv_run_vis_ico = self.style().standardIcon(QStyle.SP_CommandLink)
        self.solv_run_vis.setIcon(solv_run_vis_ico)
        if self.interface_lng_val == 'Russian':
            self.solv_run_vis.setToolTip(
                'Выполнить визуализацию результатов решения')
        elif self.interface_lng_val == 'English':
            self.solv_run_vis.setToolTip('Visualize the solution results')

        self.toolBar_3 = QToolBar()
        self.toolBar_3.addAction(self.solv_run)
        self.toolBar_3.addAction(self.solv_stop)
        self.toolBar_3.addAction(self.solv_run_vis)

        self.solv_run.triggered.connect(
            lambda: second_toolbar_functions_class.on_solv_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.solv_stop.triggered.connect(
            lambda: second_toolbar_functions_class.on_solv_stop(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.solv_run_vis.triggered.connect(
            lambda: second_toolbar_functions_class.on_solv_vis(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.addToolBar(self.toolBar_3)
        self.insertToolBarBreak(self.toolBar_3)

        ###----------------Верхний виджет с полным путем до файла сетки----------------###

        self.tdw = QDockWidget()
        self.tdw.setFixedSize(1400, 65)
        self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures)
        self.tdw_grid = QGridLayout()
        self.tdw_grid.setColumnStretch(2, 1)
        self.tdw_frame = QFrame()
        self.tdw_frame.setStyleSheet("background-color: ghostwhite;"
                                     "border-width: 0.5px;"
                                     "border-style: solid;"
                                     "border-color: silver;")
        self.tdw_frame.setLayout(self.tdw_grid)
        self.tdw.setWidget(self.tdw_frame)
        self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.tdw)

        ###-----------------Левый виджет с файловой системой проекта---------------------###

        self.fsw = QDockWidget()
        self.fsw.setFeatures(self.fsw.NoDockWidgetFeatures)
        self.fsw_label = QLabel()
        self.fsw_label.setAlignment(QtCore.Qt.AlignCenter)
        self.fsw_grid = QGridLayout()
        self.fsw_grid.addWidget(self.fsw_label, 0, 0)
        self.fsw_frame = QFrame()
        self.fsw_frame.setFixedSize(200, 35)
        self.fsw_frame.setStyleSheet("background-color: honeydew;"
                                     "border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;")
        self.fsw_frame.setLayout(self.fsw_grid)

        if self.interface_lng_val == 'Russian':
            fs_lbl = "Файловая Cтруктура Проекта"
        elif self.interface_lng_val == 'English':
            fs_lbl = "File Structure of the Project"

        self.fsw_label.setText("<font color='SeaGreen'>" + fs_lbl + "</font>")
        self.fsw_label.setStyleSheet("border-style: none;" "font-size: 10pt;")
        self.fsw.setTitleBarWidget(self.fsw_frame)
        self.treeview = QTreeView()
        self.treeview.setFixedSize(200, 520)
        self.treeview.model = QtGui.QStandardItemModel()
        self.treeview.setModel(self.treeview.model)
        self.treeview.setColumnWidth(0, 100)
        self.treeview.setColumnHidden(1, True)
        self.treeview.setColumnHidden(2, True)
        self.treeview.setColumnHidden(3, True)
        self.treeview.header().hide()
        self.treeview.setItemsExpandable(False)
        self.treeview.clicked.connect(self.on_treeview_clicked)
        self.fsw.setWidget(self.treeview)

        ###-----------Правый виджет с формой вывода результатов генерации файлов-----------###

        self.cdw = QDockWidget()
        self.cdw.setFeatures(self.cdw.NoDockWidgetFeatures)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw)

        self.cdw_grid = QGridLayout()
        self.cdw_frame = QFrame()
        self.cdw_frame.setFixedSize(495, 35)
        self.cdw_frame.setStyleSheet("border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;"
                                     "background-color: honeydew;")
        self.cdw_frame.setLayout(self.cdw_grid)

        self.outf_lbl = QLabel()
        self.outf_lbl.setAlignment(QtCore.Qt.AlignCenter)
        self.outf_lbl.setStyleSheet("border-style: none;" "font-size: 9pt;")

        self.cdw_grid.addWidget(self.outf_lbl, 0, 0)

        self.outf_edit = QTextEdit()
        self.outf_scroll = QScrollArea()
        self.outf_scroll.setWidgetResizable(True)
        self.outf_scroll.setWidget(self.outf_edit)
        self.outf_scroll.setFixedSize(495, 520)

        ###-----------------Центральный виджет с формой параметров---------------------###

        self.ffw = QDockWidget()
        self.ffw.setFeatures(self.ffw.NoDockWidgetFeatures)
        self.ffw_label = QLabel()
        self.ffw_label.setAlignment(QtCore.Qt.AlignCenter)
        self.ffw_grid = QGridLayout()
        self.ffw_grid.addWidget(self.ffw_label, 0, 0)
        self.ffw_frame = QFrame()
        self.ffw_frame.setFixedSize(693, 44)
        self.ffw_frame.setStyleSheet("border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;"
                                     "background-color: honeydew;")
        self.ffw_frame.setLayout(self.ffw_grid)

        ###------------------Нижний виджет со служебными сообщениями------------------###

        if self.interface_lng_val == 'Russian':
            self.serv_mes = QDockWidget("Служебные сообщения")
        elif self.interface_lng_val == 'English':
            self.serv_mes = QDockWidget("Service messages")

        self.serv_mes.setFixedSize(1400, 160)
        self.serv_mes.setFeatures(self.serv_mes.NoDockWidgetFeatures)
        self.listWidget = QListWidget()
        self.serv_mes.setWidget(self.listWidget)

    ###---------------------Функции, связанные с работой главного окна------------------------###

    # ...........................Функция клика по файлу из дерева.........................

    ###........................Функция открытия окна выбора интерфейса программы...................###

    # ...........................Функция клика по файлу из дерева.........................

    def on_treeview_clicked(self, index):
        global fileName
        indexItem = self.treeview.model.index(index.row(), 0, index.parent())
        self.lock_bool = True
        self.file_name = self.treeview.model.itemFromIndex(indexItem).text()
        file_form_class.inp_file_form_func(self, self.file_name, self.con)
        file_name_title = file_form_class.out_file_name_func()
        self.clear_label = QLabel()
        if file_name_title != None:
            if file_name_title != 'md':
                #self.cdw.setWidget(self.clear_label)
                #self.cdw.setTitleBarWidget

                if os.path.exists(self.full_dir + '/system/' +
                                  file_name_title):
                    outf = open(self.full_dir + '/system/' + file_name_title)
                    data = outf.read()
                    self.outf_edit.setText(data)
                    outf.close()
                elif os.path.exists(self.full_dir + '/constant/' +
                                    file_name_title):
                    outf = open(self.full_dir + '/constant/' + file_name_title)
                    data = outf.read()
                    self.outf_edit.setText(data)
                    outf.close()
                elif os.path.exists(self.full_dir + '/0/' + file_name_title):
                    outf = open(self.full_dir + '/0/' + file_name_title)
                    data = outf.read()
                    self.outf_edit.setText(data)
                    outf.close()

                self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw)

                self.cdw.setWidget(self.outf_scroll)

                #data = outf.read()

                if self.interface_lng_val == 'Russian':
                    self.outf_lbl.setText("Файл " + "<font color='peru'>" +
                                          file_name_title + "</font>")
                elif self.interface_lng_val == 'English':
                    self.outf_lbl.setText("<font color='peru'>" +
                                          file_name_title + "</font>" +
                                          " file")
                #self.outf_edit.setText(data)

                self.cdw.setTitleBarWidget(self.cdw_frame)
                #outf.close()

                self.setCentralWidget(self.ffw)
                file_form = file_form_class.out_file_form_func()
                self.ffw.setWidget(file_form)
                self.ffw.setTitleBarWidget(self.ffw_frame)

                if self.interface_lng_val == 'Russian':
                    self.ffw_label.setText("Форма параметров файла: " +
                                           "<font color='peru'>" +
                                           file_name_title + "</font>")
                elif self.interface_lng_val == 'English':
                    self.ffw_label.setText("<font color='peru'>" +
                                           file_name_title + "</font>" +
                                           " file parameters form")
                self.ffw_label.setStyleSheet("border-style: none;"
                                             "font-size: 9pt;")

            elif file_name_title == 'md':
                if self.interface_lng_val == 'Russian':
                    msg_lbl = QLabel(
                        '<span style="color:blue">Для создания расчетной сетки воспользуйтесь панелью инструментов</span>'
                    )
                elif self.interface_lng_val == 'English':
                    msg_lbl = QLabel(
                        '<span style="color:blue">To create a mesh use the toolbar.</span>'
                    )

                self.listWidget.clear()
                self.item = QListWidgetItem()
                self.listWidget.addItem(self.item)
                self.listWidget.setItemWidget(self.item, msg_lbl)

        else:

            self.ffw.setTitleBarWidget(self.clear_label)
            self.ffw.setWidget(self.clear_label)
            self.cdw.setWidget(self.clear_label)
            self.cdw.setTitleBarWidget(self.clear_label)

    # .........................Функция получения языка интерфейса..........................

    def on_lng_get(self, interface_lng):
        global interface_lng_val

        self.interface_lng_val = interface_lng

        if self.interface_lng_val == 'Russian':
            self.setWindowTitle("Графический интерфейс программы OpenFOAM")
            self.proj_open.setToolTip('Открыть проект')
            self.msh_run.setToolTip('Выполнить генерацию расчетной сетки')
            self.msh_visual.setToolTip(
                'Выполнить визуализацию расчетной сетки')
            self.lng_chs.setToolTip('Выбрать язык интерфейса программы')
            self.file_open.setToolTip(
                'Открыть форму создания служебного файла для директории 0')
            self.msh_open.setToolTip('Открыть форму выбора расчетной сетки')
            self.solv_run.setToolTip('Выполнить решение')
            self.solv_stop.setToolTip('Остановить процесс решения')
            self.solv_run_vis.setToolTip(
                'Выполнить визуализацию результатов решения')

        elif self.interface_lng_val == 'English':
            self.setWindowTitle("OpenFOAM_decompose_GUI")
            self.proj_open.setToolTip('Open the project')
            self.msh_run.setToolTip('Run mesh generation')
            self.msh_visual.setToolTip('Run mesh visualization')
            self.lng_chs.setToolTip(
                'Select the interface language for the program')
            self.file_open.setToolTip(
                'Open the form for creating the service file for the directory 0'
            )
            self.msh_open.setToolTip('Open the mesh selection form')
            self.solv_run.setToolTip('Run solution')
            self.solv_stop.setToolTip('Stop the solution process')
            self.solv_run_vis.setToolTip('Visualize the solution results')

    # .........................Функция получения пути до директории..........................

    def on_prj_path_get(self, prj_path, mesh_name_txt):
        global prj_path_val
        global mesh_name_txt_val
        global pp_dir

        prj_path_val = prj_path
        mesh_name_txt_val = mesh_name_txt

        pp_dir, pp_sys = os.path.split(prj_path_val)

    # .............................Функция получения типа сетки..............................

    def on_mesh_type_get(self, pd_2):
        global msh_type
        msh_type = pd_2
예제 #11
0
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()
예제 #12
0
파일: main.py 프로젝트: wychurry/dbclient
    def __init__(self):
        # self.tbl_info_model = QStandardItemModel()
        # self.tbl_info_model.setItem(self.DB_NAME_INDEX, QStandardItem())
        # self.tbl_info_model.setItem(self.TBL_NAME_INDEX, QStandardItem())
        # self.model = MysqlModel(host='zhongdian.hanson365.com', user='******', password='******')
        self.model = MysqlModel(host='127.0.0.1',
                                user='******',
                                password='******')
        super(QWidget, self).__init__()
        hbox = QHBoxLayout()

        operate_space_layout = QVBoxLayout()
        operate_space_layout.addWidget(QTextEdit())

        data_view_space = QTableView()
        data_view_space.setModel(self.model.data_model)

        self.filter_editor = QLineEdit()
        self.filter_editor.setMinimumHeight(40)
        filter_apply_btn = QPushButton("apply")
        filter_apply_btn.setMinimumHeight(40)
        filter_apply_btn.clicked.connect(partial(self.filter_click))

        filter_layout = QHBoxLayout()
        filter_layout.addWidget(self.filter_editor)
        filter_layout.addWidget(filter_apply_btn)

        # tbl_name_label = QLabel()
        # tbl_name_label
        tbl_info_tab_layout = QGridLayout()

        data_view_tab_layout = QVBoxLayout()
        data_view_tab_layout.addLayout(filter_layout)
        data_view_tab_layout.addWidget(data_view_space)

        query_splitter = QSplitter()
        query_splitter.addWidget(QTextEdit())
        query_splitter.addWidget(QTableView())
        query_view_tab_layout = QHBoxLayout()
        query_view_tab_layout.addWidget(query_splitter)

        tbl_info_tab = QWidget()
        data_view_tab = QWidget()
        query_view_tab = QWidget()
        query_view_tab.setLayout(query_view_tab_layout)

        tbl_info_tab.setLayout(tbl_info_tab_layout)
        data_view_tab.setLayout(data_view_tab_layout)

        self.operate_tab = QTabWidget()
        self.operate_tab.addTab(tbl_info_tab, 'INFO')
        self.operate_tab.addTab(data_view_tab, 'DATA')
        self.operate_tab.addTab(query_view_tab, 'QUERY')

        nav_space = QTreeView()
        nav_space.setColumnHidden(0, True)
        nav_space.setHeaderHidden(True)
        nav_space.setModel(self.model.schema_model)
        nav_space.clicked.connect(self.show_click)

        splitter = QSplitter()
        splitter.addWidget(nav_space)
        splitter.addWidget(self.operate_tab)
        splitter.setStretchFactor(1, 1)
        splitter.setSizes([250, 550])
        hbox.addWidget(splitter)
        hbox.setContentsMargins(0, 0, 0, 0)
        self.setLayout(hbox)
        self.clipboard = QGuiApplication.clipboard()
        self.clipboard.changed.connect(self.show_clipboard)
        self.setStyleSheet('''
            # QHeaderView::section {
            #     background-color:#333;
            #     color: white;
            #     border:none;
            #     border-left: 1px solid #aaa;
            #     border-bottom: 1px solid #aaa;
            # }
            # QTreeView{
            #     color: #fff;
            #     border:none;
            #     background-color: #333;
            # }
            # QTableView{
            #     border:none;
            #     color: #fff;
            #     background-color: #333;
            # }
        ''')
예제 #13
0
class RedditScraperWindow(QWidget):
    """The main window of the program."""

    ########### Setup ##################################
    def __init__(self):
        super().__init__()

        self.read_user_config()
        self.load_assets()
        self.initialize_ui()

    def load_assets(self):
        script_folder = os.path.dirname(
            os.path.dirname(os.path.abspath(__file__)))
        asset_folder = os.path.join(script_folder, "assets")
        if os.path.isdir(asset_folder):
            self.download_icon = QIcon(
                os.path.join(asset_folder, 'download_icon.png'))
            self.stop_icon = QIcon(os.path.join(asset_folder, 'stop_icon.png'))
            self.reddit_icon = QIcon(
                os.path.join(asset_folder, 'reddit_icon.png'))
        else:
            self.download_icon = QIcon(
                os.path.join("assets", 'download_icon.png'))
            self.stop_icon = QIcon(os.path.join("assets", 'stop_icon.png'))
            self.reddit_icon = QIcon(os.path.join("assets", 'reddit_icon.png'))

    def initialize_ui(self):
        """sets up the user interface, connects all the signals and shows the window. """

        self.init_components()
        self.read_settings_config()
        self.connect_signals()

        self.setGeometry(100, 100, 1000, 800)
        self.setWindowTitle('Reddit Image Scraper')
        self.setWindowIcon(self.reddit_icon)

        self.show()

    def init_components(self):
        """initializes all components and sets up the layout"""
        internalWidgetInput = QWidget()
        internalWidgetTree = QWidget()

        ############ define components ####################
        self.subredditInput = QComboBox()
        self.subredditInput.setEditable(True)
        self.subredditInput.addItems(self.get_downloaded_subreddits())

        self.numInput = QLineEdit()
        self.onlyInt = QIntValidator()
        self.numInput.setValidator(self.onlyInt)
        subredditLabel = QLabel('subreddit')
        numLabel = QLabel('number of images')
        self.dirLabel = QLabel('choose a directory')
        scale_label = QLabel("Scale images?")
        self.imgView = QLabel()

        self.outputText = QTextEdit('')
        self.outputText.setReadOnly(True)

        self.scale_cb = QCheckBox()

        self.sortingCb = QComboBox()
        self.sortingCb.addItems([
            "Hot", "Top all time", "Top this month", "Top past year", "New",
            "Controversial"
        ])
        sortingLabel = QLabel('sorting method')
        self.runButton = QPushButton('Download')
        self.runButton.setIcon(self.download_icon)
        self.chooseDirButton = QPushButton('Save dir')
        self.stopButton = QPushButton('Stop')
        self.stopButton.setIcon(self.stop_icon)

        self.fileModel = QFileSystemModel()
        self.tree = QTreeView()

        self.tree.setModel(self.fileModel)
        self.tree.setColumnHidden(1, True)
        self.tree.setColumnHidden(2, True)
        self.tree.setColumnHidden(3, True)

        ############## Menu stuff ###################
        menu_bar = QMenuBar()
        file_menu = menu_bar.addMenu('File')
        help_menu = menu_bar.addMenu('Help')

        self.exit_action = QAction('Exit', self)

        file_menu.addAction(self.exit_action)
        self.help_action = QAction('Help', self)
        help_menu.addAction(self.help_action)
        menu_bar.setFixedHeight(30)

        ############# Setup the grid layout###############################
        grid = QGridLayout()
        # grid.addWidget(menu_bar, 1, 0, 1, 4)
        grid.setSpacing(4)
        grid.addWidget(subredditLabel, 1, 0)
        grid.addWidget(self.subredditInput, 1, 1)
        grid.addWidget(numLabel, 2, 0)
        grid.addWidget(self.numInput, 2, 1)
        grid.addWidget(sortingLabel, 3, 0)
        grid.addWidget(self.sortingCb, 3, 1)

        grid.addWidget(self.chooseDirButton, 4, 0)
        grid.addWidget(self.dirLabel, 4, 1)
        grid.addWidget(self.stopButton, 5, 0)
        grid.addWidget(self.runButton, 5, 1)
        grid.addWidget(self.outputText, 7, 0, 7, 2)
        # grid.addWidget(self.tree,1,2, 11,7)

        grid.addWidget(scale_label, 6, 0)
        grid.addWidget(self.scale_cb, 6, 1)

        hboxTree = QVBoxLayout()
        hboxTree.addWidget(self.tree)

        #the image viewer, setting how it behaves under resizing.
        self.imgView.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.imgView.setMaximumHeight(MAX_IMAGE_HEIGHT)

        self.imgView.setAlignment(Qt.AlignmentFlag.AlignCenter)

        img_scroll_area = QScrollArea()
        img_scroll_area.setMinimumHeight(MAX_IMAGE_HEIGHT)
        img_scroll_area.setMinimumWidth(MAX_IMAGE_HEIGHT)
        img_scroll_area.setWidget(self.imgView)

        internalWidgetInput.setLayout(grid)
        # internalWidgetInput.setMinimumWidth(300)
        internalWidgetInput.setFixedWidth(300)
        internalWidgetInput.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding))

        internalWidgetTree.setLayout(hboxTree)
        internalWidgetTree.setFixedWidth(360)
        internalWidgetTree.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding))

        #construct layout of main window.
        hbox = QHBoxLayout()
        hbox.setSpacing(0)
        hbox.setContentsMargins(0, 0, 0, 0)
        hbox.setMenuBar(menu_bar)
        hbox.addWidget(internalWidgetInput)
        hbox.addWidget(internalWidgetTree)
        hbox.addWidget(img_scroll_area)
        self.setLayout(hbox)

    def connect_signals(self):
        """connects all the signals to the right functions"""
        self.chooseDirButton.clicked.connect(self.show_dir_dialog)
        self.runButton.clicked.connect(self.run_download_threaded)
        self.tree.clicked.connect(self.on_treeView_clicked)
        self.stopButton.clicked.connect(self.stop_download)
        self.scale_cb.clicked.connect(self.refresh_image)
        self.exit_action.triggered.connect(exit)

        #self.edit_login_action.triggered.connect(self.edit_login_info)
        self.help_action.triggered.connect(self.show_help)

        self.tree.selectionModel().selectionChanged.connect(
            self.on_selection_change)

    def read_user_config(self):
        """reads in the users username and password from the config file, or if there is no config file,
        shows an input dialog.
        Also tests so that only valid login information gets saved to the config file. """
        config = configparser.ConfigParser()
        self.redditScraper = redditScraper()
        if os.path.exists('redditScraper.ini'):
            config.read('redditScraper.ini')

            if 'DIR' in config:
                self.folder = config['DIR']['root_folder']

        else:
            config['REDDIT'] = {
                'subreddit': "wallpapers",
                'num': 10,
                'sorting': "Hot",
                'downloaded_subreddits': ""
            }

            with open('redditScraper.ini', 'w') as configfile:
                config.write(configfile)

        self.config = config

    def read_settings_config(self):
        """reads the saved settings from the config file, if they're there."""
        if 'DIR' in self.config:
            self.folder = self.config['DIR']['root_folder']
            idx = self.fileModel.setRootPath(str(self.folder))
            self.tree.setRootIndex(idx)
            self.dirLabel.setText(self.folder)

        if 'REDDIT' in self.config:
            self.subredditInput.setCurrentText(
                self.config['REDDIT']['subreddit'])
            self.numInput.setText(self.config['REDDIT']['num'])
            self.sortingCb.setCurrentText(self.config['REDDIT']['sorting'])

    ################### Actions: ##################
    @pyqtSlot(QModelIndex)
    def on_treeView_clicked(self, index):
        """triggers when the user clicks on a file item shown in the treeView, and shows that file in the picture viewer."""
        index = self.fileModel.index(index.row(), 0, index.parent())
        self.show_image(index)

    def on_selection_change(self, selected: QItemSelection,
                            deselected: QItemSelection):
        """ Triggers when the selected item in the treeview changes, and updates the shown picture. """
        self.refresh_image()

    def refresh_image(self):
        selected_image_index = self.tree.selectedIndexes()[0]
        self.show_image(selected_image_index)

    def show_image(self, index: QModelIndex):
        filePath = self.fileModel.filePath(index)
        if os.path.isfile(filePath) and filePath.split(".")[-1] in [
                "jpg", "gif", "png", "jpeg"
        ]:
            pixmap = QPixmap(filePath)
            if self.scale_cb.isChecked():
                self.imgView.setFixedHeight(MAX_IMAGE_HEIGHT)
                scaled_img = pixmap.scaledToHeight(MAX_IMAGE_HEIGHT)
                self.imgView.setFixedWidth(scaled_img.width())
                self.imgView.setPixmap(scaled_img)
            else:
                self.imgView.setFixedHeight(pixmap.height())
                self.imgView.setFixedWidth(pixmap.width())
                self.imgView.setPixmap(pixmap)

    def show_dir_dialog(self):
        """lets the user select the root folder, and saves the choice to the config file."""

        self.folder = QFileDialog.getExistingDirectory(
            self, 'Choose base directory', '/home')
        self.dirLabel.setText(self.folder)

        self.config['DIR'] = {'root_folder': self.folder}
        with open('redditScraper.ini', 'w') as configfile:
            self.config.write(configfile)

        idx = self.fileModel.setRootPath(self.folder)
        self.tree.setRootIndex(idx)

        return self.folder

    @pyqtSlot(str)
    def update_output_text(self, message: str):
        """updates the output text area, to show progress on downloads."""
        self.outputText.setText(message + self.outputText.toPlainText())

    def save_subreddit(self, subreddit: str, num: int, sorting: str):
        """helper function to save the current settings to the config file."""
        downloaded_subreddits = self.get_downloaded_subreddits()
        if subreddit not in downloaded_subreddits:
            downloaded_subreddits.append(subreddit)
            self.subredditInput.addItem(subreddit)

        downloaded_subreddits = ','.join(downloaded_subreddits)
        self.config['REDDIT'] = {
            'subreddit': subreddit,
            'num': str(num),
            'sorting': sorting,
            'downloaded_subreddits': downloaded_subreddits
        }

        with open('redditScraper.ini', 'w') as configfile:
            self.config.write(configfile)

    def get_downloaded_subreddits(self) -> list:
        if 'downloaded_subreddits' in self.config['REDDIT'].keys():
            subreddits = self.config['REDDIT']['downloaded_subreddits'].split(
                ',')
            return subreddits
        return []

    def run_download_threaded(self):
        """downloads the pictures. Runs in a QThread, so that the program does not freeze.
        Also checks whether the specified subreddit exists. """
        subreddit = self.subredditInput.currentText()
        num = int(self.numInput.text())
        sorting = self.sortingCb.currentText()

        if self.redditScraper.sub_exists(subreddit):

            if not hasattr(self, "folder"):
                msgBox = QMessageBox()
                msgBox.setText('You need to set a download folder!')
                msgBox.setWindowTitle("Pick a download folder")
                msgBox.exec_()
                return

            self.save_subreddit(subreddit, num, sorting)
            self.get_thread = RedditDownloadThread(
                self.redditScraper, subreddit, num,
                num * LOOKUP_LIMIT_MULTIPLIER, sorting, self.folder)
            self.get_thread.changeText.connect(self.update_output_text)
            self.get_thread.start()
        else:
            msgBox = QMessageBox()
            msgBox.setText('That subreddit does not exist, please try again')
            msgBox.setWindowTitle("Invalid subreddit")
            msgBox.exec_()

        pass

    def stop_download(self):
        """Stops the download thread and prints a message to the output."""
        try:
            if self.get_thread.isRunning():
                self.get_thread.terminate()
                self.outputText.setText(self.outputText.toPlainText() +
                                        ' Aborted!\n')
        except Exception:
            pass

    ############### Menu actions: ###############

    def show_help(self):
        msgBox = QMessageBox()

        msgBox.setWindowIcon(self.reddit_icon)
        msgBox.setText(
            'This program downloads images posted to reddit.com, or more specifically, to subreddits'
            +
            '(i.e. sub-forums). To use it, one needs a valid reddit account, which one can sign up for '
            +
            'on reddit.com. One also needs to know some names of subreddits. \n Some suggestions for subreddits: '
            + 'wallpapers , earthporn , nature , and pics . \n \n ' +
            "This program will download up to the specified number of images. It can handle png, jpg and gif,"
            +
            "so links to gyf-files, videos or anything else will be ignored. Therefore the number of images actually "
            +
            "downloaded will usually be less than the specified number. So if you want a lot of images, just put"
            +
            " a large limit.\n The images will be placed in a subfolder of the chosen base folder, named after the subreddit. This folder will be created if it does not exist.\n \n "
            +
            "To view the images, click on them in the tree-view, and they will appear on the right"
        )
        msgBox.setWindowTitle("Help")
        msgBox.exec_()
예제 #14
0
    class App(QWidget):
        def __init__(self):
            super().__init__()
            self.left = 100
            self.top = 100
            self.width = 1200
            self.height = 720
            self.setWindowTitle('Mammogram Prediction')
            self.setGeometry(self.left, self.top, self.width, self.height)

            self.initUI()

        def initUI(self):
            # Widget for showing picture. The QLabel gets a Pixmap added to it to show picture
            self.picture_name_label = QLabel(currently_selected_picture)
            self.picture_label = QLabel()
            self.prediction_text = QTextEdit()
            self.prediction_text.setReadOnly(True)
            self.model_label = QLabel()

            self.init_picture_and_predictions()

            self.resized_picture = self.picture.scaled(299, 299,
                                                       Qt.KeepAspectRatio,
                                                       Qt.FastTransformation)
            self.picture_label.setPixmap(self.resized_picture)
            self.picture_label.setMinimumWidth(299)
            self.picture_label.setMinimumHeight(299)
            self.picture_label.setContentsMargins(0, 19, 0, 0)

            # Tree and List view for file directory overview of pictures
            self.picture_directory_label = QLabel('Select a Picture:')
            picture_dir_path = 'pictures\\'
            picture_file_path = 'pictures\\'
            self.treeview_picture = QTreeView()
            self.listview_picture = QListView()

            self.dirModel_picture = QFileSystemModel()
            self.dirModel_picture.setRootPath(picture_dir_path)
            self.dirModel_picture.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)

            self.fileModel_picture = QFileSystemModel()
            self.fileModel_picture.setRootPath(picture_file_path)  #
            self.fileModel_picture.setFilter(QDir.NoDotAndDotDot | QDir.Files)

            self.treeview_picture.setModel(self.dirModel_picture)
            self.listview_picture.setModel(self.fileModel_picture)

            self.treeview_picture.setRootIndex(
                self.dirModel_picture.index(picture_dir_path))
            self.listview_picture.setRootIndex(
                self.fileModel_picture.index(picture_file_path))  #
            self.treeview_picture.setCurrentIndex(
                self.dirModel_picture.index(0, 0))

            self.treeview_picture.clicked.connect(
                self.on_picture_treeview_clicked)
            self.listview_picture.clicked.connect(
                self.on_picture_listview_clicked)
            self.treeview_picture.setColumnHidden(1, True)
            self.treeview_picture.setColumnWidth(0, 275)
            self.treeview_picture.setMinimumWidth(500)
            self.listview_picture.setMinimumWidth(500)

            # List view for file directory overview of five label models
            self.model_directory_label = QLabel('Select a Five Label Model:')
            model_path = 'trained_five_Models\\'
            self.listview_model = QListView()
            self.dirModel_model = QFileSystemModel()

            self.dirModel_model.setRootPath(model_path)
            self.dirModel_model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)

            self.listview_model.setModel(self.dirModel_model)
            self.listview_model.setRootIndex(
                self.dirModel_model.index(model_path))
            self.listview_model.clicked.connect(self.on_model_listview_clicked)

            # List view for file directory overview of binary models
            self.model_binary_directory_label = QLabel(
                'Select a Binary Model:')
            model_binary_path = 'trained_binary_Models\\'
            self.listview_model_binary = QListView()
            self.dirModel_model_binary = QFileSystemModel()

            self.dirModel_model_binary.setRootPath(model_binary_path)
            self.dirModel_model_binary.setFilter(QDir.NoDotAndDotDot
                                                 | QDir.AllDirs)

            self.listview_model_binary.setModel(self.dirModel_model_binary)
            self.listview_model_binary.setRootIndex(
                self.dirModel_model_binary.index(model_binary_path))
            self.listview_model_binary.setSelectionMode(
                QAbstractItemView.MultiSelection)
            self.listview_model_binary.clicked.connect(
                self.on_model_binary_listview_clicked)

            # Layout handling.

            # self.gridlayout = QGridLayout()
            # self.gridlayout.addWidget(self.model_directory_label, 0, 0)
            # self.gridlayout.setColumnStretch(-15, -11)
            # self.gridlayout.addWidget(self.listview_model, 1, 0)
            # self.gridlayout.addWidget(self.picture_directory_label, 2, 0)
            # self.gridlayout.addWidget(self.treeview_picture, 3, 0)
            #
            # self.gridlayout.addWidget(self.model_binary_directory_label, 0, 1)
            # self.gridlayout.addWidget(self.listview_model_binary, 1, 1)
            # self.gridlayout.addWidget(self.listview_picture, 3, 1)
            #
            # self.gridlayout.addWidget(self.picture_label, 0, 2)
            # self.gridlayout.addWidget(self.picture_name_label, 1, 2)
            # self.gridlayout.addWidget(self.prediction_text, 3, 2)

            self.vbox = QVBoxLayout()
            self.vbox_left = QVBoxLayout()
            self.vbox_right = QVBoxLayout()
            self.hbox_outer = QHBoxLayout()
            self.hbox_top = QHBoxLayout()
            self.hbox_buttom = QHBoxLayout()
            self.vbox_five_label = QVBoxLayout()
            self.vbox_binary = QVBoxLayout()

            self.vbox.addLayout(self.hbox_outer)
            self.hbox_outer.addLayout(self.vbox_left)
            self.hbox_outer.addLayout(self.vbox_right)
            self.vbox_left.addLayout(self.hbox_top)
            self.hbox_top.addLayout(self.vbox_five_label)
            self.hbox_top.addLayout(self.vbox_binary)

            self.vbox_five_label.addWidget(self.model_directory_label)
            self.vbox_five_label.addWidget(self.listview_model)
            self.vbox_binary.addWidget(self.model_binary_directory_label)
            self.vbox_binary.addWidget(self.listview_model_binary)

            self.vbox_left.addWidget(self.picture_directory_label)
            self.vbox_left.addLayout(self.hbox_buttom)
            self.hbox_buttom.addWidget(self.treeview_picture)
            self.hbox_buttom.addWidget(self.listview_picture)

            self.vbox_right.addWidget(self.picture_label,
                                      alignment=Qt.AlignHCenter)
            self.vbox_right.addWidget(self.picture_name_label,
                                      alignment=Qt.AlignHCenter)
            self.vbox_right.addWidget(self.model_label,
                                      alignment=Qt.AlignHCenter)
            self.vbox_right.addWidget(self.prediction_text)

            self.vbox_right.setAlignment(Qt.AlignCenter)

            self.setLayout(self.vbox)
            self.sizePolicy = QSizePolicy(QSizePolicy.Minimum,
                                          QSizePolicy.Preferred)
            self.setSizePolicy(self.sizePolicy)
            self.show()

        def init_picture_and_predictions(self):
            if currently_selected_picture == 'Currently No Image Selected':
                self.picture = QtGui.QPixmap('GUI/no_image_selected.png')
                self.prediction_text.setText('')

        def on_picture_treeview_clicked(self, index):
            pathof_selected_dir = self.dirModel_picture.fileInfo(
                index).absoluteFilePath()
            self.listview_picture.setRootIndex(
                self.fileModel_picture.setRootPath(pathof_selected_dir))

        def on_picture_listview_clicked(self, index):
            global currently_selected_model
            global currently_selected_model_name
            global currently_selected_picture

            currently_selected_picture = self.fileModel_picture.fileInfo(
                index).absoluteFilePath()

            try:
                Image.open(currently_selected_picture)
                self.picture_name_label.setText(currently_selected_picture)
                self.picture_label.setPixmap(
                    QtGui.QPixmap(currently_selected_picture))
            except IOError:
                print('Exception: Chosen file is not a picture')

            # Checks if the selected picture has size 299
            image_in = cv2.imread(currently_selected_picture)
            size = image_in.shape[:2]
            if size[0] == 299:
                if currently_selected_model is not None:
                    for model in currently_selected_model:
                        new_prediction = self.makePrediction(
                            model,
                            self.convertPictureToNumpy(
                                currently_selected_picture))
                        split = currently_selected_model_name.split('_')
                        if split[4] in ('neg', 'bc', 'bm', 'mc', 'mm'):
                            self.show_binary_prediction(
                                new_prediction, split[4])
                        else:
                            self.show_five_prediction(new_prediction)
                else:
                    self.prediction_text.setText(
                        'No Model is Chosen for Prediction. Choose one to the left.'
                    )
            # If the selected picture is not size 299 it will be padded and cropped
            else:
                cropped_images = resize_image_padding(
                    currently_selected_picture)
                self.listview_picture.setRootIndex(
                    self.fileModel_picture.setRootPath('pictures/cropped/%s' %
                                                       cropped_images))

        def on_model_listview_clicked(self, index):
            global currently_selected_model
            global currently_selected_picture

            currently_selected_model = []

            selected_model_path = self.dirModel_model.fileInfo(
                index).absoluteFilePath()
            currently_selected_model.append(self.getModel(selected_model_path))

            self.model_label.setText(currently_selected_model_name[0])

            if currently_selected_picture != 'Currently No Image Selected':
                for model in currently_selected_model:
                    new_prediction = self.makePrediction(
                        model,
                        self.convertPictureToNumpy(currently_selected_picture))
                    self.show_five_prediction(new_prediction)

        def on_model_binary_listview_clicked(self):
            global currently_selected_model
            global currently_selected_picture
            currently_selected_model = []

            self.prediction_text.setText('')
            self.model_label.setText('')

            for x in self.listview_model_binary.selectedIndexes():
                selected_model_path = self.dirModel_model_binary.fileInfo(
                    x).absoluteFilePath()
                currently_selected_model.append(
                    self.getModel(selected_model_path))
            # if not currently_selected_model_name:
            #     self.model_label.setText(currently_selected_model_name)

            if currently_selected_picture != 'Currently No Image Selected':
                for y in currently_selected_model:
                    new_prediction = self.makePrediction(
                        y,
                        self.convertPictureToNumpy(currently_selected_picture))
                    self.show_binary_prediction(new_prediction, y.category)

        def getModel(self, model_path):
            global currently_selected_model_name
            currently_selected_model_name = []

            split = os.path.split(model_path)[1].split('_')
            model_version = split[0] + '_' + split[1] + '_' + split[
                2] + '_' + split[3]
            currently_selected_model_name.append(os.path.split(model_path)[1])

            model = getattr(sys.modules[__name__], model_version)()
            checkpoint_path = model_path + '/cp.ckpt'
            model.load_weights(checkpoint_path)
            return model

        def makePrediction(self, input_model, input_picture):
            image = tf.reshape(input_picture, [-1, 299, 299, 1])
            image = tf.cast(image, tf.float32)
            image = image / 255.0
            return input_model.predict(image)

        def convertPictureToNumpy(self, filename):
            img = Image.open(filename)
            np_array = np.array(img, dtype='uint8')
            return np_array

        def show_five_prediction(self, prediction):
            self.prediction_text.setText(
                "Probability of Negative: %s" % prediction[0, 0] +
                "\n\nProbability of Benign Calcification: %s" %
                prediction[0, 1] +
                "\n\nProbability of Benign Mass: %s" % prediction[0, 2] +
                "\n\nProbability of Malignant Calcification: %s" %
                prediction[0, 3] +
                "\n\nProbability of Malignant Mass: %s" % prediction[0, 4])

        def show_binary_prediction(self, prediction, category):
            if category == 'neg':
                self.prediction_text.append(
                    "Probability of Negative: %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))
            elif category == 'bc':
                self.prediction_text.append(
                    "Probability of Benign Calcification:  %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))
            elif category == 'bm':
                self.prediction_text.append(
                    "Probability of Benign Mass: %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))
            elif category == 'mc':
                self.prediction_text.append(
                    "Probability of Malignant Calcification: %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))
            elif category == 'mm':
                self.prediction_text.append(
                    "Probability of Malignant Mass: %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))
            else:
                self.prediction_text.append(
                    "Probability of ????: %s %s \n" %
                    (prediction[0, 0], prediction[0, 1]))

        def openFileDialog(self):
            fileName, _ = QFileDialog.getOpenFileName(
                self, "QFileDialog.getOpenFileName()", "",
                "All Files (*);;Python Files (*.py)")
            if fileName:
                return fileName

        def is_png(data):
            return data[:8] == '\x89PNG\x0d\x0a\x1a\x0a'
예제 #15
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(970, 650)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setHandleWidth(1)
        self.splitter.setObjectName("splitter")
        self.horizontalLayout.addWidget(self.splitter)
        MainWindow.setCentralWidget(self.centralwidget)

        # 文件树形目录浏览器
        self.tree = QTreeView()
        self.model = QtWidgets.QFileSystemModel()
        self.model.setRootPath('')
        self.nameFile = ["*.png", "*.jpg", "*.jpeg"]
        self.model.setNameFilterDisables(False)
        self.model.setNameFilters(self.nameFile)
        self.tree.setModel(self.model)
        self.tree.setAnimated(False)
        self.tree.setIndentation(20)
        self.tree.setWindowTitle("Dir View")
        self.tree.setSortingEnabled(True)
        self.tree.setColumnHidden(1, True)
        self.tree.setColumnHidden(2, True)
        self.tree.setColumnHidden(3, True)
        self.tree.doubleClicked.connect(self.openFileFromTreeList)
        # 图库管理器
        self.tree_2 = QTreeWidget()
        self.tree_2.setColumnCount(1)
        # 设置表头信息:隐藏表头
        self.tree_2.setHeaderHidden(1)
        # 设置root和root2为self.tree的子树,所以root和root2就是跟节点
        root = QTreeWidgetItem(self.tree_2)
        root2 = QTreeWidgetItem(self.tree_2)
        # 设置根节点的名称
        root.setText(0, '第一节点')
        root2.setText(0, '第二节点')
        # 为root节点设置子结点
        child1 = QTreeWidgetItem(root)
        child1.setText(0, 'child1')
        child1.setText(1, 'name1')
        child2 = QTreeWidgetItem(root)
        # 设置child2节点的图片
        child2.setText(0, 'child2')
        child2.setText(1, 'name2')

        # 实例化QToolBox
        self.toolBox = QToolBox()
        # 设置左侧导航栏 toolBox 在左右拉拽时的最小宽度
        self.toolBox.setMinimumWidth(100)
        # 给QToolBox添加两个子项目
        self.toolBox.addItem(self.tree, "文件资源")
        self.toolBox.addItem(self.tree_2, "图库")

        # 给QSplitter添加第一个窗体(QToolBox)
        self.splitter.addWidget(self.toolBox)

        #菜单栏
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(10, 10, 820, 30))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.menu1_file = QtWidgets.QMenu(self.menubar)
        self.menu1_file.setObjectName("menu1_file")
        self.menu2_edit = QtWidgets.QMenu(self.menubar)
        self.menu2_edit.setObjectName("menu2_edit")
        self.menu3_imageLib = QtWidgets.QMenu(self.menubar)
        self.menu3_imageLib.setObjectName("menu3_imageLib")
        self.menu4_image = QtWidgets.QMenu(self.menubar)
        self.menu4_image.setObjectName("menu4_image")
        self.menu6_user = QtWidgets.QMenu(self.menubar)
        self.menu6_user.setObjectName("menu6_user")
        self.menu5_help = QtWidgets.QMenu(self.menubar)
        self.menu5_help.setObjectName("menu5_help")
        MainWindow.setMenuBar(self.menubar)

        #menu Action
        #################action1######################
        self.action_1_1 = QtWidgets.QAction(MainWindow)
        self.action_1_1.setObjectName("action_1_1")  #打开
        self.action_1_1.triggered.connect(self.openfile)
        self.action_1_2 = QtWidgets.QAction(MainWindow)
        self.action_1_2.setObjectName("action_1_2")  #保存
        self.action_1_3 = QtWidgets.QAction(MainWindow)
        self.action_1_3.setObjectName("action_1_3")  #退出
        #################action2######################
        self.action_2_1 = QtWidgets.QAction(MainWindow)
        self.action_2_1.setObjectName("action_2_1")  #图片编辑
        self.action_2_1.triggered.connect(self.openChildWindow)
        #################action3######################
        self.action_3_1 = QtWidgets.QAction(MainWindow)
        self.action_3_1.setObjectName("action_3_1")  #图库管理器
        self.action_3_1.triggered.connect(self.imageLibUi)
        #################action4######################
        self.action_4_1 = QtWidgets.QAction(MainWindow)
        self.action_4_1.setObjectName("action_4_1")  # 添加图片
        self.action_4_2 = QtWidgets.QAction(MainWindow)
        self.action_4_2.setObjectName("action_4_2")  # 删除图片
        self.action_4_3 = QtWidgets.QAction(MainWindow)
        self.action_4_3.setObjectName("action_4_3")  # 重命名
        #################action5######################
        self.action_5 = QtWidgets.QAction(MainWindow)
        self.action_5.setObjectName("action_5")  #帮助
        #################action6######################
        self.action_6 = QtWidgets.QAction(MainWindow)
        self.action_6.setObjectName("action_6")  #用户管理
        self.action_6.triggered.connect(self.userManager)

        #给menu添加Action
        self.menu1_file.addAction(self.action_1_1)  #打开
        self.menu1_file.addAction(self.action_1_2)  #保存
        self.menu1_file.addAction(self.action_1_3)  #退出
        self.menu2_edit.addAction(self.action_2_1)  #图片编辑
        self.menu3_imageLib.addAction(self.action_3_1)  #图库管理器
        self.menu4_image.addAction(self.action_4_1)  #添加图片
        self.menu4_image.addAction(self.action_4_2)  #删除图片
        self.menu4_image.addAction(self.action_4_3)  #重命名
        self.menu6_user.addAction(self.action_6)  #用户管理
        self.menu5_help.addAction(self.action_5)  #帮助
        self.menubar.addAction(self.menu1_file.menuAction())
        self.menubar.addAction(self.menu2_edit.menuAction())
        self.menubar.addAction(self.menu3_imageLib.menuAction())
        self.menubar.addAction(self.menu4_image.menuAction())
        self.menubar.addAction(self.menu5_help.menuAction())
        self.menubar.addAction(self.menu6_user.menuAction())

        #Icon
        icon = QtGui.QIcon()
        icon2 = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("Icon/openfile.png"), QtGui.QIcon.Normal,
                       QtGui.QIcon.Off)
        icon2.addPixmap(QtGui.QPixmap("Icon/edit.png"), QtGui.QIcon.Normal,
                        QtGui.QIcon.Off)
        self.action_1_1.setIcon(icon)
        self.action_2_1.setIcon(icon2)

        #工具栏
        self.toolBar = QtWidgets.QToolBar(MainWindow)
        self.toolBar.setInputMethodHints(QtCore.Qt.ImhHiddenText
                                         | QtCore.Qt.ImhSensitiveData)
        self.toolBar.setObjectName("toolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.toolBar.addAction(self.action_1_1)
        self.toolBar.addAction(self.action_2_1)

        #状态栏
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        #初始化默认窗体
        #初始化默认窗体(图片显示窗体)
        self.imageView = ImageView()
        # 在主窗口里添加子窗口
        self.splitter.addWidget(self.imageView)

        #是普通用户还是管理员
        self

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        # 创建默认存放文件的文件夹:
        cur_dir = "C:"
        folder_name = 'InfraredImage'
        if os.path.isdir("C:/InfraredImage"):
            print("Already exist!")
        else:
            os.mkdir(os.path.join(cur_dir, folder_name))
            os.mkdir("C:/InfraredImage/TmpImg")

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "红外图像质量客观评价系统V1.0"))

        #导航栏名字
        self.menu1_file.setTitle(_translate("MainWindow", "文件"))
        self.menu3_imageLib.setTitle(_translate("MainWindow", "图库管理"))
        self.menu4_image.setTitle(_translate("MainWindow", "图片管理"))
        self.menu2_edit.setTitle(_translate("MainWindow", "编辑"))
        self.menu6_user.setTitle(_translate("MainWindow", "用户管理"))
        self.menu5_help.setTitle(_translate("MainWindow", "帮助"))

        #action名字
        self.action_1_1.setText(_translate("MainWindow", "打开"))
        self.action_1_1.setShortcut(_translate("MainWindow", "Ctrl+O"))
        self.action_1_2.setText(_translate("MainWindow", "保存"))
        self.action_1_2.setShortcut(_translate("MainWindow", "Ctrl+S"))
        self.action_1_3.setText(_translate("MainWindow", "退出"))
        self.action_1_3.setShortcut(_translate("MainWindow", "Ctrl+E"))
        self.action_2_1.setText(_translate("MainWindow", "编辑图片"))
        self.action_3_1.setText(_translate("MainWindow", "图库管理器"))
        self.action_4_1.setText(_translate("MainWindow", "添加图片"))
        self.action_4_2.setText(_translate("MainWindow", "删除图片"))
        self.action_4_3.setText(_translate("MainWindow", "重命名"))
        self.action_5.setText(_translate("MainWindow", "Help ?"))
        self.action_6.setText(_translate("MainWindow", "用户管理器"))

        self.statusbar.showMessage("Ready")

    ##########################功能函数区###############################

    def openfile(self):
        # 设置文件扩展名过滤,注意用双分号间隔
        fileName1, filetype = QFileDialog.getOpenFileName(
            None, "选取文件", "C:/", "All Files (*);;Image (*.png *.jpg *.jpeg)")
        #显示图片,并初始化图片基本信息
        self.openImage(fileName1)

    # 从文件资源目录树打开图片
    def openFileFromTreeList(self, Qmodelidx):
        filePath = self.model.filePath(Qmodelidx)
        self.openImage(filePath)

        # 打开图片,并初始化图片基本信息
    def openImage(self, filePath):
        self.action_2_1.setEnabled(True)
        self.splitter.widget(1).setParent(None)
        self.splitter.insertWidget(1, self.imageView)
        img = QtGui.QPixmap(filePath).scaled(
            self.imageView.graphicsView.width(),
            self.imageView.graphicsView.height())
        self.imageView.graphicsView.setPixmap(img)
        self.newPic = Image.open(filePath)
        self.statusbar.showMessage("打开图片")
        self.imageView.listWidget.item(1).setText("大小: " +
                                                  str(self.newPic.size))
        self.imageView.listWidget.item(2).setText("色彩通道: " + self.newPic.mode)
        self.imageView.listWidget.item(3).setText("格式: " + self.newPic.format)
        self.imageView.listWidget.item(4).setText(
            "像素: " + str(self.newPic.getextrema()))
        self.imageView.listWidget.item(5).setText("文件: " + str(filePath))
        # # 要把新打开的图片,和所有修改过的图片,都存进tempPic.jpg里面,作为一个中间变量。
        self.newPic.save("C:/InfraredImage/TmpImg/tempPic.png")
        self.newPic = "C:/InfraredImage/TmpImg/tempPic.png"

    # 打开图片处理子窗口函
    def openChildWindow(self):
        childUi = childWindow()
        if childUi.exec_() == QtWidgets.QDialog.Accepted:
            pass

    #打开图库管理窗口
    def imageLibUi(self):
        self.imageLibUi = ImageLibUi()
        # 把QSplitter的指定位置的窗体从QSplitter中剥离
        self.splitter.widget(1).setParent(None)
        # 在QSplitter的指定位置载入新窗体
        self.splitter.insertWidget(1, self.imageLibUi)
        # 打开图库管理窗口时将图片编辑器设为不可用
        self.action_2_1.setEnabled(False)

    #用户管理
    def userManager(self):
        self.userWindow = UserManagerUi()
        # 把QSplitter的指定位置的窗体从QSplitter中剥离
        self.splitter.widget(1).setParent(None)
        # 在QSplitter的指定位置载入新窗体
        self.splitter.insertWidget(1, self.userWindow)
        # 打开图库管理窗口时将图片编辑器设为不可用
        self.action_2_1.setEnabled(False)
예제 #16
0
class Navigation(QWidget):
    """
    Navigation class definition.
    
    Provide a combobox to switch on each opened directories and display it into
    a tree view
    
    Provide 2 useful function (to use in alter module):
      - add_action(name, shortcut, callback)
         - callback take 2 arguments : file_info and parent
      - add_separator()
    
    """

    SETTINGS_DIRECTORIES = 'navigation_dirs'
    SETTINGS_CURRENT_DIR = 'navigation_current_dir'

    onFileItemActivated = pyqtSignal(QFileInfo, name="onFileItemActivated")
    onDirItemActivated = pyqtSignal(QFileInfo, name="onDirItemActivated")

    def __init__(self, parent=None):
        super(Navigation, self).__init__(parent)
        self.setObjectName("Navigation")

        self.layout = QVBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        self.menu_button = QPushButton('Select directory', self)
        self.menu_button.setFlat(True)
        #        self.menu_button.clicked.connect(self.on_menu_button_clicked)
        self.menu = QMenu(self)
        self.menu_button.setMenu(self.menu)
        self.menu_directories = QMenu(self)
        self.menu_directories.setTitle('Directories')
        self.menu_add_action('Open directory', self.open_directory, None,
                             QKeySequence.Open)
        self.menu_add_separator()
        self.menu_add_action('Refresh', self.reset, None, QKeySequence.Refresh)
        # @TODO invoke_all
        self.menu_add_separator()
        self.menu.addMenu(self.menu_directories)

        self.tree = QTreeView(self)
        self.model = FileSystemModel(self)
        self.tree.setModel(self.model)
        self.tree.setColumnHidden(1, True)
        self.tree.setColumnHidden(2, True)
        self.tree.setColumnHidden(3, True)
        self.tree.setHeaderHidden(True)
        # only to expand directory or activated with one click
        self.tree.clicked.connect(self.on_item_clicked)
        # else, for file use activated signal
        self.tree.activated.connect(self.on_item_activated)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.on_context_menu)

        self.widgets = collections.OrderedDict()
        self.widgets['menu_button'] = self.menu_button
        self.widgets['tree'] = self.tree

        # @ToDo: Alter.invoke_all('add_widget', self.widgets)

        for name, widget in self.widgets.items():
            if name == 'menu_button':
                self.layout.addWidget(widget, 0, Qt.AlignLeft)
            else:
                self.layout.addWidget(widget)

        self.context_menu = QMenu(self)
        self.add_action('New file', QKeySequence.New,
                        FileSystemHelper.new_file)
        self.add_separator()
        self.add_action('Copy', QKeySequence.Copy, FileSystemHelper.copy)
        self.add_action('Cut', QKeySequence.Cut, FileSystemHelper.cut)
        self.add_action('Paste', QKeySequence.Paste, FileSystemHelper.paste)
        self.add_separator()
        self.add_action('Delete', QKeySequence.Delete, FileSystemHelper.delete)

        # @ToDo Alter.invoke_all('navigation_add_action', self)

        #restore previous session and data
        dirs = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_DIRECTORIES, None, True)
        for directory_path in dirs:
            name = os.path.basename(directory_path)
            self.menu_add_directory(name, directory_path)
        current_dir = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_CURRENT_DIR, '')
        if current_dir:
            for action in self.menu_directories.actions():
                if action.data() == current_dir:
                    action.trigger()

        self.menu_button.setFocusPolicy(Qt.NoFocus)
        self.menu_button.setFocusProxy(self.tree)

    def reset(self, file_info):
        self.model.beginResetModel()
        current_dir = ModuleManager.core['settings'].Settings.value(
            self.SETTINGS_CURRENT_DIR, '')
        if current_dir:
            for action in self.menu_directories.actions():
                if action.data() == current_dir:
                    action.trigger()

    def on_menu_button_clicked(self):
        pos = self.mapToGlobal(self.menu_button.pos())
        menu_width = self.menu.sizeHint().width()
        pos.setY(pos.y() + self.menu_button.height())
        #        pos.setX(pos.x() + self.menu_button.width() - menu_width)
        if len(self.menu.actions()) > 0:
            self.menu.exec(pos)

    def menu_add_action(self,
                        name,
                        callback,
                        data=None,
                        shortcut=None,
                        icon=None):
        action = QAction(name, self)
        if icon:
            action.setIcon(icon)
        if shortcut:
            action.setShortcut(shortcut)
            action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        if data:
            action.setData(data)
        action.triggered.connect(callback)
        self.addAction(action)
        self.menu.addAction(action)

    def menu_add_directory(self, name, data):
        action = QAction(name, self)
        action.setData(data)
        action.triggered.connect(self.on_menu_action_triggered)
        self.menu_directories.addAction(action)
        return action

    def menu_add_separator(self):
        self.menu.addSeparator()

    def add_action(self, name, shortcut, callback, icon=None):
        """
        Ajoute une action au context menu et au widget navigation lui même.
        Créer une fonction à la volé pour fournir des arguments aux fonctions
        associé aux actions.
        """
        action = QAction(name, self)
        if icon:
            action.setIcon(icon)
        action.setShortcut(shortcut)
        action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        action.triggered.connect(self.__wrapper(callback))
        self.addAction(action)
        self.context_menu.addAction(action)

    def add_separator(self):
        """Simple abstraction of self.context_menu.addSeparator()"""
        self.context_menu.addSeparator()

    def __wrapper(self, callback):
        def __new_function():
            """
            __new_function représente la forme de tous les callbacks connecté
            à une action pour pouvoir utiliser les raccourcis en même temps que
            le menu contextuel.
            """
            action = self.sender()
            file_info = action.data()
            if not file_info:
                indexes = self.tree.selectedIndexes()
                if indexes:
                    model_index = indexes[0]
                    file_info = self.model.fileInfo(model_index)
                    callback(file_info, self)
                elif action.shortcut() == QKeySequence.New:
                    file_info = self.model.fileInfo(self.tree.rootIndex())
                    callback(file_info, self)
            else:
                callback(file_info, self)
                action.setData(None)

        return __new_function

    def question(self, text, informative_text=None):
        message_box = QMessageBox(self)
        message_box.setText(text)
        if informative_text:
            message_box.setInformativeText(informative_text)
        message_box.setStandardButtons(QMessageBox.No | QMessageBox.Yes)
        message_box.setDefaultButton(QMessageBox.No)
        return message_box.exec()

    def on_context_menu(self, point):
        model_index = self.tree.indexAt(point)
        file_info = self.model.fileInfo(model_index)
        # pour chaque action on met a jour les data (file_info)
        # puis on altère les actions (ex enabled)
        for action in self.context_menu.actions():
            if not action.isSeparator():
                action.setData(file_info)
                action.setEnabled(model_index.isValid())
                if action.shortcut() == QKeySequence.New:
                    action.setEnabled(True)
                    if not model_index.isValid():
                        file_info = self.model.fileInfo(self.tree.rootIndex())
                        action.setData(file_info)
                if action.shortcut() == QKeySequence.Paste:
                    enable = FileSystemHelper.ready() and model_index.isValid()
                    action.setEnabled(enable)
                if action.shortcut() == QKeySequence.Delete:
                    # remove directory only if is an empty directory
                    if model_index.isValid() and file_info.isDir():
                        path = file_info.absoluteFilePath()
                        # QDir(path).count() always contains '.' and '..'
                        action.setEnabled(QDir(path).count() == 2)
                # @ToDo
                #Alter.invoke_all(
                #    'navigation_on_menu_action',
                #    model_index, file_info, action, self)
        if len(self.context_menu.actions()) > 0:
            self.context_menu.exec(self.tree.mapToGlobal(point))
        # reset action data, sinon y a des problèmes dans _new_function
        for action in self.context_menu.actions():
            action.setData(None)

    def on_item_activated(self, index):
        qFileInfo = self.model.fileInfo(index)
        if qFileInfo.isDir():
            self.onDirItemActivated.emit(qFileInfo)
        else:
            self.onFileItemActivated.emit(qFileInfo)

    def on_item_clicked(self, index):
        qFileInfo = self.model.fileInfo(index)
        if qFileInfo.isDir():
            self.onDirItemActivated.emit(qFileInfo)
            self.tree.setExpanded(index, not self.tree.isExpanded(index))
        else:
            self.onFileItemActivated.emit(qFileInfo)

    def open_directory(self):
        path = QFileDialog.getExistingDirectory(self, "Open Directory", ".")
        if path:
            name = os.path.basename(path)
            action = self.menu_add_directory(name, path)
            self.save_directories_path()
            action.trigger()

    def on_menu_action_triggered(self):
        action = self.sender()
        path = action.data()
        if path:
            self.model.setRootPath(path)
            self.tree.setRootIndex(self.model.index(path))
            self.menu_button.setText(os.path.basename(path))
            self.save_current_dir(path)

    def save_directories_path(self):
        ModuleManager.core['settings'].Settings.set_value(
            self.SETTINGS_DIRECTORIES,
            [action.data() for action in self.menu_directories.actions()])

    def save_current_dir(self, path):
        ModuleManager.core['settings'].Settings.set_value(
            self.SETTINGS_CURRENT_DIR, path)
class LogInspectorWindow(QMainWindow):
    def __init__(self, configFilePath, parent=None):
        super(LogInspectorWindow, self).__init__(parent)
        self.initMatPlotLib()
        self.configFilePath = configFilePath

        folder = os.path.dirname(self.configFilePath)
        if not os.path.exists(folder):
            os.makedirs(folder)

        if os.path.exists(self.configFilePath):
            # config.yaml found.  Read from file.
            file = open(self.configFilePath, 'r')
            self.config = yaml.safe_load(file)
            file.close()
        else:
            # config.yaml not found.  Create new file.
            self.config = {}
            self.config['logs_directory'] = os.path.join(
                os.path.expanduser("~"), "Documents", "Inertial_Sense", "Logs")
            self.config['directory'] = ""
            self.config['serials'] = ["ALL"]
            file = open(self.configFilePath, 'w')
            yaml.dump(self.config, file)
            file.close()

        self.currently_selected = 'posNEDMap'
        self.downsample = 5
        self.plotargs = None
        self.log = None
        self.plotter = None

    def initMatPlotLib(self):
        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.figure.subplots_adjust(left=0.05,
                                    right=0.99,
                                    bottom=0.05,
                                    top=0.91,
                                    wspace=0.2,
                                    hspace=0.2)

    def addButton(self, name, function, multithreaded=True, layout=None):
        setattr(self, name + "button", QPushButton(name))
        # if multithreaded:
        # setattr(self, name+"buttonThread", Thread(target=function))
        # getattr(self, name+"button").pressed.connect(self.startLoadingIndicator)
        # getattr(self, name+"button").released.connect(getattr(self, name+"buttonThread").start)
        # else:
        getattr(self, name + "button").clicked.connect(function)
        # getattr(self, name + "button").setMinimumWidth(220)
        if layout is None:
            if self.buttonLayoutRightCol.count(
            ) < self.buttonLayoutMiddleCol.count():
                self.buttonLayoutRightCol.addWidget(
                    getattr(self, name + "button"))
            elif self.buttonLayoutMiddleCol.count(
            ) < self.buttonLayoutLeftCol.count():
                self.buttonLayoutMiddleCol.addWidget(
                    getattr(self, name + "button"))
            else:
                self.buttonLayoutLeftCol.addWidget(
                    getattr(self, name + "button"))
        else:
            layout.addWidget(getattr(self, name + "button"))

    def updatePlot(self):
        self.plot(self.currently_selected, self.plotargs)

    def updateWindowTitle(self):
        if np.shape(self.log.data[0, DID_DEV_INFO])[0] != 0:
            info = self.log.data[0, DID_DEV_INFO][0]
            infoStr = 'SN' + str(info[1]) + ', H:' + verArrayToString(
                info[2]) + ', F:' + verArrayToString(
                    info[3]) + ' build ' + str(
                        info[4]) + ', ' + dateTimeArrayToString(
                            info[8], info[9]) + ', ' + info[10].decode('UTF-8')
            self.setWindowTitle("LogInspector  -  " + infoStr)

    def choose_directory(self):
        log_dir = config['logs_directory']
        directory = QFileDialog.getExistingDirectory(
            parent=self, caption='Choose Log Directory', directory=log_dir)

        if directory != '':
            try:
                self.load(directory)
            except Exception as e:
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Critical)
                msg.setText("Unable to load log: " + e.__str__())
                msg.setDetailedText(traceback.format_exc())
                msg.exec()

    def load(self, directory):
        print("loading files from " + directory)
        # if self.log is None:
        self.log = Log()
        self.log.load(directory)
        print("done loading")
        self.plotter = logPlot(False, False, 'svg', self.log)
        self.plotter.setDownSample(self.downsample)
        # str = ''
        # if self.log.navMode:
        #     str += 'NAV '
        # if self.log.rtk:
        #     str += 'RTK '
        # if self.log.compassing:
        #     str += 'Comp '
        # self.statusLabel.setText(str)
        self.updatePlot()
        self.updateWindowTitle()
        self.stopLoadingIndicator()

    def setupUi(self):
        self.setObjectName("LogInspector")
        self.setWindowTitle("LogInspector")
        self.resize(1280, 900)
        self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowSystemMenuHint
                            | QtCore.Qt.WindowMinMaxButtonsHint)
        self.setWindowIcon(QIcon("assets/Magnifying_glass_icon.png"))

        # MainWindow.showMaximized()

        self.createFileTree()
        self.createButtonColumn()
        self.formatButtonColumn()
        self.createBottomToolbar()

        self.figureLayout = QVBoxLayout()
        self.figureLayout.addWidget(self.canvas)
        self.figureLayout.addLayout(self.toolLayout)
        self.figureLayout.setStretchFactor(self.canvas, 1)

        layout = QHBoxLayout()
        layout.addLayout(self.controlLayout)
        layout.addLayout(self.figureLayout)
        layout.setStretch(1, 1)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        # self.resize(1280, 900)
        self.resize(1450, 1000)
        self.setAcceptDrops(True)

    def createButtonColumn(self):
        self.controlLayout = QVBoxLayout()
        self.buttonLayoutLeftCol = QVBoxLayout()
        self.buttonLayoutMiddleCol = QVBoxLayout()
        self.buttonLayoutRightCol = QVBoxLayout()
        self.addButton('Pos NED Map', lambda: self.plot('posNEDMap'))
        self.addButton('Pos NED', lambda: self.plot('posNED'))
        self.addButton('Pos LLA', lambda: self.plot('posLLA'))
        self.addButton('GPS LLA', lambda: self.plot('llaGps'))
        self.addButton('Vel NED', lambda: self.plot('velNED'))
        self.addButton('Vel UVW', lambda: self.plot('velUVW'))
        self.addButton('Attitude', lambda: self.plot('attitude'))
        self.addButton('Heading', lambda: self.plot('heading'))
        self.addButton('INS Status', lambda: self.plot('insStatus'))
        self.addButton('HDW Status', lambda: self.plot('hdwStatus'))
        self.addButton('GPS 1 Stats', lambda: self.plot('gpsStats'))
        self.addButton('GPS 2 Stats', lambda: self.plot('gps2Stats'))
        self.addButton('RTK Pos Stats', lambda: self.plot('rtkPosStats'))
        self.addButton('RTK Cmp Stats', lambda: self.plot('rtkCmpStats'))
        self.addButton('Flash Config', lambda: self.showFlashConfig())
        self.addButton('Device Info', lambda: self.showDeviceInfo())
        self.addButton('IMU PQR', lambda: self.plot('imuPQR'))
        self.addButton('IMU Accel', lambda: self.plot('imuAcc'))
        self.addButton('PSD PQR', lambda: self.plot('gyroPSD'))
        self.addButton('PSD Accel', lambda: self.plot('accelPSD'))
        self.addButton('Magnetometer', lambda: self.plot('magnetometer'))
        self.addButton('Temp', lambda: self.plot('temp'))

    def formatButtonColumn(self):
        self.buttonLayoutLeftCol.setAlignment(QtCore.Qt.AlignTop)
        self.buttonLayoutMiddleCol.setAlignment(QtCore.Qt.AlignTop)
        self.buttonLayoutRightCol.setAlignment(QtCore.Qt.AlignTop)
        self.buttonColumnLayout = QHBoxLayout()
        self.buttonColumnLayout.addLayout(self.buttonLayoutLeftCol)
        self.buttonColumnLayout.addLayout(self.buttonLayoutMiddleCol)
        self.buttonColumnLayout.addLayout(self.buttonLayoutRightCol)
        self.controlLayout.addLayout(self.buttonColumnLayout)
        self.controlDirLayout = QHBoxLayout()
        self.controlDirLayout.addWidget(self.dirLineEdit)
        self.controlLayout.addLayout(self.controlDirLayout)
        self.controlLayout.addWidget(self.fileTree)
        # self.buttonLayout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        # self.addButton('load', self.choose_directory, multithreaded=False)

    def createBottomToolbar(self):
        self.toolLayout = QHBoxLayout()
        self.toolLayout.addWidget(self.toolbar)

        self.loadingIndictator = QLabel()
        self.loadingMovie = QMovie('assets/loader.gif')
        self.emptyLoadingPicture = QPicture()
        self.emptyLoadingPicture.load('assets/empty_loader.png')
        self.stopLoadingIndicator()
        self.toolLayout.addWidget(self.loadingIndictator)

        self.toolLayout.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        # self.toolLayout.addWidget(QSpacerItem(150, 10, QSizePolicy.Expanding))

        self.copyImagePushButton = QPushButton()
        # self.copyImagePushButton.setText("Copy")
        # self.copyImagePushButton.setMinimumWidth(1)
        # self.copyImagePushButton.style().standardIcon(QStyle.SP_DialogOpenButton)
        self.copyImagePushButton.setIcon(self.style().standardIcon(
            QStyle.SP_DialogSaveButton))
        self.toolLayout.addWidget(self.copyImagePushButton)
        self.copyImagePushButton.clicked.connect(self.copyPlotToClipboard)

        downsampleLabel = QLabel()
        downsampleLabel.setText("DS")
        self.downSampleInput = QSpinBox()
        self.downSampleInput.setValue(self.downsample)
        self.toolLayout.addWidget(downsampleLabel)
        self.toolLayout.addWidget(self.downSampleInput)
        self.downSampleInput.valueChanged.connect(self.changeDownSample)

        self.statusLabel = QLabel()
        self.toolLayout.addWidget(self.statusLabel)

    def changeDownSample(self, val):
        self.downsample = val
        self.plotter.setDownSample(self.downsample)
        self.updatePlot()

    def copyPlotToClipboard(self):
        # pixmap = QPixmap.grabWidget(self.canvas)
        # QApplication.clipboard().setPixmap(pixmap)
        # pixmap.save('test.png')

        # store the image in a buffer using savefig(), this has the
        # advantage of applying all the default savefig parameters
        # such as background color; those would be ignored if you simply
        # grab the canvas using Qt
        buf = io.BytesIO()
        self.figure.savefig(buf)

        QApplication.clipboard().setImage(QImage.fromData(buf.getvalue()))
        buf.close()

    def startLoadingIndicator(self):
        self.loadingIndictator.setMovie(self.loadingMovie)
        self.loadingMovie.start()

    def dragEnterEvent(self, e):
        if (e.mimeData().hasUrls()):
            e.acceptProposedAction()

    def dropEvent(self, e):
        try:
            directory = e.mimeData().urls()[0].toLocalFile()
            self.load(directory)
        except Exception as e:
            self.showError(e)

    def showError(self, e):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)
        msg.setText("Unable to load log: " + e.__str__())
        msg.setDetailedText(traceback.format_exc())
        msg.exec()

    def createFileTree(self):
        self.dirModel = QFileSystemModel()
        self.dirModel.setRootPath(self.config["logs_directory"])
        self.dirModel.setFilter(QtCore.QDir.Dirs | QtCore.QDir.NoDotAndDotDot)
        self.dirLineEdit = QLineEdit()
        self.dirLineEdit.setText(self.config["logs_directory"])
        self.dirLineEdit.setFixedHeight(25)
        self.dirLineEdit.returnPressed.connect(self.handleTreeDirChange)
        self.fileTree = QTreeView()
        self.fileTree.setModel(self.dirModel)
        self.fileTree.setRootIndex(
            self.dirModel.index(self.config['logs_directory']))
        self.fileTree.setColumnHidden(1, True)
        self.fileTree.setColumnHidden(2, True)
        self.fileTree.setColumnHidden(3, True)
        self.fileTree.setMinimumWidth(300)
        self.fileTree.clicked.connect(self.handleTreeViewClick)
        self.fileTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection)
        self.fileTree.customContextMenuRequested.connect(
            self.handleTreeViewRightClick)
        # self.populateRMSCheck(self.config['logs_directory'])

    def updateFileTree(self):
        self.dirModel.setRootPath(self.config["logs_directory"])
        self.fileTree.setRootIndex(
            self.dirModel.index(self.config['logs_directory']))

    def populateRMSCheck(self, directory):
        for subdir in os.listdir(directory):
            path = os.path.join(directory, subdir)
            if os.path.isdir(path):
                self.populateRMSCheck(path)
            elif 'RMS' in subdir:
                f = open(path)
                rms_report = f.read()
                p = re.compile(r'(?<=^PASS/FAIL).*\n', re.M)
                line = re.search(p, rms_report).group()
                failed = True if "FAIL" in line else False
                if failed:
                    pass
                else:
                    pass

    def handleTreeDirChange(self):
        self.config["logs_directory"] = self.dirLineEdit.text()
        self.updateFileTree()

        file = open(self.configFilePath, 'w')
        yaml.dump(self.config, file)
        file.close()

    def handleTreeViewClick(self):
        selected_directory = self.fileTree.model().filePath(
            self.fileTree.selectedIndexes()[0])
        for fname in os.listdir(selected_directory):
            if fname.endswith('.dat'):
                try:
                    self.load(selected_directory)
                except Exception as e:
                    self.showError(e)
                break

    def handleTreeViewRightClick(self, event):
        selected_directory = os.path.normpath(self.fileTree.model().filePath(
            self.fileTree.selectedIndexes()[0]))
        menu = QMenu(self)
        copyAction = menu.addAction("Copy path")
        nppActionHot = menu.addAction("Run NPP, HOT start")
        nppActionCold = menu.addAction("Run NPP, COLD start")
        nppActionFactory = menu.addAction("Run NPP, FACTORY start")
        setDataInfoDirHotAction = menu.addAction(
            "Set dataInfo.json directory, HOT start")
        setDataInfoDirColdAction = menu.addAction(
            "Set dataInfo.json directory, COLD start")
        setDataInfoDirFactoryAction = menu.addAction(
            "Set dataInfo.json directory, FACTORY start")
        exploreAction = menu.addAction("Explore folder")
        cleanFolderAction = menu.addAction("Clean folder")
        deleteFolderAction = menu.addAction("Delete folder")
        action = menu.exec_(self.fileTree.viewport().mapToGlobal(event))
        if action == copyAction:
            cb = QApplication.clipboard()
            cb.clear(mode=cb.Clipboard)
            cb.setText(selected_directory, mode=cb.Clipboard)
        if action == nppActionHot:
            cleanFolder(selected_directory)
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_HOT)
            sys.path.insert(1, '../../../../python/src')
            from supernpp.supernpp import SuperNPP
            spp = SuperNPP(selected_directory, self.config['serials'])
            spp.run()
        if action == nppActionCold:
            cleanFolder(selected_directory)
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_COLD)
            sys.path.insert(1, '../../../../python/src')
            from supernpp.supernpp import SuperNPP
            spp = SuperNPP(selected_directory,
                           self.config['serials'],
                           startMode=START_MODE_COLD)
            spp.run()
        if action == nppActionFactory:
            cleanFolder(selected_directory)
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_FACTORY)
            sys.path.insert(1, '../../../../python/src')
            from supernpp.supernpp import SuperNPP
            spp = SuperNPP(selected_directory,
                           self.config['serials'],
                           startMode=START_MODE_FACTORY)
            spp.run()
        if action == setDataInfoDirHotAction:
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_HOT)
        if action == setDataInfoDirColdAction:
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_COLD)
        if action == setDataInfoDirFactoryAction:
            setDataInformationDirectory(selected_directory,
                                        startMode=START_MODE_FACTORY)
        if action == exploreAction:
            openFolderWithFileBrowser(selected_directory)
        if action == cleanFolderAction:
            cleanFolder(selected_directory)
        if action == deleteFolderAction:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Question)
            msg.setText("Are you sure you want to delete this folder?\n\n" +
                        selected_directory)
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            result = msg.exec()
            if result == QMessageBox.Yes:
                removeDirectory(selected_directory)

    def stopLoadingIndicator(self):
        self.loadingMovie.stop()
        self.loadingIndictator.clear()
        self.loadingIndictator.setPicture(self.emptyLoadingPicture)

    def showDeviceInfo(self):
        dlg = DeviceInfoDialog(self.log, self)
        dlg.show()
        dlg.exec_()

    def showFlashConfig(self):
        dlg = FlashConfigDialog(self.log, self)
        dlg.show()
        dlg.exec_()

    def plot(self, func, args=None):
        print("plotting " + func)
        self.currently_selected = func
        self.plotargs = args

        self.figure.clear()

        if hasattr(self, 'plotter'):
            if args is not None:
                getattr(self.plotter, func)(*args, self.figure)
            else:
                getattr(self.plotter, func)(self.figure)

        self.canvas.draw()
        self.stopLoadingIndicator()
        print("done plotting")
class AnalyzeTab(QWidget):

    analyzeDone = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject',
                             'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject',
                             'PyQt_PyObject')

    def __init__(self):
        super().__init__()

        # Layouts
        self.mainLayout = QHBoxLayout()
        self.lVbox = QVBoxLayout()
        self.lHbox = QHBoxLayout()
        self.lHbox_top = QHBoxLayout()
        self.rVbox = QVBoxLayout()
        self.rHbox = QHBoxLayout()
        self.rVbox2 = QVBoxLayout()
        self.stack = QStackedWidget()
        self.stack_Vbox = QVBoxLayout()
        self.stack_Hbox1 = QHBoxLayout()
        self.stack_Hbox2 = QHBoxLayout()
        self.hSplit = QSplitter(Qt.Horizontal)
        self.hSplit.setFrameShape(QFrame.StyledPanel)
        self.vSplit = QSplitter(Qt.Vertical)
        self.vSplit.setFrameShape(QFrame.StyledPanel)
        self.mainLayout.addLayout(self.lVbox, 1)
        self.mainLayout.addLayout(self.rVbox, 3)

        # Setup file browser
        self.fileModel = QFileSystemModel()
        self.fileModel.setNameFilters(['*.wav'])
        self.fileModel.setRootPath(QDir.currentPath())
        self.fileTree = QTreeView()
        self.fileTree.setModel(self.fileModel)
        self.fileTree.setRootIndex(self.fileModel.index(r'./'))
        self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection)
        self.fileTree.setColumnHidden(2, True)
        self.fileTree.setColumnHidden(1, True)
        self.rootDirEdit = QLineEdit(os.path.dirname(__file__))
        self.rootDirEdit.returnPressed.connect(self.on_edit_root)
        self.browseBtn = QPushButton('Browse')
        self.browseBtn.clicked.connect(self.on_browse)
        self.lHbox_top.addWidget(self.rootDirEdit, 3)
        self.lHbox_top.addWidget(self.browseBtn, 1)

        # Setup Canvas
        self.canvas = PlotCanvas(self)

        self.analyzeDone.connect(self.canvas.plot)
        self._analyze = lambda _: self.analyze(self.fileTree.selectedIndexes())
        self.analyzeBtn = QPushButton('Analyze')
        self.analyzeBtn.clicked.connect(self._analyze)

        ## BATCH ANALYSIS CONTROLS ##

        self.batchAnalyzeChk = QCheckBox('Batch Analysis')
        self.dataTable = QTableWidget()
        self.batchCtrlBox = QGroupBox("Batch Analysis")
        self.batchCtrlBox.setLayout(self.stack_Vbox)

        # Analysis Mode
        self.modeGroup = QButtonGroup()
        self.modeBox = QGroupBox('Analysis Mode')
        self.modeBox.setLayout(self.stack_Hbox1)
        self.stack_Vbox.addWidget(self.modeBox)
        self.wavAnalysisChk = QCheckBox('Wav analysis')
        self.wavAnalysisChk.setChecked(True)
        self.calibrationLocationBox = QComboBox()
        self.calibrationLocationBox.addItems([str(n) for n in range(1, 11)])
        self.calibrationCurveChk = QCheckBox('Calibration Curve')
        self.calibrationCurveChk.toggled.connect(
            lambda state: self.calibrationLocationBox.setEnabled(state))
        self.calibrationCurveChk.setChecked(False)
        self.stack_Hbox1.addWidget(self.wavAnalysisChk, 3)
        self.stack_Hbox1.addWidget(self.calibrationCurveChk, 3)
        self.stack_Hbox1.addWidget(QLabel('Location: '), 1)
        self.stack_Hbox1.addWidget(self.calibrationLocationBox, 1)
        self.stack_Vbox.addLayout(self.stack_Hbox1)
        self.modeGroup.addButton(self.wavAnalysisChk)
        self.modeGroup.addButton(self.calibrationCurveChk)
        self.modeGroup.setExclusive(True)

        # Outputs
        self.outputCtrlBox = QGroupBox('Outputs')
        self.outputCtrlBox.setLayout(self.stack_Hbox2)
        self.stack_Vbox.addWidget(self.outputCtrlBox)
        self.toCSVchk = QCheckBox('.csv')
        self.toJSONchk = QCheckBox('.json')
        self.toCSVchk.stateChanged.connect(lambda _: self.update_settings(
            'output', 'toCSV', self.toCSVchk.isChecked()))
        self.toJSONchk.stateChanged.connect(lambda _: self.update_settings(
            'output', 'toJSON', self.toJSONchk.isChecked()))

        self.stack_Hbox2.addWidget(self.toCSVchk)
        self.stack_Hbox2.addWidget(self.toJSONchk)
        self.stack_Vbox.addLayout(self.stack_Hbox2)

        self.stack.addWidget(self.dataTable)
        self.stack.addWidget(self.batchCtrlBox)
        self.stack.setCurrentWidget(self.dataTable)
        self.stack.show()
        self.batchAnalyzeChk.stateChanged.connect(self.toggle_stack)
        self.batchAnalyzeChk.setChecked(False)
        self.stack_Vbox.addStretch()

        ## PROCESSING CONTROLS ##
        self.processControls = QGroupBox('Signal Processing')
        self.tOffsetSlider = QSlider(Qt.Horizontal, )
        self.tOffsetSlider.setMinimum(1)
        self.tOffsetSlider.setMaximum(100)
        self.tOffsetSlider.setValue(100)
        self.tOffsetSlider.setTickPosition(QSlider.TicksBelow)
        self.tOffsetSlider.setTickInterval(10)
        self.tOffsetSlider.valueChanged.connect(
            lambda val: self.update_settings('processing', 'tChop', val))
        self.tOffsetLayout = QHBoxLayout()
        self.tOffsetSlider_Box = QGroupBox(
            f'Chop Signal - {self.tOffsetSlider.value()}%')
        self.tOffsetSlider.valueChanged.connect(
            lambda val: self.tOffsetSlider_Box.setTitle(f'Chop Signal - {val}%'
                                                        ))
        self.tOffsetSlider_Box.setLayout(self.tOffsetLayout)
        self.tOffsetLayout.addWidget(self.tOffsetSlider)

        self.nFFTSlider = QSlider(Qt.Horizontal, )
        self.nFFTSlider.setMinimum(1)
        self.nFFTSlider.setMaximum(16)
        self.nFFTSlider.setValue(1)
        self.nFFTSlider.setTickPosition(QSlider.TicksBelow)
        self.nFFTSlider.setTickInterval(2)
        self.nFFTSlider.valueChanged.connect(
            lambda val: self.update_settings('processing', 'detail', val))
        self.nFFTLayout = QHBoxLayout()
        self.nFFTSlider.valueChanged.connect(
            lambda val: self.nFFTSlider_Box.setTitle(f'FFT Size - {val*65536}'
                                                     ))
        self.nFFTSlider_Box = QGroupBox(
            f'FFT Size - {self.nFFTSlider.value()*65536}')
        self.nFFTSlider_Box.setLayout(self.nFFTLayout)
        self.nFFTLayout.addWidget(self.nFFTSlider)

        self.rVbox2.addWidget(self.tOffsetSlider_Box)
        self.rVbox2.addWidget(self.nFFTSlider_Box)
        self.processControls.setLayout(self.rVbox2)

        self.lVbox.addLayout(self.lHbox_top, 1)
        self.lVbox.addWidget(self.fileTree, 7)
        self.lVbox.addLayout(self.lHbox, 1)
        self.lHbox.addWidget(self.analyzeBtn, 2)
        self.lHbox.addWidget(self.batchAnalyzeChk, 1)
        self.vSplit.addWidget(self.canvas)
        self.vSplit.addWidget(self.hSplit)
        self.rVbox.addWidget(self.vSplit)
        self.hSplit.addWidget(self.stack)
        self.hSplit.addWidget(self.processControls)

        self.settings = {
            'processing': {
                'tChop': self.tOffsetSlider.value(),
                'detail': self.nFFTSlider.value()
            },
            'output': {
                'toCSV': self.toCSVchk.isChecked(),
                'toJSON': self.toJSONchk.isChecked()
            }
        }
        self.setLayout(self.mainLayout)

    def on_browse(self):
        # Browse to file tree root directory
        options = QFileDialog.Options()
        path = QFileDialog.getExistingDirectory(
            self, caption="Choose root directory", options=options)
        self.rootDirEdit.setText(path)
        self.fileTree.setRootIndex(self.fileModel.index(path))

    def on_edit_root(self):
        # Update the file tree root directory
        self.fileTree.setRootIndex(
            self.fileModel.index(self.rootDirEdit.text()))

    def update_settings(self, category, setting, value):
        # Update settings and reprocess FFT if in single analysis mode
        self.settings[category][setting] = value

        if category == 'processing' and self.fileTree.selectedIndexes():
            self.analyze(self.fileTree.selectedIndexes())

    def toggle_stack(self, state):
        if state == 2:
            self.stack.setCurrentWidget(self.batchCtrlBox)
            self.fileTree.setSelectionMode(QAbstractItemView.MultiSelection)
        else:
            self.stack.setCurrentWidget(self.dataTable)
            self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection)

    def analyze(self, filePaths):
        if self.batchAnalyzeChk.isChecked():
            if self.wavAnalysisChk.isChecked():
                self.batch_analyze_wav(
                    [self.fileModel.filePath(path) for path in filePaths[::4]])
            if self.calibrationCurveChk.isChecked():
                self.generate_calibration_curve(
                    [self.fileModel.filePath(path) for path in filePaths[::4]])

        else:
            if os.path.isdir(self.fileModel.filePath(
                    filePaths[0])) or len(filePaths) > 4:
                QMessageBox.information(
                    self, 'Error',
                    'Please select only 1 file for single analysis.')
                return
            self.single_analyze_wav(self.fileModel.filePath(filePaths[0]))

    def single_analyze_wav(self, filePath):
        """
        Do an FFT and find peaks on a single wav file

        :param filePath: file path to .wav file
        """

        tChopped, vChopped, fVals,\
        powerFFT, peakFreqs, peakAmps = Utils.AnalyzeFFT(filePath, tChop=self.settings['processing']['tChop'],
                                                                   detail=self.settings['processing']['detail'])

        self.analyzeDone.emit(tChopped, vChopped, fVals, powerFFT, peakFreqs,
                              peakAmps, filePath)
        self.update_table(peakFreqs, peakAmps)

    def batch_analyze_wav(self, filePaths):
        """
        Perform a batch analysis of many .wav files. Outputs FFTs and peaks in .csv or .json format

        :param filePaths: A list of folders containing the .wav files to be analyzed
        """

        toCSV = self.settings['output']['toCSV']
        toJSON = self.settings['output']['toJSON']

        start = time.time()

        fileTotal = 0
        for path in filePaths:
            if os.path.isdir(path):
                blockName = os.path.basename(path)
                print(f'Block: {blockName}')

                files = [
                    os.path.join(path, file) for file in os.listdir(path)
                    if '.wav' in file
                ]
                fileTotal += len(files)

                if toCSV:
                    if not os.path.exists(os.path.join(path,
                                                       'fft_results_csv')):
                        os.makedirs(os.path.join(path, 'fft_results_csv'))
                    resultFilePath = os.path.join(path, 'fft_results_csv')

                    print('Processing FFTs...')
                    with multiprocessing.Pool(processes=4) as pool:
                        results = pool.starmap(
                            Utils.AnalyzeFFT,
                            zip(files, itertools.repeat(True),
                                itertools.repeat(True)))
                    results = [
                        result for result in results if result is not None
                    ]

                    peaks = [result[0] for result in results]
                    ffts = [result[1] for result in results]

                    print('Writing to .csv...')
                    resultFileName = os.path.join(resultFilePath,
                                                  f'{blockName}_Peaks.csv')
                    peakFrames = pd.concat(peaks)
                    peakFrames.to_csv(resultFileName, index=False, header=True)
                    with concurrent.futures.ThreadPoolExecutor(
                            max_workers=16) as executor:
                        executor.map(self.multi_csv_write, ffts)

                if toJSON:
                    if not os.path.exists(
                            os.path.join(path, 'fft_results_json')):
                        os.makedirs(os.path.join(path, 'fft_results_json'))
                    print(os.path.join(path, 'fft_results_json'))

                    print('Processing FFTs...')
                    with multiprocessing.Pool(processes=4) as pool:
                        results = pool.starmap(
                            Utils.AnalyzeFFT,
                            zip(files, itertools.repeat(True),
                                itertools.repeat(False),
                                itertools.repeat(True)))
                        results = [
                            result for result in results if result is not None
                        ]

                    print('Writing to .json...')
                    with concurrent.futures.ThreadPoolExecutor(
                            max_workers=16) as executor:
                        executor.map(self.multi_json_write, results)

        end = time.time()
        print(
            f'**Done!** {len(filePaths)} blocks with {fileTotal} files took {round(end-start, 1)}s'
        )

    def generate_calibration_curve(self, filePaths):
        """
        Attempt to fit an exponential function to a set of data points (x: Peak Frequency, y: Compressive strength)
        provided in JSON format.

        ex:{
              "shape": "2-Hole",
              "testData": {
                "location": "1",
                "strength": 3.092453552,
                "peaks": [
                  {
                    "frequency": 1134.5561082797967,
                    "magnitude": 0.349102384777402
                  }]
              },
              "waveData": [...],
              "freqData": [...]
        }

        Plot the curve, data points and give the function if successful.

        ** NOTE ** This function is still experimental and a bit buggy. Sometimes the scipy.optimize curve_fit won't
        converge with the initial guess given for the coeffecients. You're probably better off writing your own code.

        :param filePaths: A list of folders containing .jsons
        """
        # Strike Location
        location = self.calibrationLocationBox.currentText()

        # Function to fit to the data
        exp_f = lambda x, a, b, c: a * np.exp(b * x) + c

        # Threaded method for opening all the .jsons and fitting
        calibCurve = ThreadedCalibrationCurve(filePaths, location, exp_f)
        progressDialog = QProgressDialog(
            f'Gettings samples for location: {location}', None, 0,
            len(filePaths), self)
        progressDialog.setModal(True)
        calibCurve.blocksSearched.connect(progressDialog.setValue)
        try:
            peakFreqs, strengths, popt, pcov, fitX = calibCurve.run()
        except Exception as e:
            QMessageBox.information(self, 'Error', e)
            return

        # Calculate R Squared
        residuals = strengths - exp_f(peakFreqs, *popt)
        ss_res = np.sum(residuals**2)
        ss_tot = np.sum((strengths - np.mean(strengths))**2)
        r_squared = 1 - (ss_res / ss_tot)

        # Plot Results
        fig = Figure()
        plt.scatter(peakFreqs, strengths)
        plt.plot(fitX, exp_f(fitX, *popt), '-k')
        ax = plt.gca()
        plt.text(
            0.05,
            0.9,
            f'y = {round(popt[0],3)}*exp({round(popt[1], 5)}x) + {round(popt[2], 3)}\n',
            ha='left',
            va='center',
            transform=ax.transAxes)
        plt.text(0.05,
                 0.85,
                 f'R^2 = {round(r_squared,3)}',
                 ha='left',
                 va='center',
                 transform=ax.transAxes)

        plt.title(f'Calibration Curve, Location: {location}')
        plt.xlabel('Frequency (Hz)')
        plt.ylabel('Compressive Strength (MPa)')

        plt.show()

    def multi_csv_write(self, frameTuple):
        frame = frameTuple[1]
        wavPath = frameTuple[0]

        resultFileDir = os.path.join(os.path.dirname(wavPath),
                                     'fft_results_csv')
        resultFileName = os.path.basename(wavPath) + '_fft.csv'
        resultFilePath = os.path.join(resultFileDir, resultFileName)

        frame.to_csv(resultFilePath, index=False, header=True)

    def multi_json_write(self, results):
        data = results[0]
        wavPath = results[1]

        jsonFileDir = os.path.join(os.path.dirname(wavPath),
                                   'fft_results_json')
        resultFileName = os.path.basename(wavPath) + '_fft.json'
        resultFilePath = os.path.join(jsonFileDir, resultFileName)

        # blockName = os.path.basename(os.path.dirname(wavPath))
        # blockDir = os.path.join(jsonFileDir, blockName)
        # if not os.path.exists(blockDir):
        #     os.makedirs(blockDir)
        # print(resultFilePath)
        with open(resultFilePath, 'w') as f:
            json.dump(data, f, indent=2)

    def update_table(self, peakFreqs, peakAmps):
        """

        :param peakFreqs:
        :param peakAmps:
        :return:
        """
        self.dataTable.setRowCount(2)
        self.dataTable.setColumnCount(len(peakFreqs) + 1)

        self.dataTable.setItem(0, 0, QTableWidgetItem("Frequencies: "))
        self.dataTable.setItem(1, 0, QTableWidgetItem("Powers: "))

        for col, freq in enumerate(peakFreqs, start=1):
            self.dataTable.setItem(0, col, QTableWidgetItem(str(round(freq))))
        for col, power in enumerate(peakAmps, start=1):
            item = QTableWidgetItem(str(round(power, 3)))
            if power > 0.7:
                item.setBackground(QColor(239, 81, 28))
            elif power >= 0.4:
                item.setBackground(QColor(232, 225, 34))
            elif power < 0.4:
                item.setBackground(QColor(113, 232, 34))
            self.dataTable.setItem(1, col, item)
예제 #19
0
class FilenamePrompt(_BasePrompt):

    """A prompt for a filename."""

    def __init__(self, question, parent=None):
        super().__init__(question, parent)
        self._init_texts(question)
        self._init_key_label()

        self._lineedit = LineEdit(self)
        if question.default:
            self._lineedit.setText(question.default)
        self._lineedit.textEdited.connect(self._set_fileview_root)
        self._vbox.addWidget(self._lineedit)

        self.setFocusProxy(self._lineedit)

        self._init_fileview()
        self._set_fileview_root(question.default)

        if config.val.prompt.filebrowser:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        self._to_complete = ''

    @pyqtSlot(str)
    def _set_fileview_root(self, path, *, tabbed=False):
        """Set the root path for the file display."""
        separators = os.sep
        if os.altsep is not None:
            separators += os.altsep

        dirname = os.path.dirname(path)
        basename = os.path.basename(path)
        if not tabbed:
            self._to_complete = ''

        try:
            if not path:
                pass
            elif path in separators and os.path.isdir(path):
                # Input "/" -> don't strip anything
                pass
            elif path[-1] in separators and os.path.isdir(path):
                # Input like /foo/bar/ -> show /foo/bar/ contents
                path = path.rstrip(separators)
            elif os.path.isdir(dirname) and not tabbed:
                # Input like /foo/ba -> show /foo contents
                path = dirname
                self._to_complete = basename
            else:
                return
        except OSError:
            log.prompt.exception("Failed to get directory information")
            return

        root = self._file_model.setRootPath(path)
        self._file_view.setRootIndex(root)

    @pyqtSlot(QModelIndex)
    def _insert_path(self, index, *, clicked=True):
        """Handle an element selection.

        Args:
            index: The QModelIndex of the selected element.
            clicked: Whether the element was clicked.
        """
        if index == QModelIndex():
            path = os.path.join(self._file_model.rootPath(), self._to_complete)
        else:
            path = os.path.normpath(self._file_model.filePath(index))

        if clicked:
            path += os.sep
        else:
            # On Windows, when we have C:\foo and tab over .., we get C:\
            path = path.rstrip(os.sep)

        log.prompt.debug('Inserting path {}'.format(path))
        self._lineedit.setText(path)
        self._lineedit.setFocus()
        self._set_fileview_root(path, tabbed=True)
        if clicked:
            # Avoid having a ..-subtree highlighted
            self._file_view.setCurrentIndex(QModelIndex())

    def _init_fileview(self):
        self._file_view = QTreeView(self)
        self._file_model = QFileSystemModel(self)
        self._file_view.setModel(self._file_model)
        self._file_view.clicked.connect(self._insert_path)

        if config.val.prompt.filebrowser:
            self._vbox.addWidget(self._file_view)
        else:
            self._file_view.hide()

        # Only show name
        self._file_view.setHeaderHidden(True)
        for col in range(1, 4):
            self._file_view.setColumnHidden(col, True)
        # Nothing selected initially
        self._file_view.setCurrentIndex(QModelIndex())
        # The model needs to be sorted so we get the correct first/last index
        self._file_model.directoryLoaded.connect(
            lambda: self._file_model.sort(0))

    def accept(self, value=None, save=False):
        self._check_save_support(save)
        text = value if value is not None else self._lineedit.text()
        text = downloads.transform_path(text)
        if text is None:
            message.error("Invalid filename")
            return False
        self.question.answer = text
        return True

    def item_focus(self, which):
        # This duplicates some completion code, but I don't see a nicer way...
        assert which in ['prev', 'next'], which
        selmodel = self._file_view.selectionModel()

        parent = self._file_view.rootIndex()
        first_index = self._file_model.index(0, 0, parent)
        row = self._file_model.rowCount(parent) - 1
        last_index = self._file_model.index(row, 0, parent)

        if not first_index.isValid():
            # No entries
            return

        assert last_index.isValid()

        idx = selmodel.currentIndex()

        if not idx.isValid():
            # No item selected yet
            idx = last_index if which == 'prev' else first_index
        elif which == 'prev':
            idx = self._file_view.indexAbove(idx)
        else:
            assert which == 'next', which
            idx = self._file_view.indexBelow(idx)

        # wrap around if we arrived at beginning/end
        if not idx.isValid():
            idx = last_index if which == 'prev' else first_index

        idx = self._do_completion(idx, which)

        selmodel.setCurrentIndex(
            idx,
            QItemSelectionModel.ClearAndSelect |  # type: ignore[arg-type]
            QItemSelectionModel.Rows)
        self._insert_path(idx, clicked=False)

    def _do_completion(self, idx, which):
        filename = self._file_model.fileName(idx)
        while not filename.startswith(self._to_complete) and idx.isValid():
            if which == 'prev':
                idx = self._file_view.indexAbove(idx)
            else:
                assert which == 'next', which
                idx = self._file_view.indexBelow(idx)
            filename = self._file_model.fileName(idx)

        return idx

    def _allowed_commands(self):
        return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
예제 #20
0
class MainWindowClass(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.interface_lng_val = 'Russian'
        self.setWindowTitle("Графический интерфейс программы OpenFOAM")

        self.full_dir = ''
        self.prj_name = ''
        self.con = ''

        # ---------------------------Панель управления решением задачи МСС----------------------------- #

        self.proj_open = QAction(self)
        self.proj_open.setEnabled(True)
        proj_ico = self.style().standardIcon(QStyle.SP_ArrowUp)
        self.proj_open.setIcon(proj_ico)
        self.proj_open.setToolTip('Открыть проект')

        self.lng_chs = QAction(self)
        self.lng_chs.setEnabled(True)
        lng_chs_ico = self.style().standardIcon(
            QStyle.SP_FileDialogDetailedView)
        self.lng_chs.setIcon(lng_chs_ico)
        self.lng_chs.setToolTip('Выбрать язык интерфейса программы')

        self.toolBar_1 = QToolBar("MyToolBar")
        self.toolBar_1.addAction(self.proj_open)
        self.toolBar_1.addAction(self.lng_chs)

        self.proj_open.triggered.connect(
            lambda: first_toolbar_functions_class.on_proj_open(self))

        self.addToolBar(self.toolBar_1)

        ###----------------------Панель управления подготовкой РС--------------------------###

        self.msh_open = QAction(self)
        self.msh_open.setEnabled(False)
        msh_ico = self.style().standardIcon(QStyle.SP_FileDialogNewFolder)
        self.msh_open.setIcon(msh_ico)
        self.msh_open.setToolTip('Открыть форму выбора расчетной сетки')

        self.msh_run = QAction(self)
        self.msh_run.setEnabled(False)
        msh_ico = self.style().standardIcon(QStyle.SP_ArrowRight)
        self.msh_run.setIcon(msh_ico)
        self.msh_run.setToolTip('Выполнить генерацию расчетной сетки')

        self.msh_visual = QAction(self)
        self.msh_visual.setEnabled(False)
        msh_visual_ico = self.style().standardIcon(QStyle.SP_MediaSeekForward)
        self.msh_visual.setIcon(msh_visual_ico)
        self.msh_visual.setToolTip('Выполнить визуализацию расчетной сетки')

        self.toolBar_2 = QToolBar()
        self.toolBar_2.addAction(self.msh_open)
        self.toolBar_2.addAction(self.msh_run)
        self.toolBar_2.addAction(self.msh_visual)

        self.msh_open.triggered.connect(
            lambda: second_toolbar_functions_class.on_msh_open(self))
        self.msh_run.triggered.connect(
            lambda: second_toolbar_functions_class.on_msh_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.msh_visual.triggered.connect(
            lambda: second_toolbar_functions_class.on_visual_msh_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.addToolBar(self.toolBar_2)
        self.insertToolBarBreak(self.toolBar_2)

        ###----------------------Панель управления проведением стресс-анализа--------------------------###

        self.str_an_run = QAction(self)
        self.str_an_run.setEnabled(False)
        str_an_ico = self.style().standardIcon(QStyle.SP_CommandLink)
        self.str_an_run.setIcon(str_an_ico)
        self.str_an_run.setToolTip('Выполнить стресс-анализ')

        self.str_an_vis_run = QAction(self)
        self.str_an_vis_run.setEnabled(False)
        str_an_vis_ico = self.style().standardIcon(QStyle.SP_MediaPlay)
        self.str_an_vis_run.setIcon(str_an_vis_ico)
        self.str_an_vis_run.setToolTip(
            'Выполнить визуализацию результатов стресс-анализ')

        self.toolBar_3 = QToolBar()
        self.toolBar_3.addAction(self.str_an_run)
        self.toolBar_3.addAction(self.str_an_vis_run)

        self.str_an_run.triggered.connect(
            lambda: second_toolbar_functions_class.on_str_an_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.str_an_vis_run.triggered.connect(
            lambda: second_toolbar_functions_class.on_visual_on_str_an_run(
                prj_path_val, mesh_name_txt_val, pp_dir, self, self.
                interface_lng_val, msh_type))

        self.addToolBar(self.toolBar_3)
        self.insertToolBarBreak(self.toolBar_3)

        ###----------------Верхний виджет с полным путем до файла сетки----------------###

        self.tdw = QDockWidget()
        self.tdw.setFixedSize(1400, 65)
        self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures)
        self.tdw_grid = QGridLayout()
        self.tdw_grid.setColumnStretch(2, 1)
        self.tdw_frame = QFrame()
        self.tdw_frame.setStyleSheet("background-color: ghostwhite;"
                                     "border-width: 0.5px;"
                                     "border-style: solid;"
                                     "border-color: silver;")
        self.tdw_frame.setLayout(self.tdw_grid)
        self.tdw.setWidget(self.tdw_frame)
        self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.tdw)

        ###-----------------Левый виджет с файловой системой проекта---------------------###

        self.fsw = QDockWidget()
        self.fsw.setFeatures(self.fsw.NoDockWidgetFeatures)
        self.fsw_label = QLabel()
        self.fsw_label.setAlignment(QtCore.Qt.AlignCenter)
        self.fsw_grid = QGridLayout()
        self.fsw_grid.addWidget(self.fsw_label, 0, 0)
        self.fsw_frame = QFrame()
        self.fsw_frame.setFixedSize(200, 35)
        self.fsw_frame.setStyleSheet("background-color: honeydew;"
                                     "border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;")
        self.fsw_frame.setLayout(self.fsw_grid)
        fs_lbl = "Файловая структура проекта"
        self.fsw_label.setText("<font color='SeaGreen'>" + fs_lbl + "</font>")
        self.fsw_label.setStyleSheet("border-style: none;" "font-size: 10pt;")
        self.fsw.setTitleBarWidget(self.fsw_frame)
        self.treeview = QTreeView()
        self.treeview.setFixedSize(200, 520)
        self.treeview.model = QtGui.QStandardItemModel()
        self.treeview.setModel(self.treeview.model)
        self.treeview.setColumnWidth(0, 100)
        self.treeview.setColumnHidden(1, True)
        self.treeview.setColumnHidden(2, True)
        self.treeview.setColumnHidden(3, True)
        self.treeview.header().hide()
        self.treeview.setItemsExpandable(False)
        self.treeview.clicked.connect(self.on_treeview_clicked)
        self.fsw.setWidget(self.treeview)

        ###-----------Правый виджет с формой вывода результатов генерации файлов-----------###

        self.cdw = QDockWidget()
        self.cdw.setFeatures(self.cdw.NoDockWidgetFeatures)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.cdw)

        self.cdw_grid = QGridLayout()
        self.cdw_frame = QFrame()
        self.cdw_frame.setFixedSize(495, 35)
        self.cdw_frame.setStyleSheet("border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;"
                                     "background-color: honeydew;")
        self.cdw_frame.setLayout(self.cdw_grid)

        self.outf_lbl = QLabel()
        self.outf_lbl.setAlignment(QtCore.Qt.AlignCenter)
        self.outf_lbl.setStyleSheet("border-style: none;" "font-size: 9pt;")

        self.cdw_grid.addWidget(self.outf_lbl, 0, 0)

        self.outf_edit = QTextEdit()
        self.outf_scroll = QScrollArea()
        self.outf_scroll.setWidgetResizable(True)
        self.outf_scroll.setWidget(self.outf_edit)
        self.outf_scroll.setFixedSize(495, 520)

        ###-----------------Центральный виджет с формой параметров---------------------###

        self.ffw = QDockWidget()
        self.ffw.setFeatures(self.ffw.NoDockWidgetFeatures)
        self.ffw_label = QLabel()
        self.ffw_label.setAlignment(QtCore.Qt.AlignCenter)
        self.ffw_grid = QGridLayout()
        self.ffw_grid.addWidget(self.ffw_label, 0, 0)
        self.ffw_frame = QFrame()
        self.ffw_frame.setFixedSize(693, 44)
        self.ffw_frame.setStyleSheet("border-width: 1px;"
                                     "border-style: solid;"
                                     "border-color: dimgray;"
                                     "border-radius: 4px;"
                                     "background-color: honeydew;")
        self.ffw_frame.setLayout(self.ffw_grid)

        ###------------------Нижний виджет со служебными сообщениями------------------###

        self.serv_mes = QDockWidget("Служебные сообщения")
        self.serv_mes.setFixedSize(1400, 160)
        self.serv_mes.setFeatures(self.serv_mes.NoDockWidgetFeatures)
        self.listWidget = QListWidget()
        self.serv_mes.setWidget(self.listWidget)

    ###---------------------Функции, связанные с работой главного окна------------------------###

    # ...........................Функция клика по файлу из дерева.........................

    ###........................Функция открытия окна выбора интерфейса программы...................###

    # ...........................Функция клика по файлу из дерева.........................

    def on_treeview_clicked(self, index):
        global fileName
        indexItem = self.treeview.model.index(index.row(), 0, index.parent())
        file_name = self.treeview.model.itemFromIndex(indexItem).text()
        file_form_class.inp_file_form_func(self, file_name, self.con)
        file_name_title = file_form_class.out_file_name_func()
        self.clear_label = QLabel()
        if file_name_title != None:
            self.cdw.setWidget(self.clear_label)
            self.cdw.setTitleBarWidget(self.clear_label)
            self.setCentralWidget(self.ffw)
            file_form = file_form_class.out_file_form_func()
            self.ffw.setWidget(file_form)
            self.ffw.setTitleBarWidget(self.ffw_frame)
            self.ffw_label.setText("Форма параметров файла: " +
                                   "<font color='peru'>" + file_name_title +
                                   "</font>")
            self.ffw_label.setStyleSheet("border-style: none;"
                                         "font-size: 9pt;")
        else:

            self.ffw.setTitleBarWidget(self.clear_label)
            self.ffw.setWidget(self.clear_label)
            self.cdw.setWidget(self.clear_label)
            self.cdw.setTitleBarWidget(self.clear_label)

        if file_name_title == 'blockMeshDict' or file_name_title == 'snappyHexMeshDict':
            if self.interface_lng_val == 'Russian':
                msg_lbl = QLabel(
                    '<span style="color:blue">Для создания расчетной сетки воспользуйтесь панелью инструментов</span>'
                )
            elif self.interface_lng_val == 'English':
                msg_lbl = QLabel(
                    '<span style="color:blue">For computational mesh generation use the toolbar</span>'
                )

            self.listWidget.clear()
            self.item = QListWidgetItem()
            self.listWidget.addItem(self.item)
            self.listWidget.setItemWidget(self.item, msg_lbl)

    # .........................Функция получения языка интерфейса..........................

    def on_lng_get(self, interface_lng):
        global interface_lng_val

        self.interface_lng_val = interface_lng

        if self.interface_lng_val == 'Russian':
            self.setWindowTitle("Генератор расчетных сеток")
            self.prj_open.setToolTip('Открыть проект')
            self.msh_run.setToolTip('Выполнить генерацию расчетной сетки')
            self.msh_visual.setToolTip(
                'Выполнить визуализацию расчетной сетки')
            self.lng_chs.setToolTip('Выбрать язык интерфейса программы')
        elif self.interface_lng_val == 'English':
            self.setWindowTitle("Mesh generator")
            self.prj_open.setToolTip('Open project')
            self.msh_run.setToolTip('Run mesh generation')
            self.msh_visual.setToolTip('Run mesh vizualization')
            self.lng_chs.setToolTip(
                'Select the interface language for the program')

    # .........................Функция получения пути до директории..........................

    def on_prj_path_get(self, prj_path, mesh_name_txt):
        global prj_path_val
        global mesh_name_txt_val
        global pp_dir

        prj_path_val = prj_path
        mesh_name_txt_val = mesh_name_txt

        pp_dir, pp_sys = os.path.split(prj_path_val)

    # .............................Функция получения типа сетки..............................

    def on_mesh_type_get(self, pd_2):
        global msh_type
        msh_type = pd_2