def new_console(tabto=None, floating=False, dockingarea=QtCore.Qt.RightDockWidgetArea):
    """
    Create a new console and float it as a max widget
    tabto: name of a widget on top of which the console should be tabbed
    floating: True to float the console, False to leave it docked
    dockingarea: The docking area for docking the window (default = right)
    """
    main_window = GetQMaxMainWindow()

    # create and setup a console
    console = PythonConsole(formats=HUGOS_THEME)
    console.setStyleSheet("background-color: #333333;")

    # create a dock widget for the console
    dock_widget = QDockWidget(main_window)
    dock_widget.setWidget(console)
    dock_widget.setObjectName("pyconsole")
    dock_widget.setWindowTitle("Python Console")
    main_window.addDockWidget(dockingarea, dock_widget)
    if not tabto is None:
        tabw = main_window.findChild(QWidget, tabto)
        main_window.tabifyDockWidget(tabw, dock_widget)
    dock_widget.setFloating(floating)
    dock_widget.show()

    # make the console do stuff
    console.eval_queued()
    return console
Beispiel #2
0
    def createDockWidget(self):
        """
        Criar dock
        """
        dock_wgt = QDockWidget()
        dock_wgt.setWindowTitle("Dock Exemplo")
        dock_wgt.setAllowedAreas(Qt.AllDockWidgetAreas)

        dock_wgt.setWidget(QTextEdit())

        self.addDockWidget(Qt.LeftDockWidgetArea, dock_wgt)
Beispiel #3
0
class Main(QMainWindow):
    """ MainWindow which contains all widgets of POSM.
    """
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.setWindowTitle("POSM")
        # All widgets should be destryed when the main window is closed. This the widgets can use the destroyed widget
        # to allow clean up. E.g. save the database of the TileLoader.
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.resize(config.config.window_size[0], config.config.window_size[1])

        self.elements_loader = ElementsLoader()

        # Element Viewer as DockWidget
        self.element_viewer = ElementViewer(self)
        self.dock_element_viewer = QDockWidget()
        self.dock_element_viewer.setWindowTitle("Element Viewer")
        self.dock_element_viewer.setFeatures(QDockWidget.DockWidgetFloatable
                                             | QDockWidget.DockWidgetMovable)
        self.dock_element_viewer.setWidget(self.element_viewer)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.dock_element_viewer)

        # LayerManger as DockWidget
        self.layer_manager = LayerManager(self)
        self.dock_layer_manager = QDockWidget()
        self.dock_layer_manager.setWindowTitle("Layer Manager")
        self.dock_layer_manager.setFeatures(QDockWidget.DockWidgetFloatable
                                            | QDockWidget.DockWidgetMovable)
        self.dock_layer_manager.setWidget(self.layer_manager)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.dock_layer_manager)

        self.viewer = Viewer.Viewer(self)
        self.setCentralWidget(self.viewer)
        self.viewer.setFocus()
        self.viewer.setFocusPolicy(QtCore.Qt.StrongFocus)

        self.changeset = Changeset(self)
        self.changset_form = ChangesetForm(self)

        self.toolbar = QToolBar()
        self.toolbar.addAction("Load Elements", self.viewer.load_elements)
        self.toolbar.addAction("Undo Changes", self.viewer.undo_changes)
        self.toolbar.addAction("Create Node",
                               partial(self.viewer.change_mode, "new_node"))
        self.toolbar.addAction("Upload Changes", self.changset_form.show)
        self.toolbar.addAction("Open Configuration",
                               partial(os.startfile, str(config.path_config)))
        self.addToolBar(self.toolbar)

        self.statusBar().showMessage("Welcome to POSM!")
def demo_docking_widgets():
    """
    Demonstrates how to create a QWidget with PySide2 and attach it to the 3dsmax main window.
    Creates two types of dockable widgets, a QDockWidget and a QToolbar
    """
    # Retrieve 3ds Max Main Window QWdiget
    main_window = GetQMaxMainWindow()

    # QAction reused by both dockable widgets.
    cylinder_icon_path = os.path.dirname(os.path.realpath(__file__)) + "\\cylinder_icon_48.png"
    cylinder_icon = QtGui.QIcon(cylinder_icon_path)
    create_cyl_action = QAction(cylinder_icon, u"Create Cylinder", main_window)
    create_cyl_action.triggered.connect(create_cylinder)

    # QDockWidget construction and placement over the main window
    dock_widget = QDockWidget(main_window)

    # Set for position persistence
    dock_widget.setObjectName("Creators")
    # Set to see dock widget name in toolbar customize popup
    dock_widget.setWindowTitle("Creators")
    dock_tool_button = QToolButton()
    dock_tool_button.setAutoRaise(True)
    dock_tool_button.setDefaultAction(create_cyl_action)
    dock_tool_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
    dock_widget.setWidget(dock_tool_button)

    main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock_widget)
    dock_widget.setFloating(True)
    dock_widget.show()

    # QToolBar construction and attachement to main window
    toolbar_widget = QToolBar(main_window)

    # Set for position persistence
    toolbar_widget.setObjectName("Creators TB")
    # Set to see dock widget name in toolbar customize popup
    toolbar_widget.setWindowTitle("Creators TB")
    toolbar_widget.setFloatable(True)
    toolbar_widget.addAction(create_cyl_action)

    main_window.addToolBar(QtCore.Qt.BottomToolBarArea, toolbar_widget)
    toolbar_widget.show()

    toolbar_position = get_pos_to_dock_toolbar(dock_widget)
    make_toolbar_floating(toolbar_widget, toolbar_position)
Beispiel #5
0
    def _on_select():
        global edd
        it = ed.scene().selectedItems()

        if len(it) > 0:
            it = it[0]
        else:
            it = None

        if isinstance(it, Element):
            edd = QDockWidget()
            edd.setWidget(it.editor())
            edd.setWindowTitle('Element properties')
            edd.setFeatures(QDockWidget.DockWidgetMovable
                            | QDockWidget.DockWidgetFloatable)
            w.addDockWidget(Qt.LeftDockWidgetArea, edd)
        elif edd is not None:
            w.removeDockWidget(edd)
            edd = None
Beispiel #6
0
                category_item.addChild(it)

            self.addTopLevelItem(category_item)


if __name__ == "__main__":
    app = QApplication()
    w = QMainWindow()
    w.setMinimumSize(640, 480)

    elems = ElementTree()
    elems.create_from_dict(ELEMENTS)
    elems.expandAll()
    dw = QDockWidget()
    dw.setWidget(elems)
    dw.setWindowTitle('Elements')
    dw.setFeatures(QDockWidget.DockWidgetMovable
                   | QDockWidget.DockWidgetFloatable)
    w.addDockWidget(Qt.LeftDockWidgetArea, dw)

    sim = Simulator()
    schem = Schematic()
    sim.root = schem.root
    g = Gate('or', 1, 2, False)
    g.name = 'gate'
    el = GateElement(sim, g)
    schem.add_element(el)
    ed = SchematicEditor(schem)
    t = QTimer(w)

    edd = None
Beispiel #7
0
    def __init__(self, app):
        super(MainWindow, self).__init__()
        self._app = app
        self._selectedIndex = None

        # model
        nodeFactory = NodeFactory()
        rootNode = nodeFactory.create(NodeType.General, 'Root')
        # for i in range(10000):  # for testing
        childNode0 = nodeFactory.create(NodeType.General, 'RightPirateLeg',
                                        rootNode)
        childNode1 = nodeFactory.create(NodeType.General, 'RightPirateLeg_END',
                                        childNode0)
        childNode2 = nodeFactory.create(NodeType.General, 'LeftFemur',
                                        rootNode)
        childNode3 = nodeFactory.create(NodeType.Sphere, 'LeftTibia',
                                        childNode2)
        childNode4 = nodeFactory.create(NodeType.Sphere, 'LeftFoot',
                                        childNode3)
        transform = childNode4.component(ComponentType.Transform)
        qTransform = transform.component()
        translation = qTransform.translation()
        translation.setX(5)
        qTransform.setTranslation(translation)

        # childNode5 = nodeFactory.create(NodeType.Box, 'LeftFoot_END', childNode4)
        self._model = SceneGraphModel(rootNode)

        self._sceneView = SceneView(rootNode.entity())
        self._container = self.createWindowContainer(self._sceneView)

        # scene graph view
        self._treeView = QTreeView()
        self._treeView.setModel(self._model)
        self._treeView.setHeaderHidden(True)
        self._treeView.setAlternatingRowColors(True)

        dockWidget = QDockWidget()
        dockWidget.setWidget(self._treeView)
        dockWidget.setWindowTitle('Scene Graph')
        dockWidget.setObjectName('sceneGraph')
        sceneGraphToggleAction = dockWidget.toggleViewAction()
        self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget)

        # property editor
        propertyEditor = PropertyEditor(self._model, nodeFactory,
                                        FieldFactory())

        dockWidget = QDockWidget()
        dockWidget.setWidget(propertyEditor)
        dockWidget.setWindowTitle('Property Editor')
        dockWidget.setObjectName('propertyEditor')
        propertyEditorToggleAction = dockWidget.toggleViewAction()
        self.addDockWidget(Qt.RightDockWidgetArea, dockWidget)

        # menu
        menuBar = self.menuBar()
        menu = menuBar.addMenu('&File')
        exitAction = menu.addAction('E&xit')
        exitAction.triggered.connect(self.close)
        menu.addAction(exitAction)
        menu = menuBar.addMenu('&Windows')
        menu.addAction(sceneGraphToggleAction)
        menu.addAction(propertyEditorToggleAction)
        menuBar.addMenu(menu)

        # central widget
        #button = QPushButton()
        self.setCentralWidget(self._container)

        # selection change event
        selectionModel = self._treeView.selectionModel()
        selectionModel.currentChanged.connect(propertyEditor.changeSelection)
Beispiel #8
0
class MainWindow(QMainWindow):
    """Provides the parent window that includes the BookmarkWidget,
    BrowserTabWidget, and a DownloadWidget, to offer the complete
    web browsing experience."""
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PySide2 tabbed browser Example')

        self._tab_widget = BrowserTabWidget(create_main_window_with_browser)
        self._tab_widget.enabled_changed.connect(self._enabled_changed)
        self._tab_widget.download_requested.connect(self._download_requested)
        self.setCentralWidget(self._tab_widget)
        self.connect(self._tab_widget, QtCore.SIGNAL("url_changed(QUrl)"),
                     self.url_changed)

        self._bookmark_dock = QDockWidget()
        self._bookmark_dock.setWindowTitle('Bookmarks')
        self._bookmark_widget = BookmarkWidget()
        self._bookmark_widget.open_bookmark.connect(self.load_url)
        self._bookmark_widget.open_bookmark_in_new_tab.connect(
            self.load_url_in_new_tab)
        self._bookmark_dock.setWidget(self._bookmark_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmark_dock)

        self._find_tool_bar = None

        self._actions = {}
        self._create_menu()

        self._tool_bar = QToolBar()
        self.addToolBar(self._tool_bar)
        for action in self._actions.values():
            if not action.icon().isNull():
                self._tool_bar.addAction(action)

        self._addres_line_edit = QLineEdit()
        self._addres_line_edit.setClearButtonEnabled(True)
        self._addres_line_edit.returnPressed.connect(self.load)
        self._tool_bar.addWidget(self._addres_line_edit)
        self._zoom_label = QLabel()
        self.statusBar().addPermanentWidget(self._zoom_label)
        self._update_zoom_label()

        self._bookmarksToolBar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, self._bookmarksToolBar)
        self.insertToolBarBreak(self._bookmarksToolBar)
        self._bookmark_widget.changed.connect(self._update_bookmarks)
        self._update_bookmarks()

    def _update_bookmarks(self):
        self._bookmark_widget.populate_tool_bar(self._bookmarksToolBar)
        self._bookmark_widget.populate_other(self._bookmark_menu, 3)

    def _create_menu(self):
        file_menu = self.menuBar().addMenu("&File")
        exit_action = QAction(QIcon.fromTheme("application-exit"),
                              "E&xit",
                              self,
                              shortcut="Ctrl+Q",
                              triggered=qApp.quit)
        file_menu.addAction(exit_action)

        navigation_menu = self.menuBar().addMenu("&Navigation")

        style_icons = ':/qt-project.org/styles/commonstyle/images/'
        back_action = QAction(QIcon.fromTheme(
            "go-previous", QIcon(style_icons + 'left-32.png')),
                              "Back",
                              self,
                              shortcut=QKeySequence(QKeySequence.Back),
                              triggered=self._tab_widget.back)
        self._actions[QWebEnginePage.Back] = back_action
        back_action.setEnabled(False)
        navigation_menu.addAction(back_action)
        forward_action = QAction(QIcon.fromTheme(
            "go-next", QIcon(style_icons + 'right-32.png')),
                                 "Forward",
                                 self,
                                 shortcut=QKeySequence(QKeySequence.Forward),
                                 triggered=self._tab_widget.forward)
        forward_action.setEnabled(False)
        self._actions[QWebEnginePage.Forward] = forward_action

        navigation_menu.addAction(forward_action)
        reload_action = QAction(QIcon(style_icons + 'refresh-32.png'),
                                "Reload",
                                self,
                                shortcut=QKeySequence(QKeySequence.Refresh),
                                triggered=self._tab_widget.reload)
        self._actions[QWebEnginePage.Reload] = reload_action
        reload_action.setEnabled(False)
        navigation_menu.addAction(reload_action)

        navigation_menu.addSeparator()

        new_tab_action = QAction("New Tab",
                                 self,
                                 shortcut='Ctrl+T',
                                 triggered=self.add_browser_tab)
        navigation_menu.addAction(new_tab_action)

        close_tab_action = QAction("Close Current Tab",
                                   self,
                                   shortcut="Ctrl+W",
                                   triggered=self._close_current_tab)
        navigation_menu.addAction(close_tab_action)

        edit_menu = self.menuBar().addMenu("&Edit")

        find_action = QAction("Find",
                              self,
                              shortcut=QKeySequence(QKeySequence.Find),
                              triggered=self._show_find)
        edit_menu.addAction(find_action)

        edit_menu.addSeparator()
        undo_action = QAction("Undo",
                              self,
                              shortcut=QKeySequence(QKeySequence.Undo),
                              triggered=self._tab_widget.undo)
        self._actions[QWebEnginePage.Undo] = undo_action
        undo_action.setEnabled(False)
        edit_menu.addAction(undo_action)

        redo_action = QAction("Redo",
                              self,
                              shortcut=QKeySequence(QKeySequence.Redo),
                              triggered=self._tab_widget.redo)
        self._actions[QWebEnginePage.Redo] = redo_action
        redo_action.setEnabled(False)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction("Cut",
                             self,
                             shortcut=QKeySequence(QKeySequence.Cut),
                             triggered=self._tab_widget.cut)
        self._actions[QWebEnginePage.Cut] = cut_action
        cut_action.setEnabled(False)
        edit_menu.addAction(cut_action)

        copy_action = QAction("Copy",
                              self,
                              shortcut=QKeySequence(QKeySequence.Copy),
                              triggered=self._tab_widget.copy)
        self._actions[QWebEnginePage.Copy] = copy_action
        copy_action.setEnabled(False)
        edit_menu.addAction(copy_action)

        paste_action = QAction("Paste",
                               self,
                               shortcut=QKeySequence(QKeySequence.Paste),
                               triggered=self._tab_widget.paste)
        self._actions[QWebEnginePage.Paste] = paste_action
        paste_action.setEnabled(False)
        edit_menu.addAction(paste_action)

        edit_menu.addSeparator()

        select_all_action = QAction("Select All",
                                    self,
                                    shortcut=QKeySequence(
                                        QKeySequence.SelectAll),
                                    triggered=self._tab_widget.select_all)
        self._actions[QWebEnginePage.SelectAll] = select_all_action
        select_all_action.setEnabled(False)
        edit_menu.addAction(select_all_action)

        self._bookmark_menu = self.menuBar().addMenu("&Bookmarks")
        add_bookmark_action = QAction("&Add Bookmark",
                                      self,
                                      triggered=self._add_bookmark)
        self._bookmark_menu.addAction(add_bookmark_action)
        add_tool_bar_bookmark_action = QAction(
            "&Add Bookmark to Tool Bar",
            self,
            triggered=self._add_tool_bar_bookmark)
        self._bookmark_menu.addAction(add_tool_bar_bookmark_action)
        self._bookmark_menu.addSeparator()

        tools_menu = self.menuBar().addMenu("&Tools")
        download_action = QAction(
            "Open Downloads",
            self,
            triggered=DownloadWidget.open_download_directory)
        tools_menu.addAction(download_action)

        window_menu = self.menuBar().addMenu("&Window")

        window_menu.addAction(self._bookmark_dock.toggleViewAction())

        window_menu.addSeparator()

        zoom_in_action = QAction(QIcon.fromTheme("zoom-in"),
                                 "Zoom In",
                                 self,
                                 shortcut=QKeySequence(QKeySequence.ZoomIn),
                                 triggered=self._zoom_in)
        window_menu.addAction(zoom_in_action)
        zoom_out_action = QAction(QIcon.fromTheme("zoom-out"),
                                  "Zoom Out",
                                  self,
                                  shortcut=QKeySequence(QKeySequence.ZoomOut),
                                  triggered=self._zoom_out)
        window_menu.addAction(zoom_out_action)

        reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"),
                                    "Reset Zoom",
                                    self,
                                    shortcut="Ctrl+0",
                                    triggered=self._reset_zoom)
        window_menu.addAction(reset_zoom_action)

        about_menu = self.menuBar().addMenu("&About")
        about_action = QAction("About Qt",
                               self,
                               shortcut=QKeySequence(
                                   QKeySequence.HelpContents),
                               triggered=qApp.aboutQt)
        about_menu.addAction(about_action)

    def add_browser_tab(self):
        return self._tab_widget.add_browser_tab()

    def _close_current_tab(self):
        if self._tab_widget.count() > 1:
            self._tab_widget.close_current_tab()
        else:
            self.close()

    def close_event(self, event):
        main_windows.remove(self)
        event.accept()

    def load(self):
        url_string = self._addres_line_edit.text().strip()
        if url_string:
            self.load_url_string(url_string)

    def load_url_string(self, url_s):
        url = QUrl.fromUserInput(url_s)
        if (url.isValid()):
            self.load_url(url)

    def load_url(self, url):
        self._tab_widget.load(url)

    def load_url_in_new_tab(self, url):
        self.add_browser_tab().load(url)

    def url_changed(self, url):
        self._addres_line_edit.setText(url.toString())

    def _enabled_changed(self, web_action, enabled):
        action = self._actions[web_action]
        if action:
            action.setEnabled(enabled)

    def _add_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_bookmark(url, title, icon)

    def _add_tool_bar_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_tool_bar_bookmark(url, title, icon)

    def _zoom_in(self):
        new_zoom = self._tab_widget.zoom_factor() * 1.5
        if (new_zoom <= WebEngineView.maximum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _zoom_out(self):
        new_zoom = self._tab_widget.zoom_factor() / 1.5
        if (new_zoom >= WebEngineView.minimum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _reset_zoom(self):
        self._tab_widget.set_zoom_factor(1)
        self._update_zoom_label()

    def _update_zoom_label(self):
        percent = int(self._tab_widget.zoom_factor() * 100)
        self._zoom_label.setText("{}%".format(percent))

    def _download_requested(self, item):
        # Remove old downloads before opening a new one
        for old_download in self.statusBar().children():
            if type(old_download).__name__ == 'download_widget' and \
                old_download.state() != QWebEngineDownloadItem.DownloadInProgress:
                self.statusBar().removeWidget(old_download)
                del old_download

        item.accept()
        download_widget = download_widget(item)
        download_widget.removeRequested.connect(
            self._remove_download_requested, Qt.QueuedConnection)
        self.statusBar().addWidget(download_widget)

    def _remove_download_requested(self):
        download_widget = self.sender()
        self.statusBar().removeWidget(download_widget)
        del download_widget

    def _show_find(self):
        if self._find_tool_bar is None:
            self._find_tool_bar = FindToolBar()
            self._find_tool_bar.find.connect(self._tab_widget.find)
            self.addToolBar(Qt.BottomToolBarArea, self._find_tool_bar)
        else:
            self._find_tool_bar.show()
        self._find_tool_bar.focus_find()

    def write_bookmarks(self):
        self._bookmark_widget.write_bookmarks()
Beispiel #9
0
class PhotoEditor(QMainWindow):  #Ok
    def __init__(self):
        super().__init__()
        self.iniciaUI()

    def iniciaUI(self):
        """
        Inicializa a janela e mostra seu conteuda na tela
        """

        self.setFixedSize(650, 650)
        #self.setGeometry(100,100, 400, 230)
        self.setWindowTitle("Photo Editor")
        self.centerMainWindow()
        self.createToolsDockWidget()
        self.createMenu()
        self.createToolBar()
        self.photoEditorWidgets()

        self.show()

    def centerMainWindow(self):  #Ok
        """
        Use a classe QDesktopWidget para acessar informações sobre 
        sua tela e use-a para centralizar a janela do aplicativo.
        """
        desktop = QDesktopWidget().screenGeometry()
        screen_width = desktop.width()
        screen_height = desktop.height()
        self.move((screen_width - self.width()) / 2,
                  (screen_height - self.height()) / 2)

    def createMenu(self):  #Ok
        """
        Criar menu para editor de fotos
        """

        self.abre_act = QAction(QIcon('Imagens/open_file.png'), "Abrir", self)
        self.abre_act.setShortcut('Ctrl+O')
        self.abre_act.setStatusTip('Abrir uma nova imagem')
        self.abre_act.triggered.connect(self.openImage)

        self.salv_act = QAction(QIcon('Imagens/save_file.png'), 'Salvar', self)
        self.salv_act.setShortcut('Ctrl+S')
        self.salv_act.setStatusTip('Salvar imagem')
        self.salv_act.triggered.connect(self.saveToFile)

        self.prnt_act = QAction(QIcon('Imagens/print.png'), "Imprimir", self)
        self.prnt_act.setShortcut('Ctrl+P')
        self.prnt_act.setStatusTip('Imprimir imagem')
        self.prnt_act.triggered.connect(self.printImage)
        self.prnt_act.setEnabled(False)

        self.sair_act = QAction(QIcon('Imagens/exit.png'), 'Sair', self)
        self.sair_act.setShortcut('Ctrl+Q')
        self.sair_act.setStatusTip('Sair do programa')
        self.sair_act.triggered.connect(self.close)

        self.rt90_act = QAction("Girar 90°", self)
        self.rt90_act.setStatusTip('Girar imagem 90 ° no sentido horário')
        self.rt90_act.triggered.connect(self.rotateImage90)

        self.rt180_act = QAction("Girar 180°", self)
        self.rt180_act.setStatusTip('Girar imagem 180° no sentido horário')
        self.rt180_act.triggered.connect(self.rotateImage180)

        self.flph_act = QAction("Espelhar na Horizontal", self)
        self.flph_act.setStatusTip('Espelhar imagem no eixo horizontal')
        self.flph_act.triggered.connect(self.flipImageHorizontal)

        self.flpv_act = QAction("Espelhar na Vertical", self)
        self.flpv_act.setStatusTip('Espelhar imagem no eixo vertical')
        self.flpv_act.triggered.connect(self.flipImageVertical)

        self.redm_act = QAction("Redimensionar metade", self)
        self.redm_act.setStatusTip(
            'Redimensionar imagem para metade do tamanho original')
        self.redm_act.triggered.connect(self.resizeImageHalf)

        self.limp_act = QAction(QIcon('Imagens/clear.png'), "Limpar Imagem",
                                self)
        self.limp_act.setShortcut("Ctrl+D")
        self.limp_act.setStatusTip('Limpar a imagem atual')
        self.limp_act.triggered.connect(self.clearImage)

        menu_bar = self.menuBar()
        menu_bar.setNativeMenuBar(False)

        arqv_menu = menu_bar.addMenu('Arquivo')
        arqv_menu.addAction(self.abre_act)
        arqv_menu.addAction(self.salv_act)
        arqv_menu.addSeparator()
        arqv_menu.addAction(self.prnt_act)
        arqv_menu.addSeparator()
        arqv_menu.addAction(self.sair_act)

        edit_menu = menu_bar.addMenu('Editar')
        edit_menu.addAction(self.rt90_act)
        edit_menu.addAction(self.rt180_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.flph_act)
        edit_menu.addAction(self.flpv_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.redm_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.limp_act)

        #???????????????????
        view_menu = menu_bar.addMenu('Exibir')
        view_menu.addAction(self.toggle_dock_tools_act)

        self.setStatusBar(QStatusBar(self))

    def openImage(self):  #Ok
        """
        Abrir um arquivo de imagem e exiba seu conteúdo 
        no label.
        Exibir mensagem de erro se a imagem não puder ser aberta.
        """
        arq_img, _ = QFileDialog.getOpenFileName(
            self, "Abrir Imagem", "",
            "Arquivos JPG (*.jpeg *.jpg );;Arquivos PNG (*.png)\
                            ;;Arquivos  Bitmap (*.bmp);;Arquivos  GIF (*.gif)")

        if arq_img:
            self.img = QPixmap(arq_img)
            self.img_lbl.setPixmap(
                self.img.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                                Qt.SmoothTransformation))
        else:
            QMessageBox.information(self, "Erro",
                                    "Não é possível abrir imagem.",
                                    QMessageBox.Ok)

        self.prnt_act.setEnabled(True)

    def saveToFile(self):  #Ok
        """
        Salvar a imagem.
        Exibir mensagem de erro se a imagem não puder ser salva.
        """

        arq_img, _ = QFileDialog.getSaveFileName(
            self, "Salvar Imagem", "",
            "Arquivos JPG (*.jpeg *.jpg );;Arquivos PNG (*.png)\
                            ;;Arquivos  Bitmap (*.bmp);;Arquivos  GIF (*.gif)")

        if arq_img and self.img.isNull() == False:
            self.img.save(image_file)
        else:
            QMessageBox.information(self, "Não é possível salvar imagem.",
                                    QMessageBox.Ok)

    def printImage(self):  #Ok
        """Imprimir Imagem
        """
        printer = QPrinter()
        printer.setOutputFormat(QPrinter.NativeFormat)

        prnt_dlg = QPrintDialog(printer)

        if (prnt_dlg.exec_() == QPrintDialog.Accepted):

            painter = QPainter()

            painter.begin(printer)

            rect = QRect(painter.viewport())

            size = QSize(self.img_lbl.pixmap().size())
            size.scale(rect.size(), Qt.KeepAspectRatio)

            painter.setViewport(rect.x(), rect.y(), size.width(),
                                size.height())
            painter.setWindow(self.img_lbl.pixmap().rect())

            painter.drawPixmap(0, 0, self.img_lbl.pixmap())

            painter.end()

    def rotateImage90(self):  #Ok
        """
        Girar imagem 90° no sentido horário
        """
        if self.img.isNull() == False:
            transform90 = QTransform().rotate(90)
            pixmap = QPixmap(self.img)
            rotated = pixmap.transformed(transform90,
                                         mode=Qt.SmoothTransformation)
            self.img_lbl.setPixmap(
                rotated.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            self.img = QPixmap(rotated)
            self.img_lbl.repaint()  # repaint the child widget
        else:
            # No image to rotate
            pass

    def rotateImage180(self):  #Ok
        """
        Girar imagem 180° no sentido horário
        """
        if self.img.isNull() == False:
            transform180 = QTransform().rotate(180)
            pixmap = QPixmap(self.img)
            rotated = pixmap.transformed(transform180,
                                         mode=Qt.SmoothTransformation)
            self.img_lbl.setPixmap(
                rotated.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            self.img = QPixmap(rotated)
            self.img_label.repaint()  # repaint the child widget
        else:
            # No image to rotate
            pass

    def flipImageHorizontal(self):  #Ok
        """
        Espelhar a imagem no eixo horizontal
        """
        if self.img.isNull() == False:
            flip_h = QTransform().scale(-1, 1)
            pixmap = QPixmap(self.img)
            flipped = pixmap.transformed(flip_h)
            self.img_lbl.setPixmap(
                flipped.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            self.img = QPixmap(flipped)
            self.img_lbl.repaint()
        else:
            pass

    def flipImageVertical(self):  #Ok
        """
        Espelhar a imagem no eixo vertical
        """
        if self.img.isNull() == False:
            flip_v = QTransform().scale(1, -1)
            pixmap = QPixmap(self.img)
            flipped = pixmap.transformed(flip_v)
            self.img_lbl.setPixmap(
                flipped.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            self.img = QPixmap(flipped)
            self.img_lbl.repaint()
        else:
            pass

    def resizeImageHalf(self):  #Ok
        """
        Redimensione a imagem para a metade do tamanho atual.
        """
        if self.img.isNull() == False:
            resize = QTransform().scale(0.5, 0.5)
            pixmap = QPixmap(self.img)
            resized = pixmap.transformed(resize)
            self.img_lbl.setPixmap(
                resized.scaled(self.img_lbl.size(), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            self.img = QPixmap(resized)
            self.img_lbl.repaint()
        else:
            pass

    def clearImage(self):  #Ok
        """
        Limpar a imagem atual no widget QLabel
        """
        self.img_lbl.clear()
        self.img = QPixmap()

    def createToolBar(self):  #Ok
        """
        Criar barra de ferramentas para editor de fotos
        """
        tool_bar = QToolBar("Barra de Ferramentas do Editor de Fotos")
        tool_bar.setIconSize(QSize(24, 24))
        self.addToolBar(tool_bar)

        tool_bar.addAction(self.abre_act)
        tool_bar.addAction(self.salv_act)
        tool_bar.addAction(self.prnt_act)
        tool_bar.addAction(self.limp_act)
        tool_bar.addSeparator()
        tool_bar.addAction(self.sair_act)

    def createToolsDockWidget(self):  #Ok
        """
        Use o menu Exibir -> Editar Ferramentas de Imagem e clique
        no widget dock para ligar ou desligar. 
        O dock de ferramentas pode ser colocado à esquerda ou à 
        direita da janela principal.
        """

        self.dock_tools_view = QDockWidget()
        self.dock_tools_view.setWindowTitle("Ferramentas Edição de Imagem")
        self.dock_tools_view.setAllowedAreas(Qt.LeftDockWidgetArea
                                             | Qt.RightDockWidgetArea)

        self.img_tool = QWidget()

        self.rt90_btn = QPushButton("Girar 90°")
        self.rt90_btn.setMinimumSize(QSize(130, 40))
        self.rt90_btn.setStatusTip('Girar imagem 90° no sentido horário')
        self.rt90_btn.clicked.connect(self.rotateImage90)

        self.rt180_btn = QPushButton("Girar 180°")
        self.rt180_btn.setMinimumSize(QSize(130, 40))
        self.rt180_btn.setStatusTip('Girar imagem 180° no sentido horário')
        self.rt180_btn.clicked.connect(self.rotateImage180)

        self.flph_btn = QPushButton("Espelhar na Horizontal")
        self.flph_btn.setMinimumSize(QSize(130, 40))
        self.flph_btn.setStatusTip('Espelhar imagem no eixo horizontal')
        self.flph_btn.clicked.connect(self.flipImageHorizontal)

        self.flpv_btn = QPushButton("Espelhar na Vertical")
        self.flpv_btn.setMinimumSize(QSize(130, 40))
        self.flpv_btn.setStatusTip('Espelhar imagem no eixo vertical')
        self.flpv_btn.clicked.connect(self.flipImageVertical)

        self.redm_btn = QPushButton("Redimensionar metade")
        self.redm_btn.setMinimumSize(QSize(130, 40))
        self.redm_btn.setStatusTip(
            'Redimensionar imagem para metade do tamanho original')
        self.redm_btn.clicked.connect(self.resizeImageHalf)

        vbox = QVBoxLayout()
        vbox.addWidget(self.rt90_btn)
        vbox.addWidget(self.rt180_btn)
        vbox.addStretch(1)
        vbox.addWidget(self.flph_btn)
        vbox.addWidget(self.flpv_btn)
        vbox.addStretch(1)
        vbox.addWidget(self.redm_btn)
        vbox.addStretch(6)

        self.img_tool.setLayout(vbox)
        self.dock_tools_view.setWidget(self.img_tool)

        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_tools_view)

        self.toggle_dock_tools_act = self.dock_tools_view.toggleViewAction()

    def photoEditorWidgets(self):  #Ok
        """
        Configurar instâncias de widgets para editor de fotos
        """

        self.img = QPixmap()
        self.img_lbl = QLabel()
        self.img_lbl.setAlignment(Qt.AlignCenter)
        self.img_lbl.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored)

        self.setCentralWidget(self.img_lbl)
Beispiel #10
0
class FB(rv.rvtypes.MinorMode):
    def __init__(self):
        rv.rvtypes.MinorMode.__init__(self)
        self.init("File Browser", None, None, [("File Browser", [
            ("Show File Browser", self.toggle, None, self._state)
        ])])
        self.setupUI()

        self._visible = False
        self.dock.visibilityChanged.connect(self.setVisible)

    def setupUI(self):
        self.dock = QDockWidget()
        self.dock.setWindowTitle("File Browser")

        self.masterWidget = QWidget()
        self.masterLayout = QVBoxLayout(self.masterWidget)
        self.dock.setWidget(self.masterWidget)

        movieExt = ["*.mov", "*.mp4", "*.wmv", "*.movieproc"]
        imgExt = [
            "*.ext", "*.tiff", "*.tif", "*.dpx", "*.iff", "*.jpeg", "*.png",
            "*.ari"
        ]
        rawCam = [
            ".arw", ".cr2", ".crw", ".dng", ".nef", ".orf", ".pef", ".ptx",
            ".raf", ".rdc", ".rmf"
        ]
        self.fileBrowser = FileBrowser(filterExtension=movieExt + imgExt +
                                       rawCam)
        self.fileBrowser.executed.connect(self.play)
        self.masterLayout.addWidget(self.fileBrowser)

    def readPrefs(self):
        self._visible = rv.commands.readSettings("File Browser", "visible",
                                                 False)

    def writePrefs(self, state):
        rv.commands.writeSettings("File Browser", "visible", state)

    def setVisible(self, visible):
        self._visible = visible

    def dockToggle(self):
        if self._visible:
            self.dock.show()
        else:
            self.dock.hide()
        self.writePrefs(self._visible)

    def toggle(self, event):
        self._visible = not self._visible
        self.dockToggle()

    def _state(self):
        if self._visible:
            return rv.commands.CheckedMenuState
        return rv.commands.UncheckedMenuState

    def activate(self):
        print("Activating QCTools")
        try:
            rv.rvtypes.MinorMode.activate(self)
            self.window = rv.qtutils.sessionWindow()
            self.window.addDockWidget(Qt.BottomDockWidgetArea, self.dock)
            self.dockToggle()
        except Exception as e:
            print("-" * 50)
            print(str(e))
            print("-" * 50)

    def deactivate(self):
        print("Deactivating QCTools")
        self.window.removeDockWidget(self.dock)
        self.dock.hide()
        rv.rvtypes.MinorMode.deactivate(self)

    def clearSession(self):
        rv.commands.clearSession()

    def play(self, file, new=True):
        if new:
            self.clearSession()
        source = rv.commands.addSourceVerbose([file], None)
        mediaInfo = rv.commands.sourceMediaInfo(source)
        print(mediaInfo)
        rv.commands.setRealtime(True)
        rv.commands.setCacheMode(1)
Beispiel #11
0
class MainWindow(QMainWindow):
    """Provides the parent window that includes the BookmarkWidget,
    BrowserTabWidget, and a DownloadWidget, to offer the complete
    web browsing experience."""
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PySide2 tabbed browser Example')

        self._tab_widget = BrowserTabWidget(create_main_window_with_browser)
        self._tab_widget.enabled_changed.connect(self._enabled_changed)
        self._tab_widget.download_requested.connect(self._download_requested)
        self.setCentralWidget(self._tab_widget)
        self.connect(self._tab_widget, QtCore.SIGNAL("url_changed(QUrl)"),
                     self.url_changed)

        self._bookmark_dock = QDockWidget()
        self._bookmark_dock.setWindowTitle('Bookmarks')
        self._bookmark_widget = BookmarkWidget()
        self._bookmark_widget.open_bookmark.connect(self.load_url)
        self._bookmark_widget.open_bookmark_in_new_tab.connect(self.load_url_in_new_tab)
        self._bookmark_dock.setWidget(self._bookmark_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmark_dock)

        self._find_tool_bar = None

        self._actions = {}
        self._create_menu()

        self._tool_bar = QToolBar()
        self.addToolBar(self._tool_bar)
        for action in self._actions.values():
            if not action.icon().isNull():
                self._tool_bar.addAction(action)

        self._addres_line_edit = QLineEdit()
        self._addres_line_edit.setClearButtonEnabled(True)
        self._addres_line_edit.returnPressed.connect(self.load)
        self._tool_bar.addWidget(self._addres_line_edit)
        self._zoom_label = QLabel()
        self.statusBar().addPermanentWidget(self._zoom_label)
        self._update_zoom_label()

        self._bookmarksToolBar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, self._bookmarksToolBar)
        self.insertToolBarBreak(self._bookmarksToolBar)
        self._bookmark_widget.changed.connect(self._update_bookmarks)
        self._update_bookmarks()

    def _update_bookmarks(self):
        self._bookmark_widget.populate_tool_bar(self._bookmarksToolBar)
        self._bookmark_widget.populate_other(self._bookmark_menu, 3)

    def _create_menu(self):
        file_menu = self.menuBar().addMenu("&File")
        exit_action = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                             self, shortcut = "Ctrl+Q", triggered=qApp.quit)
        file_menu.addAction(exit_action)

        navigation_menu = self.menuBar().addMenu("&Navigation")

        style_icons = ':/qt-project.org/styles/commonstyle/images/'
        back_action = QAction(QIcon.fromTheme("go-previous",
                                             QIcon(style_icons + 'left-32.png')),
                             "Back", self,
                             shortcut = QKeySequence(QKeySequence.Back),
                             triggered = self._tab_widget.back)
        self._actions[QWebEnginePage.Back] = back_action
        back_action.setEnabled(False)
        navigation_menu.addAction(back_action)
        forward_action = QAction(QIcon.fromTheme("go-next",
                                                QIcon(style_icons + 'right-32.png')),
                                "Forward", self,
                                shortcut = QKeySequence(QKeySequence.Forward),
                                triggered = self._tab_widget.forward)
        forward_action.setEnabled(False)
        self._actions[QWebEnginePage.Forward] = forward_action

        navigation_menu.addAction(forward_action)
        reload_action = QAction(QIcon(style_icons + 'refresh-32.png'),
                               "Reload", self,
                               shortcut = QKeySequence(QKeySequence.Refresh),
                               triggered = self._tab_widget.reload)
        self._actions[QWebEnginePage.Reload] = reload_action
        reload_action.setEnabled(False)
        navigation_menu.addAction(reload_action)

        navigation_menu.addSeparator()

        new_tab_action = QAction("New Tab", self,
                             shortcut = 'Ctrl+T',
                             triggered = self.add_browser_tab)
        navigation_menu.addAction(new_tab_action)

        close_tab_action = QAction("Close Current Tab", self,
                                 shortcut = "Ctrl+W",
                                 triggered = self._close_current_tab)
        navigation_menu.addAction(close_tab_action)

        edit_menu = self.menuBar().addMenu("&Edit")

        find_action = QAction("Find", self,
                             shortcut = QKeySequence(QKeySequence.Find),
                             triggered = self._show_find)
        edit_menu.addAction(find_action)

        edit_menu.addSeparator()
        undo_action = QAction("Undo", self,
                             shortcut = QKeySequence(QKeySequence.Undo),
                             triggered = self._tab_widget.undo)
        self._actions[QWebEnginePage.Undo] = undo_action
        undo_action.setEnabled(False)
        edit_menu.addAction(undo_action)

        redo_action = QAction("Redo", self,
                             shortcut = QKeySequence(QKeySequence.Redo),
                             triggered = self._tab_widget.redo)
        self._actions[QWebEnginePage.Redo] = redo_action
        redo_action.setEnabled(False)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction("Cut", self,
                            shortcut = QKeySequence(QKeySequence.Cut),
                            triggered = self._tab_widget.cut)
        self._actions[QWebEnginePage.Cut] = cut_action
        cut_action.setEnabled(False)
        edit_menu.addAction(cut_action)

        copy_action = QAction("Copy", self,
                             shortcut = QKeySequence(QKeySequence.Copy),
                             triggered = self._tab_widget.copy)
        self._actions[QWebEnginePage.Copy] = copy_action
        copy_action.setEnabled(False)
        edit_menu.addAction(copy_action)

        paste_action = QAction("Paste", self,
                             shortcut = QKeySequence(QKeySequence.Paste),
                             triggered = self._tab_widget.paste)
        self._actions[QWebEnginePage.Paste] = paste_action
        paste_action.setEnabled(False)
        edit_menu.addAction(paste_action)

        edit_menu.addSeparator()

        select_all_action = QAction("Select All", self,
                                  shortcut = QKeySequence(QKeySequence.SelectAll),
                                  triggered = self._tab_widget.select_all)
        self._actions[QWebEnginePage.SelectAll] = select_all_action
        select_all_action.setEnabled(False)
        edit_menu.addAction(select_all_action)

        self._bookmark_menu = self.menuBar().addMenu("&Bookmarks")
        add_bookmark_action = QAction("&Add Bookmark", self,
                                    triggered = self._add_bookmark)
        self._bookmark_menu.addAction(add_bookmark_action)
        add_tool_bar_bookmark_action = QAction("&Add Bookmark to Tool Bar", self,
                                           triggered = self._add_tool_bar_bookmark)
        self._bookmark_menu.addAction(add_tool_bar_bookmark_action)
        self._bookmark_menu.addSeparator()

        tools_menu = self.menuBar().addMenu("&Tools")
        download_action = QAction("Open Downloads", self,
                                 triggered = DownloadWidget.open_download_directory)
        tools_menu.addAction(download_action)

        window_menu = self.menuBar().addMenu("&Window")

        window_menu.addAction(self._bookmark_dock.toggleViewAction())

        window_menu.addSeparator()

        zoom_in_action = QAction(QIcon.fromTheme("zoom-in"),
                               "Zoom In", self,
                               shortcut = QKeySequence(QKeySequence.ZoomIn),
                               triggered = self._zoom_in)
        window_menu.addAction(zoom_in_action)
        zoom_out_action = QAction(QIcon.fromTheme("zoom-out"),
                                "Zoom Out", self,
                                shortcut = QKeySequence(QKeySequence.ZoomOut),
                                triggered = self._zoom_out)
        window_menu.addAction(zoom_out_action)

        reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"),
                                  "Reset Zoom", self,
                                  shortcut = "Ctrl+0",
                                  triggered = self._reset_zoom)
        window_menu.addAction(reset_zoom_action)

        about_menu = self.menuBar().addMenu("&About")
        about_action = QAction("About Qt", self,
                              shortcut = QKeySequence(QKeySequence.HelpContents),
                              triggered=qApp.aboutQt)
        about_menu.addAction(about_action)

    def add_browser_tab(self):
        return self._tab_widget.add_browser_tab()

    def _close_current_tab(self):
        if self._tab_widget.count() > 1:
            self._tab_widget.close_current_tab()
        else:
            self.close()

    def close_event(self, event):
        main_windows.remove(self)
        event.accept()

    def load(self):
        url_string = self._addres_line_edit.text().strip()
        if url_string:
            self.load_url_string(url_string)

    def load_url_string(self, url_s):
        url = QUrl.fromUserInput(url_s)
        if (url.isValid()):
            self.load_url(url)

    def load_url(self, url):
        self._tab_widget.load(url)

    def load_url_in_new_tab(self, url):
        self.add_browser_tab().load(url)

    def url_changed(self, url):
        self._addres_line_edit.setText(url.toString())

    def _enabled_changed(self, web_action, enabled):
        action = self._actions[web_action]
        if action:
            action.setEnabled(enabled)

    def _add_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_bookmark(url, title, icon)

    def _add_tool_bar_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_tool_bar_bookmark(url, title, icon)

    def _zoom_in(self):
        new_zoom = self._tab_widget.zoom_factor() * 1.5
        if (new_zoom <= WebEngineView.maximum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _zoom_out(self):
        new_zoom = self._tab_widget.zoom_factor() / 1.5
        if (new_zoom >= WebEngineView.minimum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _reset_zoom(self):
        self._tab_widget.set_zoom_factor(1)
        self._update_zoom_label()

    def _update_zoom_label(self):
        percent = int(self._tab_widget.zoom_factor() * 100)
        self._zoom_label.setText("{}%".format(percent))

    def _download_requested(self, item):
        # Remove old downloads before opening a new one
        for old_download in self.statusBar().children():
            if type(old_download).__name__ == 'download_widget' and \
                old_download.state() != QWebEngineDownloadItem.DownloadInProgress:
                self.statusBar().removeWidget(old_download)
                del old_download

        item.accept()
        download_widget = download_widget(item)
        download_widget.removeRequested.connect(self._remove_download_requested,
                                               Qt.QueuedConnection)
        self.statusBar().addWidget(download_widget)

    def _remove_download_requested(self):
            download_widget = self.sender()
            self.statusBar().removeWidget(download_widget)
            del download_widget

    def _show_find(self):
        if self._find_tool_bar is None:
            self._find_tool_bar = FindToolBar()
            self._find_tool_bar.find.connect(self._tab_widget.find)
            self.addToolBar(Qt.BottomToolBarArea, self._find_tool_bar)
        else:
            self._find_tool_bar.show()
        self._find_tool_bar.focus_find()

    def write_bookmarks(self):
        self._bookmark_widget.write_bookmarks()
Beispiel #12
0
class Main(QMainWindow):
    """ MainWindow which contains all widgets of Osmapy.
    """
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.setWindowTitle("Osmapy")
        path_base = pathlib.Path(__file__).parent
        icon_path = str(path_base / pathlib.Path("assets/appicon.png"))
        self.setWindowIcon(QIcon(str(icon_path)))
        # All widgets should be destroyed when the main window is closed. This the widgets can use the destroyed widget
        # to allow clean up. E.g. save the database of the TileLoader.
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.resize(config.config.window_size[0], config.config.window_size[1])

        self.elements_loader = ElementsLoader()

        # Element Viewer as DockWidget
        self.element_viewer = ElementViewer(self)
        self.dock_element_viewer = QDockWidget()
        self.dock_element_viewer.setWindowTitle("Element Viewer")
        self.dock_element_viewer.setFeatures(QDockWidget.DockWidgetFloatable
                                             | QDockWidget.DockWidgetMovable)
        self.dock_element_viewer.setWidget(self.element_viewer)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.dock_element_viewer)

        # LayerManger as DockWidget
        self.layer_manager = LayerManager(self)
        self.dock_layer_manager = QDockWidget()
        self.dock_layer_manager.setWindowTitle("Layer Manager")
        self.dock_layer_manager.setFeatures(QDockWidget.DockWidgetFloatable
                                            | QDockWidget.DockWidgetMovable)
        self.dock_layer_manager.setWidget(self.layer_manager)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea,
                           self.dock_layer_manager)

        self.viewer = Viewer.Viewer(self)
        self.setCentralWidget(self.viewer)
        self.viewer.setFocus()
        self.viewer.setFocusPolicy(QtCore.Qt.StrongFocus)

        self.changeset = Changeset(self)
        self.changset_form = ChangesetForm(self)

        self.toolbar = QToolBar()
        self.toolbar.addAction("Load Elements", self.viewer.load_elements)
        self.toolbar.addAction("Undo Changes", self.viewer.undo_changes)
        self.toolbar.addAction("Create Node",
                               partial(self.viewer.change_mode, "new_node"))
        self.toolbar.addAction("Upload Changes", self.changset_form.show)
        if os.name == "nt":
            self.toolbar.addAction(
                "Open Configuration",
                partial(os.startfile, str(config.path_config)))
        elif sys.platform == "darwin":
            self.toolbar.addAction(
                "Open Configuration",
                partial(call, ["open", str(config.path_config)]))
        else:
            self.toolbar.addAction(
                "Open Configuration",
                partial(call, ["xdg-open", str(config.path_config)]))
        self.addToolBar(self.toolbar)

        self.statusBar().showMessage("Welcome to Osmapy!")
Beispiel #13
0
class AsemblerIDE(QMainWindow):
    def __init__(self):
        super(AsemblerIDE, self).__init__()
        self.workspace = None
        self.backupTimer = 300000
        PathManager.START_DIRECTORY = os.getcwd()
        self.workspaceConfiguration = WorkspaceConfiguration.loadConfiguration(
        )
        self.snippetManager = SnippetManager.loadSnippetConfiguration()
        self.tooltipManager = TooltipManager.loadTooltipConfiguration()
        self.configurationManager = ConfigurationManager()
        self.editorTabs = EditorTabWidget(self.snippetManager,
                                          self.tooltipManager)
        self.menuBar = MenuBar()
        self.terminal = Terminal()
        self.toolBar = ToolBar(self.configurationManager)
        self.statusBar = StatusBar()
        self.treeView = TreeView(self.configurationManager)
        self.help = HelpWidget()
        self.ascii = AsciiTableWidget()
        self.setStatusBar(self.statusBar)
        self.addToolBar(self.toolBar)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.terminal)
        self.addDockWidget(Qt.RightDockWidgetArea, self.help)
        self.addDockWidget(Qt.RightDockWidgetArea, self.ascii)
        self.splitDockWidget(self.help, self.ascii, Qt.Vertical)
        self.treeDock = QDockWidget()
        self.treeDock.setAllowedAreas(Qt.LeftDockWidgetArea
                                      | Qt.RightDockWidgetArea)
        self.treeDock.setStyleSheet("background-color: #2D2D30; color: white;")
        self.treeDock.setFeatures(QDockWidget.DockWidgetMovable
                                  | QDockWidget.DockWidgetClosable)
        self.treeDock.setWindowTitle("Workspace explorer")
        self.treeDock.setWidget(self.treeView)
        header = QLabel("Workspace explorer")
        # header.setStyleSheet("background-color: #007ACC;")
        self.treeDock.setTitleBarWidget(header)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.treeDock)
        self.setMenuBar(self.menuBar)
        self.setMinimumSize(1200, 800)
        self.setWindowTitle("i386 Assembly Integrated Development Environment")
        self.setCentralWidget(self.editorTabs)
        self.setStyleSheet("background-color: #3E3E42; color: white;")
        self.setWindowIcon(QIcon(resource_path("resources/app_icon.ico")))

        self.addTabWidgetEventHandlers()
        self.addMenuBarEventHandlers()
        self.addToolBarEventHandlers()
        self.addTreeViewEventHandlers()
        self.checkWorkspaceConfiguration()
        #self.populateTreeView()
        #self.statusBar.comboBox.currentTextChanged.connect(self.changeEditorSyntax)
        self.statusBar.tabWidthComboBox.currentTextChanged.connect(
            self.changeEditorTabWidth)
        self.timer = QTimer()
        self.timer.start(self.backupTimer)
        self.timer.timeout.connect(self.makeBackupSave)

        self.terminal.console.setFocus()
        self.tabSwitcher = TabSwitcher(self.editorTabs)
        self.tabSwitcher.hide()
        self.projectSwitcher = ProjectSwitcher(self.configurationManager,
                                               self.toolBar.projectComboBox)
        self.projectSwitcher.hide()
        self.terminal.projectSwitchRequested.connect(self.showProjectSwitcher)
        self.terminal.tabSwitchRequested.connect(self.showTabSwitcher)
        self.editorTabs.tabSwitchRequested.connect(self.showTabSwitcher)
        self.editorTabs.projectSwitchRequested.connect(
            self.showProjectSwitcher)

        self.helpDocsDialog = GettingStartedDialog()
        self.helpDocsDialog.hide()

    def makeBackupSave(self):
        self.workspace.saveBackup()
        self.timer.setInterval(
            self.backupTimer
        )  # interval has to be reset cause the timer may have been paused

    def changeEditorTabWidth(self, text):
        currentTab: EditorTab = self.editorTabs.getCurrentTab()
        if currentTab:
            currentTab.widget.editor.tabSize = int(text)

    def changeEditorSyntax(self, text):
        currentTab: EditorTab = self.editorTabs.getCurrentTab()
        if currentTab:
            if text == "Assembly":
                currentTab.widget.editor.sintaksa = AsemblerSintaksa(
                    currentTab.widget.editor.document())
            elif text == "C":
                currentTab.widget.editor.sintaksa = CSyntax(
                    currentTab.widget.editor.document())
            currentTab.widget.editor.update()

    def checkWorkspaceConfiguration(self):
        defaultWorkspace = self.workspaceConfiguration.getDefaultWorkspace()
        if defaultWorkspace:
            if self.openWorkspaceAction(defaultWorkspace):
                self.show()
                return
            else:
                self.workspaceConfiguration.removeWorkspace(defaultWorkspace)
        dialog = WorkspaceConfigurationEditor(self.workspaceConfiguration,
                                              self)
        if dialog.exec_():
            self.show()
        else:
            sys.exit(0)

    def addTabWidgetEventHandlers(self):
        self.editorTabs.currentChanged.connect(self.activeTabChanged)

    def addTreeViewEventHandlers(self):
        self.treeView.fileDoubleCliked.connect(self.loadFileText)
        self.treeView.workspaceReload.connect(
            lambda wsProxy: self.openWorkspaceAction(wsProxy.path,
                                                     updateWorkspace=True))
        self.treeView.workspaceRename.connect(
            lambda oldPath, wsProxy: self.workspaceConfiguration.
            replaceWorkpsace(oldPath, wsProxy.path))
        self.treeView.newProjectAdded.connect(
            lambda: self.toolBar.updateComboBox())
        self.treeView.projectCompile.connect(
            lambda proxy: self.compileAction(proxy))
        self.treeView.projectDebug.connect(
            lambda proxy: self.debugAction(proxy))
        self.treeView.projectRun.connect(lambda proxy: self.runAction(proxy))
        self.treeView.projectRemove.connect(
            lambda proxy: self.removeProject(proxy))
        self.treeView.projectRename.connect(
            lambda oldPath, project: self.renameProject(oldPath, project))
        self.treeView.fileRemove.connect(
            lambda fileProxy: self.removeFile(fileProxy))
        self.treeView.fileRename.connect(
            lambda oldPath, fileProxy: self.renameFile(oldPath, fileProxy))
        self.treeView.fileSave.connect(
            lambda fileProxy: self.updateEditorTrie(fileProxy))
        self.treeView.invalidWorkspace.connect(self.invalidWorkspace)
        self.treeView.projectSave.connect(self.saveProject)
        self.treeView.quickAssemblyFile.connect(self.loadFileText)
        self.treeView.newFile.connect(self.loadFileText)

    def saveProject(self, projectProxy: ProjectProxy):
        self.saveAllFiles(projectProxy)

    def invalidWorkspace(self, workspace: WorkspaceNode):
        workspace.deleted = True
        msg = QMessageBox()
        msg.setStyleSheet("background-color: #2D2D30; color: white;")
        msg.setModal(True)
        msg.setIcon(QMessageBox.Critical)
        msg.setText("Workspace '{}' has been deleted from the disk.".format(
            workspace.path))
        msg.setWindowTitle("Invalid workspace")
        msg.exec_()
        if workspace.path in self.workspaceConfiguration.getWorkspaces():
            self.workspaceConfiguration.removeWorkspace(workspace.path)
        self.switchWorkspaceAction()

    def renameFile(self, oldPath: str, fileProxy: FileProxy):
        # fileProxy.text = None
        key = "{}/{}".format(fileProxy.parent.path, oldPath)
        if key in self.editorTabs.projectTabs:
            newKey = "{}/{}".format(fileProxy.parent.path, fileProxy.path)
            tab = self.editorTabs.projectTabs.pop(key)
            self.editorTabs.projectTabs[newKey] = tab
            tab.tabName = newKey
            index = self.editorTabs.tabs.index(fileProxy)
            tabText = newKey + "*" if fileProxy.hasUnsavedChanges else newKey
            self.editorTabs.setTabText(index, tabText)

    def renameProject(self, oldPath: str, project: ProjectNode):
        self.toolBar.updateComboBox()
        for fileProxy in project.proxy.files:
            oldKey = "{}/{}".format(oldPath, fileProxy.path)
            if oldKey in self.editorTabs.projectTabs:
                newKey = "{}/{}".format(project.proxy.path, fileProxy.path)
                tab = self.editorTabs.projectTabs.pop(oldKey)
                self.editorTabs.projectTabs[newKey] = tab
                tab.tabName = newKey
                index = self.editorTabs.tabs.index(fileProxy)
                tabText = newKey + "*" if fileProxy.hasUnsavedChanges else newKey
                self.editorTabs.setTabText(index, tabText)

    def removeFile(self, proxy: FileProxy):
        key = "{}/{}".format(proxy.parent.path, proxy.path)
        if key in self.editorTabs.projectTabs:
            self.editorTabs.closeTab(self.editorTabs.tabs.index(proxy),
                                     askToSave=False)

    def removeProject(self, proxy: ProjectProxy):
        for file in proxy.files:
            if file in self.editorTabs.tabs:
                self.editorTabs.closeTab(self.editorTabs.tabs.index(file),
                                         askToSave=False)
        self.toolBar.updateComboBox()

    def checkIfWorkspaceDeleted(self):
        if not os.path.exists(self.workspace.path):
            self.workspace.deleted = True

    def activeTabChanged(self, index):
        if index == -1:
            self.statusBar.tabWidthComboBox.setCurrentText('4')
            return
        syntax = "Assembly" if self.editorTabs.tabs[index].path[-1].lower(
        ) == "s" else "C"
        proxy = self.editorTabs.tabs[index]
        key = "{}/{}".format(proxy.parent.path, proxy.path)
        self.statusBar.comboBox.setCurrentText(syntax)
        self.statusBar.tabWidthComboBox.setCurrentText(
            str(self.editorTabs.projectTabs[key].widget.editor.tabSize))
        #self.changeEditorSyntax(syntax)

    def populateTreeView(self):
        workspace = WorkspaceNode()
        workspace.setText(0, "My workspace")
        self.treeView.setRoot(workspace)
        for i in range(5):
            project = ProjectNode()
            project.setText(0, "My Project {}".format(i + 1))
            assemblyFile = AssemblyFileNode()
            assemblyFile.setText(0, "procedure_{}.S".format(i + 1))
            cFile = CFileNode()
            cFile.setText(0, "main_{}.c".format(i + 1))
            self.treeView.addNode(workspace, project)
            self.treeView.addNode(project, assemblyFile)
            self.treeView.addNode(project, cFile)
            project.setExpanded(True)
        self.workspace = workspace

    def closeEvent(self, event):
        if self.tabSwitcher.isActiveWindow():
            self.tabSwitcher.hide()
        if self.helpDocsDialog.isVisible():
            self.helpDocsDialog.hide()
        for proxy in self.editorTabs.tabs:
            if proxy.hasUnsavedChanges:
                msg = QMessageBox()
                msg.setStyleSheet("background-color: #2D2D30; color: white;")
                msg.setParent(None)
                msg.setModal(True)
                msg.setWindowTitle("Confirm Exit")
                msg.setText("The file {}/{} has been modified.".format(
                    proxy.parent.path, proxy.path))
                msg.setInformativeText("Do you want to save the changes?")
                msg.setStandardButtons(QMessageBox.Save | QMessageBox.Discard
                                       | QMessageBox.Cancel)
                msg.setDefaultButton(QMessageBox.Save)
                retValue = msg.exec_()
                if retValue == QMessageBox.Save:
                    if not self.saveFileAction():
                        event.ignore()
                        return
                elif retValue == QMessageBox.Discard:
                    pass
                else:
                    event.ignore()
                    return
        self.workspaceConfiguration.saveConfiguration()
        self.snippetManager.saveConfiguration()
        self.tooltipManager.saveConfiguration()
        self.checkIfWorkspaceDeleted()
        if not self.workspace.deleted:
            self.workspace.proxy.closedNormally = True
            self.saveWorkspaceAction()
        else:
            if self.workspace.path in self.workspaceConfiguration.getWorkspaces(
            ):
                self.workspaceConfiguration.removeWorkspace(
                    self.workspace.path)
        super(AsemblerIDE, self).closeEvent(event)

    def addMenuBarEventHandlers(self):
        self.menuBar.quickAssemblyProjectAction.triggered.connect(
            self.quickAssemblyProject)
        self.menuBar.newWorkspaceAction.triggered.connect(
            self.newWorkspaceAction)
        self.menuBar.saveWorkspaceAction.triggered.connect(
            self.saveWorkpsaceAllFiles)
        self.menuBar.openWorkspaceAction.triggered.connect(
            self.openWorkspaceAction)
        self.menuBar.switchWorkspaceAction.triggered.connect(
            self.switchWorkspaceAction)

        self.menuBar.saveAction.triggered.connect(self.saveFileAction)
        self.menuBar.findAction.triggered.connect(self.findAction)
        self.menuBar.editDefaultWorkspace.triggered.connect(
            self.editDefaultWorkspaceConfiguration)
        self.menuBar.editCodeSnippets.triggered.connect(self.editCodeSnippets)
        self.menuBar.editSettings.triggered.connect(self.editSettings)

        self.menuBar.aboutAction.triggered.connect(self.showAbout)
        self.menuBar.helpAction.triggered.connect(self.showGettingStarted)

        self.menuBar.view.addAction(self.terminal.toggleViewAction())
        self.menuBar.view.addAction(self.treeDock.toggleViewAction())
        self.menuBar.view.addAction(self.help.toggleViewAction())
        self.menuBar.view.addAction(self.ascii.toggleViewAction())
        self.menuBar.view.addAction(self.toolBar.toggleViewAction())

    def quickAssemblyProject(self):
        if self.workspace:
            self.workspace.createQuickAssemblyProject()

    def showAbout(self):
        dialog = AboutDialog()
        dialog.exec_()

    def showGettingStarted(self):
        if self.helpDocsDialog.isHidden():
            self.helpDocsDialog.show()

    def findAction(self):
        currentTab: EditorTabWidget = self.editorTabs.getCurrentTab()
        if not currentTab:
            msg = QMessageBox()
            msg.setStyleSheet("background-color: #2D2D30; color: white;")
            msg.setModal(True)
            msg.setIcon(QMessageBox.Critical)
            msg.setText(
                "Cannot open file and replace window because there is no open file at the moment."
            )
            msg.setWindowTitle("Find & Replace error")
            msg.exec_()
            return
        currentTab.widget.find.setVisible(True)
        if currentTab.widget.editor.lastFind:
            currentTab.widget.find.findLabel.setText(
                currentTab.widget.editor.lastFind)
        currentTab.widget.find.findLabel.setFocus()

    def switchWorkspaceAction(self):
        remaining = self.timer.remainingTime()
        self.timer.stop(
        )  # timer for creating backups needs to be paused when switching ws
        dialog = WorkspaceConfigurationEditor(self.workspaceConfiguration,
                                              self,
                                              switch=True)
        if dialog.exec_() and dialog.workspaceDirectory:
            self.workspace.proxy.closedNormally = True
            self.saveWorkspaceAction()
            if not self.editorTabs.closeAllTabs():
                self.timer.start(
                    remaining)  # timer for saving backups is resumed
                return
            self.openWorkspaceAction(dialog.workspaceDirectory)
        self.timer.start(remaining)  # timer for saving backups is resumed

    def editDefaultWorkspaceConfiguration(self):
        editor = DefaultWorkspaceEditor(self.workspaceConfiguration)
        if editor.exec_():
            self.workspaceConfiguration.saveConfiguration()

    def editCodeSnippets(self):
        editor = SnippetEditor(self.snippetManager)
        if editor.exec_():
            self.snippetManager.saveConfiguration()

    def editSettings(self):
        editor = SettingsEditor(self.tooltipManager)
        if editor.exec_():
            self.tooltipManager.saveConfiguration()

    def newWorkspaceAction(self):
        remaining = self.timer.remainingTime()
        self.timer.stop(
        )  # timer for creating backups needs to be paused when switching ws
        if not self.editorTabs.closeAllTabs():
            self.timer.start(remaining)  # timer for saving backups is resumed
            return False
        self.workspace.proxy.closedNormally = True
        self.saveWorkspaceAction()
        workspace = WorkspaceNode()
        name = QFileDialog.getExistingDirectory(
            self, "New workspace", "select new workspace directory")
        if name:
            path = os.path.join(name, ".metadata")
            backup_path = os.path.join(name, ".backup")
            if os.path.isdir(path) or os.path.isdir(backup_path):
                self.msgInvalidFolderError(name)
                self.timer.start(
                    remaining)  # timer for saving backups is resumed
                return
            wsname = name[name.rindex(os.path.sep) + 1:]
            regex = re.compile('[@!#$%^&*()<>?/\|}{~:]')
            if ' ' in name or regex.search(wsname):
                msg = QMessageBox()
                msg.setStyleSheet("background-color: #2D2D30; color: white;")
                msg.setModal(True)
                msg.setIcon(QMessageBox.Critical)
                msg.setText(
                    "Workspace path/name cannot contain whitespace or special characters."
                )
                msg.setWindowTitle("Workspace creation error")
                msg.exec_()
                self.timer.start(
                    remaining)  # timer for saving backups is resumed
                return False
            workspace.path = name
            proxy = WorkspaceProxy()
            proxy.path = name
            workspace.proxy = proxy
            workspace.setIcon(0,
                              QIcon(resource_path("resources/workspace.png")))
            workspace.setText(0, wsname)
            self.workspace = workspace
            self.treeView.setRoot(self.workspace)
            self.saveWorkspaceAction()
            self.configurationManager.allProjects = []
            self.configurationManager.currentProject = None
            self.toolBar.updateComboBox()
            self.terminal.executeCommand("cd {}".format(self.workspace.path))
            self.workspaceConfiguration.addWorkspace(self.workspace.proxy.path)
            self.timer.start(remaining)  # timer for saving backups is resumed
            return True
        self.timer.start(remaining)  # timer for saving backups is resumed
        return False

    def saveWorkspaceAction(self, workspacePath=None):
        if self.workspace:
            self.workspace.saveWorkspace(workspacePath)

    def saveWorkpsaceAllFiles(self):
        self.saveAllFiles()
        self.saveWorkspaceAction()

    def updateProjectList(self):
        self.configurationManager.allProjects = []
        self.configurationManager.currentProject = None
        projects = self.treeView.getProjects()
        if len(projects):
            self.configurationManager.allProjects = self.treeView.getProjects()
            self.configurationManager.currentProject = projects[0]
        self.toolBar.updateComboBox()

    def openWorkspaceAction(self, workspacePath=None, updateWorkspace=False):
        if not self.editorTabs.closeAllTabs():
            return
        if not workspacePath:
            workspacePath = QFileDialog.getExistingDirectory(
                self, "Open workspace", "select new workspace directory")
            if not workspacePath:
                return
        regex = re.compile('[@!#$%^&*()<>?/\|}{~:]')
        if ' ' in workspacePath or regex.search(
                os.path.basename(workspacePath)):
            msg = QMessageBox()
            msg.setStyleSheet("background-color: #2D2D30; color: white;")
            msg.setModal(True)
            msg.setIcon(QMessageBox.Critical)
            msg.setText(
                "Workspace path/name cannot contain whitespace or special characters."
            )
            msg.setWindowTitle("Workspace creation error")
            msg.exec_()
            return False
        path = os.path.join(workspacePath, ".metadata")
        backup_path = os.path.join(workspacePath, ".backup")
        if os.path.isdir(path) or os.path.isdir(backup_path):
            self.msgInvalidFolderError(workspacePath)
            return
        workspace = WorkspaceProxy()
        self.workspace = WorkspaceNode()
        if os.path.exists(path):
            try:  # in try block in case there is a corrupted .metadata file on the path
                with open(path, 'rb') as file:
                    workspace = pickle.load(file)
            except:
                workspace.closedNormally = False  # set it to false to trigger backup msg in case .metadata is corrupted
        elif not os.path.exists(
                backup_path
        ):  # creates a .metadata file for a clean new workspace
            self.workspace.proxy = workspace
            self.applyWsCompatibilityFix(workspacePath)
            self.saveWorkspaceAction(workspacePath)
        self.workspace.proxy = workspace
        self.applyWsCompatibilityFix(workspacePath)
        attempted_backup = False
        if not self.workspace.proxy.closedNormally:
            if self.restoreBackupMessage(workspacePath,
                                         updateWorkspace=updateWorkspace):
                attempted_backup = True
                if self.loadWorkspaceAction(
                        workspacePath, backup=True):  # attempt to load backup
                    self.updateProjectList()
                    return True
                else:
                    self.messageBackupError("closedAbruptly")

        if self.loadWorkspaceAction(
                workspacePath,
                backup=False):  # attempt to load regular ws file
            self.updateProjectList()
            return True
        # If the regular file won't load for some reason and there was no backup attempt, ask to load the backup file
        elif not attempted_backup and self.restoreBackupMessage(
                workspacePath, failedToLoad=True):
            if self.loadWorkspaceAction(
                    workspacePath,
                    backup=True):  # attempt to load the backup file
                self.updateProjectList()
                return True
            else:
                self.messageBackupError()
        return False

    def msgInvalidFolderError(self, path):
        msg = QMessageBox()
        msg.setStyleSheet("background-color: #2D2D30; color: white;")
        msg.setModal(True)
        msg.setIcon(QMessageBox.Critical)
        msg.setText(
            "Invalid folder for a workspace."
            "\nEnsure there are no .metadata and .backup folders in \n{}".
            format(path))
        msg.setWindowTitle("Failed to load workspace.")
        msg.exec_()

    def messageBackupError(self, msgType=None):
        msg = QMessageBox()
        msg.setStyleSheet("background-color: #2D2D30; color: white;")
        msg.setModal(True)
        msg.setIcon(QMessageBox.Critical)
        if msgType == "closedAbruptly":
            msg.setText("Failed to load {}."
                        "\nRegular workspace save will be restored.".format(
                            ".backup workspace file"))
        else:
            msg.setText("Failed to load {}.".format(".backup workspace file"))
        msg.setWindowTitle("Failed to load backup workspace.")
        msg.exec_()

    def applyWsCompatibilityFix(self, workspacePath):
        try:
            closedNormally = self.workspace.proxy.closedNormally
        except AttributeError:
            closedNormally = True
        self.workspace.proxy.closedNormally = closedNormally  # adds attribute to old ws files
        self.workspace.path = workspacePath  # changes the path to currently selected dir, in case it was moved
        self.workspace.proxy.path = workspacePath

    def restoreBackupMessage(self,
                             wsName,
                             failedToLoad=False,
                             updateWorkspace=False):
        try:
            msg = QMessageBox()
            msg.setStyleSheet("background-color: #2D2D30; color: white;")
            msg.setParent(None)
            msg.setModal(True)
            msg.setWindowTitle("Workspace recovery")
            time = strftime(
                '%m/%d/%Y %H:%M:%S',
                localtime(os.path.getmtime(os.path.join(wsName, ".backup"))))
            if failedToLoad:
                msg.setText("The workplace {} could not be loaded.\n"
                            "\nTime the backup was created: {}".format(
                                wsName, time))
            elif updateWorkspace:
                msg.setText(
                    "Choose if you want to reload workspace or to recover from backup.\n"
                    "\nTime the backup was created: {}".format(wsName, time))
            else:
                msg.setText("The workplace {} was closed unexpectedly.\n"
                            "\nTime the backup was created: {}".format(
                                wsName, time))
            if not updateWorkspace:
                msg.setInformativeText(
                    "Would you like to recover from backup?")
            else:
                msg.setInformativeText(
                    "Would you like to recover from backup? Select No if you just want to update the workspace."
                )
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.setDefaultButton(QMessageBox.Yes)
            retValue = msg.exec_()
            if retValue == QMessageBox.Yes:
                return True
            else:
                return
        except:
            return False

    def loadWorkspaceAction(self, workspacePath, backup=False):
        if backup:
            path = os.path.join(workspacePath, ".backup")
        else:
            path = os.path.join(workspacePath, ".metadata")
        if os.path.exists(path):
            try:  # in try block in case there is a corrupted .metadata file on the path
                with open(path, 'rb') as file:
                    workspace = pickle.load(file)
            except:
                return False
        else:
            return False
        self.workspace = WorkspaceNode()
        self.workspace.proxy = workspace
        self.applyWsCompatibilityFix(workspacePath)
        self.workspace.setIcon(0,
                               QIcon(resource_path("resources/workspace.png")))
        self.workspace.setText(
            0, workspacePath[workspacePath.rindex(os.path.sep) + 1:])
        self.workspace.proxy.closedNormally = False
        if backup:
            success = self.workspace.loadBackupWorkspace(workspacePath)
        else:
            success = self.workspace.loadWorkspace()
        if not success:
            return False
        self.treeView.setRoot(self.workspace)
        projects = self.treeView.getProjects()
        if projects:
            self.configurationManager.allProjects.clear()
            self.configurationManager.allProjects.extend(projects)
        self.toolBar.updateComboBox()
        #self.treeView.expandAll()
        self.terminal.executeCommand("cd {}".format(self.workspace.path))
        self.workspaceConfiguration.addWorkspace(self.workspace.proxy.path)
        if workspacePath:
            self.saveWorkspaceAction(workspacePath)
        return True

    def addToolBarEventHandlers(self):
        self.toolBar.compile.triggered.connect(self.compileAction)
        self.toolBar.run.triggered.connect(self.runAction)
        self.toolBar.debug.triggered.connect(self.debugAction)

    def debugAction(self, projectProxy=None):
        currentProject: ProjectNode = self.configurationManager.currentProject
        if not currentProject:
            self.showNoCurrentProjectMessage("Debug")
            return
        if not os.path.exists(currentProject.proxy.getProjectPath()):
            currentProject.eventManager.invalidProject.emit(currentProject)
            return
        proxy = None
        if projectProxy:
            proxy = projectProxy
        else:
            if currentProject:
                proxy = currentProject.proxy
        if proxy:
            commandString = proxy.getProjectDebugCommand()
            self.terminal.console.setFocus()
            if self.terminal.executeCommand(proxy.getProjectCompileCommand()):
                copmileString = proxy.getProjectCompileCommand()
                if ' -g ' not in copmileString:
                    msg = QMessageBox()
                    msg.setStyleSheet(
                        "background-color: #2D2D30; color: white;")
                    msg.setModal(True)
                    msg.setIcon(QMessageBox.Warning)
                    msg.setText(
                        "Please set '-g' option in compiler configuration to be able to debug your project."
                    )
                    msg.setWindowTitle("Debug warning")
                    msg.exec_()
                    return False
                self.terminal.executeCommand(commandString)
            self.toolBar.projectComboBox.setCurrentText(proxy.path)

    def runAction(self, projectProxy=None):
        currentProject: ProjectNode = self.configurationManager.currentProject
        if not currentProject:
            self.showNoCurrentProjectMessage("Run")
            return
        if not os.path.exists(currentProject.proxy.getProjectPath()):
            currentProject.eventManager.invalidProject.emit(currentProject)
            return
        proxy = None
        if projectProxy:
            proxy = projectProxy
        else:
            if currentProject:
                proxy = currentProject.proxy
        if proxy:
            commandString = proxy.getProjectRunCommand()
            self.terminal.console.setFocus()
            if self.terminal.executeCommand(proxy.getProjectCompileCommand()):
                self.terminal.executeCommand(commandString)
            self.toolBar.projectComboBox.setCurrentText(proxy.path)

    def compileAction(self, projectProxy=None):
        currentProject: ProjectNode = self.configurationManager.currentProject
        if not currentProject:
            self.showNoCurrentProjectMessage("Compile")
            return
        if not os.path.exists(currentProject.proxy.getProjectPath()):
            currentProject.eventManager.invalidProject.emit(currentProject)
            return
        proxy = None
        if projectProxy:
            proxy = projectProxy
        else:
            if currentProject:
                proxy = currentProject.proxy
        if proxy:
            commandString = proxy.getProjectCompileCommand()
            self.terminal.console.setFocus()
            self.terminal.executeCommand(commandString)
            self.toolBar.projectComboBox.setCurrentText(proxy.path)

    def showNoCurrentProjectMessage(self, action: str):
        msg = QMessageBox()
        msg.setStyleSheet("background-color: #2D2D30; color: white;")
        msg.setModal(True)
        msg.setIcon(QMessageBox.Critical)
        msg.setText("You have to select a project first.")
        msg.setWindowTitle("{} error".format(action.capitalize()))
        msg.exec_()

    def checkExecutable(self):
        if self.editor.filePath:
            destination = self.editor.filePath[:-1] + "out"
            return os.path.exists(destination)
        return None

    def loadFileText(self, fileProxy):
        key = "{}/{}".format(fileProxy.parent.path, fileProxy.path)
        if key in self.editorTabs.projectTabs:
            self.editorTabs.setCurrentIndex(
                self.editorTabs.tabs.index(fileProxy))
            return
        text = self.openFileAction(fileProxy)
        fileProxy.text = text
        fileProxy.hasUnsavedChanges = False
        if fileProxy.getFilePath()[-1].lower() == "c":
            currentText = "C"
        else:
            currentText = "Assembly"
        update = True
        if len(self.editorTabs.tabs) == 0:
            self.editorTabs.tabs.append(fileProxy)
            update = False
        self.editorTabs.addNewTab(fileProxy, update)
        self.statusBar.comboBox.setCurrentText(currentText)
        if currentText == "Assembly":
            self.editorTabs.projectTabs[
                key].widget.editor.sintaksa = AsemblerSintaksa(
                    self.editorTabs.projectTabs[key].widget.editor.document())
        elif currentText == "C":
            self.editorTabs.projectTabs[key].widget.editor.sintaksa = CSyntax(
                self.editorTabs.projectTabs[key].widget.editor.document())

    def updateEditorTrie(self, proxy: FileProxy):
        key = "{}/{}".format(proxy.parent.path, proxy.path)
        if key in self.editorTabs.projectTabs:
            self.editorTabs.projectTabs[key].widget.editor.updateTrie()
            self.editorTabs.removeChangeIdentificator(proxy)

    def saveAllFiles(self, projectProxy=None):
        couldNotBeSaved = []
        for i in range(len(self.editorTabs.tabs)):
            fileProxy = self.editorTabs.tabs[i]
            try:
                if fileProxy and fileProxy.hasUnsavedChanges:
                    if projectProxy and fileProxy.parent.path != projectProxy.path:
                        continue
                    with open(fileProxy.getFilePath(), 'w') as file:
                        file.write(fileProxy.text)
                        fileProxy.hasUnsavedChanges = False
                    self.updateEditorTrie(fileProxy)
            except:
                couldNotBeSaved.append(fileProxy.path)
        self.saveWorkspaceAction()
        if couldNotBeSaved:
            msg = QMessageBox()
            msg.setStyleSheet("background-color: #2D2D30; color: white;")
            msg.setModal(True)
            msg.setIcon(QMessageBox.Critical)
            msg.setText("The following file(s) could not be saved: {}".format(
                ','.join(couldNotBeSaved)))
            msg.setWindowTitle("File save error")
            msg.exec_()

    def saveFileAction(self):
        if len(self.editorTabs.tabs):
            proxy = self.editorTabs.getCurrentFileProxy()
            if proxy and proxy.hasUnsavedChanges:
                try:
                    with open(proxy.getFilePath(), 'w') as file:
                        file.write(proxy.text)
                        proxy.hasUnsavedChanges = False
                    self.updateEditorTrie(proxy)
                except:
                    msg = QMessageBox()
                    msg.setStyleSheet(
                        "background-color: #2D2D30; color: white;")
                    msg.setModal(True)
                    msg.setIcon(QMessageBox.Critical)
                    msg.setText(
                        "The following file could not be saved: {}".format(
                            proxy.path))
                    msg.setWindowTitle("File save error")
                    msg.exec_()
            self.saveWorkspaceAction()
            return True

    def openFileAction(self, fileName: FileProxy):
        text = None
        # if fileName.text:
        #     return fileName.text
        with open(fileName.getFilePath(), 'r') as file:
            text = file.read()
        return text

    def keyPressEvent(self, event):
        if event.modifiers() == Qt.ControlModifier:
            if event.key() == Qt.Key_Tab:
                self.showTabSwitcher()
            elif event.key() == Qt.Key_E:
                self.showProjectSwitcher()
        super(AsemblerIDE, self).keyPressEvent(event)

    def showProjectSwitcher(self):
        if self.projectSwitcher.isHidden() and len(
                self.configurationManager.allProjects):
            self.projectSwitcher.showSwitcher()
            self.projectSwitcher.setFocus()

    def showTabSwitcher(self):
        if self.tabSwitcher.isHidden() and len(self.editorTabs.tabs):
            self.tabSwitcher.showSwitcher()
            self.tabSwitcher.setFocus()