Пример #1
0
    class abstract_treeview(QtWidgets.QTreeWidget):
        """Base class for the two treeview controls"""

        instanceSelected = QtCore.pyqtSignal([object])
        instanceVisibilityChanged = QtCore.pyqtSignal([object, int])
        instanceDisplayModeChanged = QtCore.pyqtSignal([object, int])

        def __init__(self):
            QtWidgets.QTreeView.__init__(self)
            self.setColumnCount(len(self.ATTRIBUTES))
            self.setHeaderLabels(self.ATTRIBUTES)
            self.children = defaultdict(list)

        def get_children(self, inst):
            c = [inst]
            i = 0
            while i < len(c):
                c.extend(self.children[c[i]])
                i += 1
            return c

        def contextMenuEvent(self, event):
            menu = QtWidgets.QMenu(self)
            visibility = [menu.addAction("Show"), menu.addAction("Hide")]
            displaymode = [
                menu.addAction("Solid"),
                menu.addAction("Wireframe")
            ]
            action = menu.exec_(self.mapToGlobal(event.pos()))
            index = self.selectionModel().currentIndex()
            inst = index.data(QtCore.Qt.UserRole)
            if hasattr(inst, "toPyObject"):
                inst = inst
            if action in visibility:
                self.instanceVisibilityChanged.emit(inst,
                                                    visibility.index(action))
            elif action in displaymode:
                self.instanceDisplayModeChanged.emit(inst,
                                                     displaymode.index(action))

        def clicked_(self, index):
            inst = index.data(QtCore.Qt.UserRole)
            if hasattr(inst, "toPyObject"):
                inst = inst
            if inst:
                self.instanceSelected.emit(inst)

        def select(self, product):
            itm = self.product_to_item.get(product)
            if itm is None:
                return
            self.selectionModel().setCurrentIndex(
                itm, QtCore.QItemSelectionModel.SelectCurrent
                | QtCore.QItemSelectionModel.Rows)
Пример #2
0
    class window(QtWidgets.QMainWindow):

        TITLE = "IfcOpenShell IFC viewer"

        window_closed = QtCore.pyqtSignal([])

        def __init__(self):
            QtWidgets.QMainWindow.__init__(self)
            self.setWindowTitle(self.TITLE)
            self.menu = self.menuBar()
            self.menus = {}

        def closeEvent(self, *args):
            self.window_closed.emit()

        def add_menu_item(self, menu, label, callback, icon=None, shortcut=None):
            m = self.menus.get(menu)
            if m is None:
                m = self.menu.addMenu(menu)
                self.menus[menu] = m

            if icon:
                a = QtWidgets.QAction(QtGui.QIcon(icon), label, self)
            else:
                a = QtWidgets.QAction(label, self)

            if shortcut:
                a.setShortcut(shortcut)

            a.triggered.connect(callback)
            m.addAction(a)
Пример #3
0
class CreateVirtualEnvThread(QtCore.QThread):
    """
    Thread used to run the process that creates a new virtual env.
    """
    #: Signal emitted when the virtual env has been created
    created = QtCore.pyqtSignal(str)
    #: Path of the environment to create
    path = ''
    #: Base interpreter, must be a system interpreter
    interpreter = ''
    #: True to enable system site-packages. Not recommended.
    system_site_packages = False

    def run(self):
        """
        Creates the virtual env
        """
        command = ['virtualenv', '-p', self.interpreter, self.path]
        if self.system_site_packages:
            command.insert(1, '--system-site-packages')
        command = ' '.join(command)
        if os.system(command) == 0:
            ext = '.exe' if WINDOWS else ''
            path = os.path.join(self.path, 'bin', 'python' + ext)
        else:
            path = None
        self.created.emit(path)
Пример #4
0
class FileDropWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(FileDropWidget, self).__init__(parent)
        self.setAcceptDrops(True)

    fileDropped = QtCore.pyqtSignal(str)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.acceptProposedAction()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            event.acceptProposedAction()

    def dropEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            for url in event.mimeData().urls():
                self.fileDropped.emit(str(url.toLocalFile()))
        else:
            event.acceptProposedAction()
Пример #5
0
class geometry_creation_signals(QtCore.QObject):
    completed = QtCore.pyqtSignal("PyQt_PyObject")
    progress = QtCore.pyqtSignal("PyQt_PyObject")
Пример #6
0
    class viewer(qtViewer3d):

        instanceSelected = QtCore.pyqtSignal([object])

        #         @staticmethod
        #         def ais_to_key(ais_handle):
        #             def yield_shapes():
        #                 ais = ais_handle.GetObject()
        #                 if hasattr(ais, "Shape"):
        #                     yield ais.Shape()
        #                     return
        #                 shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
        #                 if not shp.IsNull():
        #                     yield shp.Shape()
        #                 return
        #                 mult = ais_handle
        #                 if mult.IsNull():
        #                     shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
        #                     if not shp.IsNull():
        #                         yield shp
        #                 else:
        #                     li = mult.GetObject().ConnectedTo()
        #                     for i in range(li.Length()):
        #                         shp = OCC.AIS.Handle_AIS_Shape.DownCast(li.Value(i + 1))
        #                         if not shp.IsNull():
        #                             yield shp

        #             return tuple(shp.HashCode(1 << 24) for shp in yield_shapes())

        def __init__(self, widget):
            qtViewer3d.__init__(self, widget)
            self.ais_to_product = {}
            self.product_to_ais = {}
            self.counter = 0
            self.window = widget
            self.thread = None

        def initialize(self):
            self.InitDriver()
            self._display.Select = self.HandleSelection

        def finished(self, file_shapes):
            it, f, shapes = file_shapes
            v = self._display

            t = {0: time.time()}

            def update(dt=None):
                t1 = time.time()
                if dt is None or t1 - t[0] > dt:
                    v.FitAll()
                    v.Repaint()
                    t[0] = t1

            for shape in shapes:
                ais = display_shape(shape, viewer_handle=v)
                product = f[shape.data.id]

                if USE_OCCT_HANDLE:
                    ais.GetObject().SetSelectionPriority(self.counter)
                self.ais_to_product[self.counter] = product
                self.product_to_ais[product] = ais
                self.counter += 1

                QtWidgets.QApplication.processEvents()

                if product.is_a() in {"IfcSpace", "IfcOpeningElement"}:
                    v.Context.Erase(ais, True)

                update(1.0)

            update()

            self.thread = None

        def load_file(self, f, setting=None):

            if self.thread is not None:
                return

            if setting is None:
                setting = settings()
                setting.set(setting.INCLUDE_CURVES, True)
                setting.set(setting.USE_PYTHON_OPENCASCADE, True)

            self.signals = geometry_creation_signals()
            thread = self.thread = geometry_creation_thread(
                self.signals, setting, f)
            self.window.window_closed.connect(lambda *args: thread.terminate())
            self.signals.completed.connect(self.finished)
            self.thread.start()

        def select(self, product):
            ais = self.product_to_ais.get(product)
            if ais is None:
                return
            v = self._display.Context
            v.ClearSelected(False)
            v.SetSelected(ais, True)

        def toggle(self, product_or_products, fn):
            if not isinstance(product_or_products, Iterable):
                product_or_products = [product_or_products]
            aiss = list(
                filter(None, map(self.product_to_ais.get,
                                 product_or_products)))
            last = len(aiss) - 1
            for i, ais in enumerate(aiss):
                fn(ais, i == last)

        def toggle_visibility(self, product_or_products, flag):
            v = self._display.Context
            if flag:

                def visibility(ais, last):
                    v.Erase(ais, last)

            else:

                def visibility(ais, last):
                    v.Display(ais, last)

            self.toggle(product_or_products, visibility)

        def toggle_wireframe(self, product_or_products, flag):
            v = self._display.Context
            if flag:

                def wireframe(ais, last):
                    if v.IsDisplayed(ais):
                        v.SetDisplayMode(ais, 0, last)

            else:

                def wireframe(ais, last):
                    if v.IsDisplayed(ais):
                        v.SetDisplayMode(ais, 1, last)

            self.toggle(product_or_products, wireframe)

        def HandleSelection(self, X, Y):
            v = self._display.Context
            v.Select()
            v.InitSelected()
            if v.MoreSelected():
                ais = v.SelectedInteractive()
                inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
                self.instanceSelected.emit(inst)
Пример #7
0
    class viewer(qtViewer3d):

        instanceSelected = QtCore.pyqtSignal([object])

        @staticmethod
        def ais_to_key(ais_handle):
            def yield_shapes():
                ais = ais_handle.GetObject()
                if hasattr(ais, 'Shape'):
                    yield ais.Shape()
                    return
                shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
                if not shp.IsNull():
                    yield shp.Shape()
                return
                mult = ais_handle
                if mult.IsNull():
                    shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
                    if not shp.IsNull():
                        yield shp
                else:
                    li = mult.GetObject().ConnectedTo()
                    for i in range(li.Length()):
                        shp = OCC.AIS.Handle_AIS_Shape.DownCast(li.Value(i +
                                                                         1))
                        if not shp.IsNull():
                            yield shp

            return tuple(shp.HashCode(1 << 24) for shp in yield_shapes())

        def __init__(self, widget):
            qtViewer3d.__init__(self, widget)
            self.ais_to_product = {}
            self.product_to_ais = {}
            self.counter = 0
            self.window = widget

        def initialize(self):
            self.InitDriver()
            self._display.Select = self.HandleSelection

        def load_file(self, f, setting=None):

            if setting is None:
                setting = settings()
                setting.set(setting.USE_PYTHON_OPENCASCADE, True)

            v = self._display

            t = {0: time.time()}

            def update(dt=None):
                t1 = time.time()
                if t1 - t[0] > (dt or -1):
                    v.FitAll()
                    v.Repaint()
                    t[0] = t1

            terminate = [False]
            self.window.window_closed.connect(
                lambda *args: operator.setitem(terminate, 0, True))

            t0 = time.time()

            it = iterator(setting, f)
            if not it.initialize():
                return

            old_progress = -1
            while True:
                if terminate[0]:
                    break
                shape = it.get()
                product = f[shape.data.id]
                ais = display_shape(shape, viewer_handle=v)
                ais.GetObject().SetSelectionPriority(self.counter)
                self.ais_to_product[self.counter] = product
                self.product_to_ais[product] = ais
                self.counter += 1
                QtWidgets.QApplication.processEvents()
                if product.is_a() in {'IfcSpace', 'IfcOpeningElement'}:
                    v.Context.Erase(ais, True)
                progress = it.progress() // 2
                if progress > old_progress:
                    print("\r[" + "#" * progress + " " * (50 - progress) + "]",
                          end="")
                    old_progress = progress
                if not it.next():
                    break
                update(0.2)

            print("\rOpened file in %.2f seconds%s" %
                  (time.time() - t0, " " * 25))

            update()

        def select(self, product):
            ais = self.product_to_ais.get(product)
            if ais is None:
                return
            v = self._display.Context
            v.ClearSelected(False)
            v.SetSelected(ais, True)

        def toggle(self, product_or_products, fn):
            if not isinstance(product_or_products, Iterable):
                product_or_products = [product_or_products]
            aiss = list(
                filter(None, map(self.product_to_ais.get,
                                 product_or_products)))
            last = len(aiss) - 1
            for i, ais in enumerate(aiss):
                fn(ais, i == last)

        def toggle_visibility(self, product_or_products, flag):
            v = self._display.Context
            if flag:

                def visibility(ais, last):
                    v.Erase(ais, last)
            else:

                def visibility(ais, last):
                    v.Display(ais, last)

            self.toggle(product_or_products, visibility)

        def toggle_wireframe(self, product_or_products, flag):
            v = self._display.Context
            if flag:

                def wireframe(ais, last):
                    if v.IsDisplayed(ais):
                        v.SetDisplayMode(ais, 0, last)
            else:

                def wireframe(ais, last):
                    if v.IsDisplayed(ais):
                        v.SetDisplayMode(ais, 1, last)

            self.toggle(product_or_products, wireframe)

        def HandleSelection(self, X, Y):
            v = self._display.Context
            v.Select()
            v.InitSelected()
            if v.MoreSelected():
                ais = v.SelectedInteractive()
                inst = self.ais_to_product[ais.GetObject().SelectionPriority()]
                self.instanceSelected.emit(inst)
Пример #8
0
class WindowBase(QtWidgets.QMainWindow):
    closed = QtCore.pyqtSignal(QtWidgets.QMainWindow)

    @property
    def app(self):
        """
        :rtype: qidle.app.Application
        """
        return self._app()

    def __init__(self, ui, app):
        super(WindowBase, self).__init__()
        self._quitting = False
        self._app = weakref.ref(app)
        self._height = None
        # path of the script, 'Untitled' if new file not saved to disk.
        self.path = None
        self.ui = ui
        self.ui.setupUi(self)
        # we need to set proper menu roles for OS X
        self.ui.actionAbout_QIdle.setMenuRole(QtWidgets.QAction.AboutRole)
        self.ui.actionQuit.setMenuRole(QtWidgets.QAction.QuitRole)
        if sys.platform == 'win32':
            self.ui.actionConfigure_IDLE.setText('Preferences')
        self.ui.actionConfigure_IDLE.setMenuRole(
            QtWidgets.QAction.PreferencesRole)
        self.ui.actionConfigureRun.setMenuRole(QtWidgets.QAction.NoRole)
        self._setup_mnu_file(app, ui)
        self._setup_windows_menu(ui)
        self._setup_help_menu()
        ui.actionConfigure_IDLE.triggered.connect(self.edit_preferences)
        self._setup_icons()
        self.dock_manager_right = DockManager(self)
        self.dock_manager_right.setObjectName('dockManagerRight')
        self.dock_manager_right.setWindowTitle('Dock manager right')
        self.addToolBar(QtCore.Qt.RightToolBarArea, self.dock_manager_right)
        self.dock_manager_bottom = DockManager(self)
        self.dock_manager_bottom.setObjectName('dockManagerBottom')
        self.dock_manager_bottom.setWindowTitle('Dock manager bottom')
        self.addToolBar(QtCore.Qt.BottomToolBarArea, self.dock_manager_bottom)

    def apply_preferences(self):
        raise NotImplementedError()

    def save(self):
        raise NotImplementedError()

    def save_as(self):
        raise NotImplementedError()

    def restore_state(self):
        raise NotImplementedError()

    def save_state(self):
        raise NotImplementedError()

    def update_recents_menu(self):
        self.menu_recents.update_actions()

    def current_interpreter(self):
        raise NotImplementedError()

    def edit_preferences(self):
        DlgPreferences.edit_preferences(self,
                                        callback=self.app.apply_preferences)

    def zoom_height(self):
        _logger(self).debug('zoom height')
        desktop = QtWidgets.QApplication.instance().desktop()
        if sys.platform == 'win32':
            difference = (self.frameGeometry().height() -
                          self.geometry().height())
        else:
            difference = 0
        self.resize(self.width(),
                    desktop.availableGeometry(self).height() - difference)
        self.move(self.pos().x(), 0)

    def update_windows_menu(self, open_windows):
        _logger(self).debug('update windows menu: %r' % open_windows)
        self._open_windows = open_windows
        self.ui.menuWindows.clear()
        self.ui.menuWindows.addAction(self.ui.actionZoom_height)
        self.ui.menuWindows.addSeparator()
        self.ui.menuWindows.addMenu(self.ui.menuTools)
        self.ui.menuWindows.addSeparator()
        for win in open_windows:
            action = QtWidgets.QAction(self)
            if win == self:
                action.setDisabled(True)
            action.setText(win.windowTitle())
            action.setData(win)
            action.triggered.connect(self._show_window_from_action)
            self.ui.menuWindows.addAction(action)

    def _emit_closed(self):
        self.closed.emit(self)

    def _setup_icons(self):
        self.ui.actionNew_file.setIcon(icons.new_file)
        self.ui.actionNew_project.setIcon(icons.new_folder)
        self.ui.actionOpen_file.setIcon(icons.open_file)
        self.ui.actionOpen_directory.setIcon(icons.open_folder)
        self.ui.actionSave.setIcon(icons.save)
        self.ui.actionSave_as.setIcon(icons.save_as)
        self.ui.actionPython_docs.setIcon(icons.python_interpreter)
        self.ui.actionAbout_QIdle.setIcon(icons.help_about)
        self.ui.actionHelp_content.setIcon(icons.help_contents)
        self.ui.actionConfigure_IDLE.setIcon(icons.preferences)
        self.ui.actionConfigureRun.setIcon(icons.configure)
        self.ui.actionRun.setIcon(icons.run)
        self.ui.actionClose.setIcon(icons.window_close)
        self.ui.actionQuit.setIcon(icons.application_exit)

    def _setup_status_bar(self):
        self.lbl_cursor_pos = QtWidgets.QLabel()
        self.lbl_cursor_pos.setText('na')
        self.statusBar().addPermanentWidget(self.lbl_cursor_pos)
        self.lbl_encoding = QtWidgets.QLabel()
        self.lbl_encoding.setText('na')
        self.statusBar().addPermanentWidget(self.lbl_encoding)

    def _setup_mnu_file(self, app, ui):
        self.ui.menuFile.clear()
        self.ui.menuFile.addAction(self.ui.actionNew_file)
        self.ui.menuFile.addAction(self.ui.actionOpen_file)
        self.ui.menuFile.addSeparator()
        self.ui.menuFile.addAction(self.ui.actionNew_project)
        self.ui.menuFile.addAction(self.ui.actionOpen_directory)
        self.ui.menuFile.addSeparator()
        self.menu_recents = MenuRecentFiles(self,
                                            app.recent_files_manager,
                                            title='Recents',
                                            icon_provider=IconProvider())
        self.menu_recents.open_requested.connect(self.app.open_recent)
        self.ui.menuFile.addMenu(self.menu_recents)
        self.ui.menuFile.addSeparator()
        self.ui.menuFile.addAction(self.ui.actionSave)
        self.ui.menuFile.addAction(self.ui.actionSave_as)
        self.ui.menuFile.addSeparator()
        self.ui.menuFile.addAction(self.ui.actionClose)
        self.ui.menuFile.addAction(self.ui.actionQuit)
        ui.actionNew_file.triggered.connect(self._on_new_file_triggered)
        ui.actionOpen_file.triggered.connect(self._on_open_file_triggered)
        ui.actionNew_project.triggered.connect(self._on_new_project_triggered)
        ui.actionOpen_directory.triggered.connect(
            self._on_open_project_triggered)
        ui.actionSave.triggered.connect(self.save)
        ui.actionSave_as.triggered.connect(self.save_as)
        self.ui.actionClose.triggered.connect(self._close)
        self.ui.actionQuit.triggered.connect(self._quit)

    def _setup_windows_menu(self, ui):
        ui.actionZoom_height.triggered.connect(self.zoom_height)
        ui.menuTools.addActions(self.createPopupMenu().actions())
        action_prev_window = QtWidgets.QAction(self)
        action_prev_window.setShortcut('Alt+Up')
        action_prev_window.triggered.connect(self._show_prev_window)
        self.addAction(action_prev_window)
        action_next_window = QtWidgets.QAction(self)
        action_next_window.setShortcut('Alt+Down')
        action_next_window.triggered.connect(self._show_next_window)
        self.addAction(action_next_window)

    def _setup_help_menu(self):
        self.ui.actionPython_docs.triggered.connect(self._show_python_docs)

    def configure_shortcuts(self):
        self.addActions(self.ui.menuFile.actions())
        # menu edit already added
        self.addActions(self.ui.menuRun.actions())
        self.addActions(self.ui.menuOptions.actions())
        self.addActions(self.ui.menuWindows.actions())
        self.addActions(self.ui.menuHelp.actions())
        key_bindings = Preferences().key_bindings.dict()
        for action in self.actions():
            try:
                key_sequence = key_bindings[action.objectName()]
            except KeyError:
                pass
            else:
                action.setShortcut(key_sequence)

    def _show_window_from_action(self):
        window = self.sender().data()
        self.app.activate_window(window)

    def _on_new_file_triggered(self):
        _logger(self).debug('create new file')
        self.save_state()
        self.app.create_script_window()

    def _on_new_project_triggered(self):
        pass

    def _open_in_current_window(self, path, script):
        from qidle.windows.script import ScriptWindow
        if ((script and isinstance(self, ScriptWindow)
             or (not script and not isinstance(self, ScriptWindow)))):
            self.open(path)
        else:
            self._open_in_new_window(path, script)

    def _open_in_new_window(self, path, script):
        if script:
            self.app.create_script_window(path)
        else:
            self.app.create_project_window(path)

    def _on_open_file_triggered(self):
        path, filter = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Open script', self.path, filter='Python files (*.py *.pyw)')
        if path:
            script = os.path.isfile(path)
            action = Preferences().general.open_scr_action
            if action == Preferences().general.OpenActions.NEW:
                self._open_in_new_window(path, script)
            elif action == Preferences().general.OpenActions.CURRENT:
                self._open_in_current_window(path, script)
            else:
                # ask
                val = DlgAskOpenScript.ask(self)
                if val == Preferences().general.OpenActions.NEW:
                    self._open_in_new_window(path, script)
                elif val == Preferences().general.OpenActions.CURRENT:
                    self._open_in_current_window(path, script)

    def _on_open_project_triggered(self):
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self, 'Open project', os.path.expanduser('~'))
        if path:
            script = os.path.isfile(path)
            action = Preferences().general.open_project_action
            if action == Preferences().general.OpenActions.NEW:
                self._open_in_new_window(path, script)
            elif action == Preferences().general.OpenActions.CURRENT:
                self._open_in_current_window(path, script)
            else:
                # ask
                val = DlgAskOpenScript.ask(self)
                if val == Preferences().general.OpenActions.NEW:
                    self._open_in_new_window(path, script)
                elif val == Preferences().general.OpenActions.CURRENT:
                    self._open_in_current_window(path, script)

    def _show_prev_window(self):
        i = self.app.windows.index(self)
        i -= 1
        if i < 0:
            i = len(self.app.windows) - 1
        window = self.app.windows[i]
        self.app.activate_window(window)

    def _show_next_window(self):
        i = self.app.windows.index(self)
        i += 1
        if i >= len(self.app.windows):
            i = 0
        window = self.app.windows[i]
        self.app.activate_window(window)

    def _restart_backend(self, editor):
        """
        Restart the backend process of `editor`. The goal is to
        :param editor: pyqode.core.api.CodeEdit or subclass
        """
        editor.backend.start(
            editor.backend.server_script, self.current_interpreter(),
            [] if sys.executable == self.current_interpreter() else ['-s'] +
            [get_library_zip_path()])
        # update checker modes for the new interpreter syntax.
        for mode in editor.modes:
            if isinstance(mode, CheckerMode):
                mode.request_analysis()

    def _show_python_docs(self):
        _logger(self).info('opening python docs in the default browser')
        QtGui.QDesktopServices.openUrl(
            QtCore.QUrl('https://docs.python.org/3/'))

    def quit_confirmation(self):
        if Preferences().general.confirm_application_exit and \
                not self._quitting:
            button = QtWidgets.QMessageBox.question(
                self, "Confirm exit", "Are you sure you want to exit QIdle?",
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
            res = button == QtWidgets.QMessageBox.Yes
            return res
        return True

    def _quit(self):
        if self.quit_confirmation():
            self._quitting = True
            self.app.qapp.closeAllWindows()
            self._quitting = False

    def _close(self):
        # not sure why but if we don't do that using a timer we get a segfault
        self.close()

    def _apply_editor_preferences(self, editor, show_panels):
        _logger(self).info('applying preferences on editor: %s' %
                           editor.file.path)
        prefs = Preferences()
        # appearance
        editor.font_name = prefs.editor_appearance.font
        editor.font_size = prefs.editor_appearance.font_size
        editor.show_whitespaces = prefs.editor_appearance.show_whitespaces
        scheme = ColorScheme(prefs.editor_appearance.color_scheme)
        editor.syntax_highlighter.color_scheme = scheme
        self.ui.textEditPgmOutput.apply_color_scheme(scheme)
        # editor settings
        editor.panels.get('FoldingPanel').highlight_caret_scope = \
            prefs.editor.highlight_caret_scope
        editor.use_spaces_instead_of_tabs = \
            prefs.editor.use_spaces_instead_of_tabs
        editor.modes.get('RightMarginMode').position = \
            prefs.editor.margin_pos
        editor.tab_length = prefs.editor.tab_len
        editor.file.replace_tabs_by_spaces = \
            prefs.editor.convert_tabs_to_spaces
        editor.file.clean_trailing_whitespaces = \
            prefs.editor.clean_trailing
        editor.file.fold_imports = prefs.editor.fold_imports
        editor.file.fold_docstrings = prefs.editor.fold_docstrings
        editor.file.restore_cursor = prefs.editor.restore_cursor
        editor.file.safe_save = prefs.editor.safe_save
        mode = editor.modes.get('CodeCompletionMode')
        mode.trigger_length = prefs.editor.cc_trigger_len
        mode.show_tooltips = prefs.editor.cc_show_tooltips
        mode.case_sensitive = prefs.editor.cc_case_sensitive
        editor.setCenterOnScroll(prefs.editor.center_on_scroll)
        # modes
        for m in editor.modes:
            if m.name in prefs.editor.modes:
                m.enabled = prefs.editor.modes[m.name]
            else:
                m.enabled = True

        # disable unwanted panels
        for name, state in prefs.editor.panels.items():
            try:
                panel = editor.panels.get(name)
            except KeyError:
                _logger().exception('failed to retrieve mode by name: %r' %
                                    name)
            else:
                if name not in commons.DYNAMIC_PANELS:
                    if not show_panels and state is True:
                        continue
                    panel.setEnabled(state)
                    panel.setVisible(state)

    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.path)
Пример #9
0
class QDbgConsole(QtWidgets.QTextEdit):
    """
    A simple QTextEdit, with a few pre-set attributes and a file-like
    interface.
    """
    log_signal = QtCore.pyqtSignal(str)
    error_signal = QtCore.pyqtSignal(str)

    def __init__(self, size=None, parent=None):
        super(QDbgConsole, self).__init__(parent)

        self._buffer = io.StringIO()

        if size:
            self.setMinimumSize(*size)
        self.setReadOnly(True)
        self.getting_input = False
        self.input_cursor_pos = None
        self.log_signal.connect(self.write)
        self.error_signal.connect(
            lambda msg: self.write(msg, text_color=QtGui.QColor(139, 0, 0)))

    def write(self, msg, text_color=QtGui.QColor(0, 0, 0)):
        """Add msg to the console's output, on a new line."""
        self.setTextColor(text_color)
        self.insertPlainText(msg)
        # Autoscroll
        self.moveCursor(QtGui.QTextCursor.End)
        self._buffer.write(msg)

    def get_input(self, prompt=""):
        self.getting_input = True
        self.log_signal.emit(prompt)
        self.moveCursor(QtGui.QTextCursor.End)
        self.setReadOnly(False)
        self.input_cursor_pos = self.textCursor().position() + len(prompt)
        while self.getting_input:
            time.sleep(0.1)
        self.moveCursor(QtGui.QTextCursor.End)
        ret = self.toPlainText()[self.input_cursor_pos:].strip()
        return ret

    def keyPressEvent(self, event):
        if self.getting_input:
            if event.key() == QtCore.Qt.Key_Return:
                self.setReadOnly(True)
                self.write("\n")
                self.getting_input = False
                return

            if event.key() in [QtCore.Qt.Key_Delete, QtCore.Qt.Key_Backspace]:
                if self.textCursor().position() <= self.input_cursor_pos:
                    return
            super().keyPressEvent(event)
        self.moveCursor(QtGui.QTextCursor.End)

    def __getattr__(self, attr):
        """
        Fall back to the buffer object if an attribute can't be found.
        """
        return getattr(self._buffer, attr)
Пример #10
0
class Application(QtCore.QObject):
    """
    Sets up the Qt Application, the main window and the various controllers.

    The application class contains references to the main window user interface
    and to the various controllers so that they can collaborate each others.
    """
    _report_exception_requested = QtCore.pyqtSignal(object, str)

    def apply_mimetypes_preferences(self):
        for ext in Settings().all_extensions:
            mimetypes.add_type('text/x-cobol', ext)
            mimetypes.add_type('text/x-cobol', ext.upper())

    def __init__(self, parse_args=True):
        super().__init__()
        if system.darwin:
            Application._osx_init()
        self._reported_tracebacks = []
        self._old_except_hook = sys.excepthook
        sys.excepthook = self._except_hook
        self._report_exception_requested.connect(self._report_exception)
        if hasattr(sys, 'frozen') and sys.platform == 'win32':
            sys.stdout = open(
                os.path.join(system.get_cache_directory(), 'ocide_stdout.log'),
                'w')
            sys.stderr = open(
                os.path.join(system.get_cache_directory(), 'ocide_stderr.log'),
                'w')
        self.app = QtWidgets.QApplication(sys.argv)
        if parse_args and not system.darwin:
            args = self.parse_args()
            verbose = args.verbose
            files = args.files
        else:
            verbose = False
            files = []
        logger.setup_logging(__version__, debug=verbose or Settings().verbose)
        self.name = 'OpenCobolIDE'
        self.version = __version__
        self.title = '%s %s' % (self.name, self.version)

        self.apply_mimetypes_preferences()

        self.win = MainWindow()
        self.win.setWindowTitle(self.title)
        self.file = FileController(self)
        self.view = ViewController(self)
        self.home = HomeController(self)
        self.edit = EditController(self)
        self.cobol = CobolController(self)
        self.help = HelpController(self)

        self.view.show_perspective(Settings().perspective)
        self.view.show_home_page()

        self.update_app_style()

        try:
            check_compiler()
        except CompilerNotFound:
            msg = 'Failed to find a working GnuCOBOL compiler!\n' \
                "The IDE will continue to work but you won't be able to " \
                'compile...'
            if system.windows:
                msg += '\n\nTip: Ensure that there is no additional ' \
                    'installation of MinGW in %s:\MinGW' % sys.executable[0]
            QtWidgets.QMessageBox.warning(
                self.win, 'COBOL compiler not found or not working', msg)
        else:
            _logger().info('GnuCOBOL version: %s',
                           GnuCobolCompiler.get_version())
        # open specified files
        for f in files:
            self.file.open_file(f)

    def restart(self):
        """
        Restarts the IDE.
        """
        if hasattr(sys, 'frozen'):
            QtCore.QProcess.startDetached(sys.executable)
        else:
            QtCore.QProcess.startDetached(sys.executable, sys.argv)
        sys.exit(0)

    def close(self):
        self.view = None
        self.cobol = None
        self.edit = None
        self.file = None
        self.win = None
        self.home = None
        self.help = None

    def update_app_style(self):
        if Settings().dark_style:
            try:
                import qdarkstyle
            except ImportError:
                Settings().dark_style = False
            else:
                qt_api = os.environ[QT_API]
                if qt_api in PYQT5_API:
                    qss = qdarkstyle.load_stylesheet_pyqt5()
                else:
                    qss = qdarkstyle.load_stylesheet(qt_api in PYSIDE_API)
                self.app.setStyleSheet(qss)
                return
        self.app.setStyleSheet('')

    def run(self):
        """
        Run the Qt main loop.
        """
        if Settings().fullscreen:
            self.win.showFullScreen()
        else:
            self.win.showMaximized()
        return self.app.exec_()

    @staticmethod
    def _osx_init():
        """
        Mac OSX specific initialisation, adds missing path to the PATH
        environment variable (see github issue #40).

        """
        #
        paths = [
            '/bin', '/sbin', '/usr/bin', '/usr/sbin', '/usr/local/bin',
            '/usr/local/sbin', '/opt/bin', '/opt/sbin', '/opt/local/bin',
            '/opt/local/sbin'
        ]
        os.environ['PATH'] = ':'.join(paths)

    def exit(self):
        """
        Closes all top level windows and quits the application (without
        prompting the user, if you need to prompt the user, use
        Application.file.quit())
        """
        self.app.closeAllWindows()
        self.close()

    def parse_args(self):
        parser = argparse.ArgumentParser(
            description='Simple and lightweight COBOL IDE.')
        parser.add_argument('files',
                            type=str,
                            nargs='*',
                            help='List of files to open, if any')
        parser.add_argument('--verbose',
                            dest='verbose',
                            action='store_true',
                            help='Verbose mode will enable debug and info '
                            'messages to be shown in the application log')
        return parser.parse_args()

    def _except_hook(self, exc_type, exc_val, tb):
        tb = '\n'.join([
            ''.join(traceback.format_tb(tb)),
            '{0}: {1}'.format(exc_type.__name__, exc_val)
        ])
        # exception might come from another thread, use a signal
        # so that we can be sure we will show the bug report dialog from
        # the main gui thread.
        self._report_exception_requested.emit(exc_val, tb)

    def _report_exception(self, exc, tb):
        try:
            _logger().critical('unhandled exception:\n%s', tb)
            _tb = tb
            if isinstance(exc, UnicodeDecodeError):
                # This might be the same exception in the same file but at another position
                # in the stream
                _tb = tb.splitlines()[-4]
            if _tb in self._reported_tracebacks:
                return
            self._reported_tracebacks.append(_tb)
            title = '[Unhandled exception] %s' % exc.__class__.__name__
            description = 'An unhandled exception has occured:\n\n'\
                          '%s\n\nWould like to send a bug report to the ' \
                          'development team?' % tb
            answer = QtWidgets.QMessageBox.critical(
                self.win, title, description,
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                QtWidgets.QMessageBox.Yes)
            if answer == QtWidgets.QMessageBox.Yes:
                description = '## Steps to reproduce\n\nPLEASE DESCRIBE '\
                    'THE CONTEXT OF THIS BUG AND THE STEPS TO REPRODUCE!\n\n'\
                    '## Traceback\n\n```\n%s\n```' % tb
                DlgReportBug.report_bug(self.win,
                                        title=title,
                                        description=description)

        except Exception:
            _logger().exception('exception in excepthook')
Пример #11
0
class FileBrowserDock(DockBase):
    """ FileBrowserDock(QtWidgets.QWidget parent = None,
                        Function openFunc = None)

        params: parent - parent widget
               openFunction - function used for open file commands
               
        desc: The dockwidget containing all the elements of the
              of a file browser.
    """

    pylint_finished = QtCore.pyqtSignal(WritableObject)

    def __init__(self, parent=None):
        super(FileBrowserDock, self).__init__(parent)

        self.initDock("File Browser")

        # make sure icons are loaded
        Icons.load()

        # self.openFunction = openFunc

        # tree view
        self.fileTree = widgets.FileSystemTreeView()
        self.fileTree.set_root_path(os.getcwd())
        self.contextMenu = FileBrowserMenu()
        self.fileTree.set_context_menu(self.contextMenu)

        # enable drag and drop
        self.fileTree.setDragEnabled(True)
        self.fileTree.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.fileTree.viewport().setAcceptDrops(True)
        self.fileTree.setDropIndicatorShown(True)
        # To Do -- not use a private member --
        self.fileTree._fs_model_source.setReadOnly(False)
        self.fileTree.setEditTriggers(
            QtWidgets.QAbstractItemView.NoEditTriggers)
        self.fileTree.setDefaultDropAction(QtCore.Qt.MoveAction)

        # Folder button
        self.menuHLayout = QtWidgets.QHBoxLayout()
        self.menuHLayout.setContentsMargins(1, 1, 1, 1)
        self.menuHLayout.addStretch(1)
        self.menuBtn = QtWidgets.QPushButton(Icons.folder, "...", self)
        self.menuBtn.setFlat(True)
        self.menuBtn.setStyleSheet("background-color: "
                                   "rgba(255, 255, 255, 0);")
        self.menuHLayout.addWidget(self.menuBtn)
        self.menuVLayout = QtWidgets.QVBoxLayout()
        self.menuVLayout.setContentsMargins(1, 1, 1, 1)
        self.menuVLayout.addLayout(self.menuHLayout)
        self.menuVLayout.addStretch(1)
        self.fileTree.setLayout(self.menuVLayout)

        self.dirContextMenu = DirMenu()
        self.menuBtn.setMenu(self.dirContextMenu)

        self.dirContextMenu.parentDirAction.triggered.connect(
            self.onParentDirClicked)
        self.dirContextMenu.openDirAction.triggered.connect(
            self.onOpenDirClicked)

        # add everything to the dock
        self.contents = QtWidgets.QWidget()
        self.layout = QtWidgets.QGridLayout(self.contents)
        self.layout.addWidget(self.fileTree, 0, 0, 1, 1)
        self.setWidget(self.contents)

        self.fileTree.doubleClicked.connect(self.onOpenItem)
        self.contextMenu.OpenAction.triggered.connect(self.openFile)
        # self.contextMenu.pylintAction.triggered.connect(self.runPyLint)
        # self.hide()

    # global signal
    fileOpenRequest = QtCore.pyqtSignal(str)

    @QtCore.pyqtSlot()
    def openFile(self):
        """openFile() -- open selected file in editor."""
        if self.fileTree is not None:
            urls = self.fileTree.helper.selected_urls()
            # Open all selected files
            for u in urls:
                if os.path.isfile(u):  # make sure it is a file
                    self.fileOpenRequest.emit(u)

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def onOpenItem(self, index):
        """ onOpenItem(index)"""
        # if self.openFunction != None:
        filePath = self.fileTree.filePath(index)
        self.fileOpenRequest.emit(filePath)
        # self.openFunction(filePath)

    @QtCore.pyqtSlot()
    def onParentDirClicked(self):
        """ Move file browser root up to parent directory."""
        # There has to be a better way to do this
        # if not then shame on python
        path = utils.rectifyPath(self.fileTree.root_path)
        parPath = utils.getParentDir(path)
        if os.path.isdir(parPath):
            self.fileTree.set_root_path(parPath)

    @QtCore.pyqtSlot()
    def onOpenDirClicked(self):
        """ Open a new directory in the file browser"""
        # Open folder dialog -- only allow folders
        path = str(
            QtWidgets.QFileDialog.getExistingDirectory(
                self, "Select Directory", self.fileTree.root_path,
                QtWidgets.QFileDialog.ShowDirsOnly
                | QtWidgets.QFileDialog.DontUseNativeDialog))
        utils.rectifyPath(path)
        if os.path.isdir(path):
            self.fileTree.set_root_path(path)