Пример #1
0
class ConsoleWidget_embed(RichJupyterWidget, ConsoleWidget):
    global fit

    def __init__(self, customBanner=None, *args, **kwargs):
        super(ConsoleWidget_embed, self).__init__(*args, **kwargs)

        if customBanner is not None:
            self.banner = customBanner

        #self.font_size = 4
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel(show_banner=True)
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel = self.kernel_manager.kernel
        self.kernel_client = self._kernel_manager.client()
        self.kernel_client.start_channels()

        def _abort_queues(kernel):
            pass

        self.kernel_manager.kernel._abort_queues = _abort_queues

        #self._execute("kernel = %s"%fit, False)

        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()
            self.guisupport.get_app_qt().exit()

        self.exit_requested.connect(stop)

    def push_vars(self, variableDict):
        """
        Given a dictionary containing name / value pairs, push those variables
        to the Jupyter console widget
        """
        self.kernel_manager.kernel.shell.push(variableDict)

    def clear(self):
        """
        Clears the terminal
        """
        self._control.clear()

        # self.kernel_manager

    def print_text(self, text, before_prompt=True):
        """
        Prints some plain text to the console
        """
        self._append_plain_text(text, before_prompt=before_prompt)

    def execute_command(self, command):
        """
        Execute a command in the frame of the console widget
        """
        self._execute(command, False)
Пример #2
0
    class JupyterWidget(RichJupyterWidget):
        def __init__(self):
            super().__init__()

            if 'asyncio' in sys.modules:
                self._init_asyncio_patch()

            self.kernel_manager = QtInProcessKernelManager()
            self.kernel_manager.start_kernel()

            self.kernel_client = self.kernel_manager.client()
            self.kernel_client.start_channels()

            # Fix issue with Jupyter 5.0+, see https://github.com/ipython/ipykernel/pull/376
            if hasattr(self.kernel_manager.kernel, '_abort_queue'):
                # noinspection PyProtectedMember
                self.kernel_manager.kernel._abort_queues = self.kernel_manager.kernel._abort_queue

            self.exit_requested.connect(self.stop)
            qApp.aboutToQuit.connect(self.stop)

        def _init_asyncio_patch(self):
            """set default asyncio policy to be compatible with tornado
            Tornado 6 (at least) is not compatible with the default
            asyncio implementation on Windows
            Pick the older SelectorEventLoopPolicy on Windows
            if the known-incompatible default policy is in use.
            do this as early as possible to make it a low priority and overrideable
            ref: https://github.com/tornadoweb/tornado/issues/2608
            FIXME: if/when tornado supports the defaults in asyncio,
                   remove and bump tornado requirement for py38
            """
            if sys.platform.startswith("win") and sys.version_info >= (
                    3, 8) and tornado.version_info < (6, 1):
                import asyncio
                try:
                    from asyncio import (
                        WindowsProactorEventLoopPolicy,
                        WindowsSelectorEventLoopPolicy,
                    )
                except ImportError:
                    pass
                    # not affected
                else:
                    if type(asyncio.get_event_loop_policy()
                            ) is WindowsProactorEventLoopPolicy:
                        # WindowsProactorEventLoopPolicy is not compatible with tornado 6
                        # fallback to the pre-3.8 default of Selector
                        asyncio.set_event_loop_policy(
                            WindowsSelectorEventLoopPolicy())

        def stop(self):
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()

        def push(self, **kwargs):
            self.kernel_manager.kernel.shell.push(kwargs)
Пример #3
0
class IPythonPlugin(GUIPlugin):
    name = 'IPython'

    def __init__(self):
        # # Enforce global style within the console
        # with open('xicam/gui/style.stylesheet', 'r') as f:
        #     style = f.read()
        # style = (qdarkstyle.load_stylesheet() + style)

        # Setup the kernel
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        kernel = self.kernel_manager.kernel
        kernel.gui = 'qt'

        # Push Xi-cam variables into the kernel
        kernel.shell.push({
            plugin.name: plugin
            for plugin in pluginmanager.get_plugins_of_type("GUIPlugin") +
            pluginmanager.get_plugins_of_type("EZPlugin")
        })

        # Observe plugin changes
        pluginmanager.attach(self.pluginsChanged)

        # Continue kernel setuppluginmanager.getPluginsOfCategory("GUIPlugin")
        self.kernel_client = self.kernel_manager.client()
        threads.invoke_in_main_thread(self.kernel_client.start_channels)

        # Setup console widget
        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()

        control = RichJupyterWidget()
        control.kernel_manager = self.kernel_manager
        threads.invoke_in_main_thread(setattr, control, "kernel_client",
                                      self.kernel_client)
        control.exit_requested.connect(stop)
        # control.style_sheet = style
        control.syntax_style = u'monokai'
        control.set_default_style(colors='Linux')

        # Setup layout
        self.stages = {'Terminal': GUILayout(control)}

        # Save for later
        self.kernel = kernel

        super(IPythonPlugin, self).__init__()

    def pluginsChanged(self):
        self.kernel.shell.push({
            plugin.name: plugin
            for plugin in pluginmanager.get_plugins_of_type("GUIPlugin") +
            pluginmanager.get_plugins_of_type("EZPlugin")
        })
Пример #4
0
class Ipython(object):
    def __init__(self, scripts_path=''):
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        sys.stdout = self.kernel.stdout
        sys.stderr = self.kernel.stderr

        self.scripts_path = scripts_path
        self.kernel.gui = 'qt4'

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        self.control = RichJupyterWidget()
        self.control.kernel_manager = self.kernel_manager
        self.control.kernel_client = self.kernel_client
        self.control.exit_requested.connect(self.stop)

        self.control.setWindowTitle("IPython shell")

        self.execute('import numpy as np')
        self.execute('from matplotlib import pyplot as plt')
        self.execute('%matplotlib')
        self.execute('')

    def __del__(self):
        self.stop()
        self.close()

    def show(self):
        self.control.show()

        self.control.setWindowState(self.control.windowState()
                                    & ~QtCore.Qt.WindowMinimized
                                    | QtCore.Qt.WindowActive)
        self.control.activateWindow()

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def close(self):
        self.control.close()

    def push(self, vardic):
        self.kernel.shell.push(vardic)

    def execute(self, cmd):
        self.control.execute(cmd)

    def run_script(self, scriptname):
        scriptpath = os.path.join(self.scripts_path, scriptname)
        return self.control.execute('run -i %s' % scriptpath)
Пример #5
0
class IPythonView(RichJupyterWidget):
    """A view with an IPython console living in the same Python process as the GUI."""
    def __init__(self, *args, **kwargs):
        super(IPythonView, self).__init__(*args, **kwargs)

    def start_kernel(self):
        """Start the IPython kernel."""

        logger.debug("Starting the kernel.")

        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel(show_banner=False)
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel = self.kernel_manager.kernel
        self.shell = self.kernel.shell

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        self.set_default_style('linux')
        self.exit_requested.connect(self.stop)

    def inject(self, **kwargs):
        """Inject variables into the IPython namespace."""
        logger.debug("Injecting variables into the kernel: %s.",
                     ', '.join(kwargs.keys()))
        self.kernel.shell.push(kwargs)

    def attach(self, gui, **kwargs):
        """Add the view to the GUI, start the kernel, and inject the specified variables."""
        gui.add_view(self)
        self.start_kernel()
        self.inject(gui=gui, **kwargs)
        try:
            import numpy
            self.inject(np=numpy)
        except ImportError:  # pragma: no cover
            pass
        try:
            import matplotlib.pyplot as plt
            self.inject(plt=plt)
        except ImportError:  # pragma: no cover
            pass

        @connect
        def on_close_view(sender, view):
            if view == self:
                self.stop()

    def stop(self):
        """Stop the kernel."""
        logger.debug("Stopping the kernel.")
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
Пример #6
0
class IPythonConsole:
    def __init__(self, layout, sim, gui):
        # Create an in-process kernel
        # >>> print_process_id()
        # will print the same process ID as the main process
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        self.kernel.gui = 'qt4'

        self.kernel.shell.write("Welcome to AO Sim!")

        config = sim.config
        #Pass some useful objects to the user
        usefulObjects = {
            "sim": sim,
            "gui": gui,
            "config": config,
            "simConfig": sim.config.sim,
            "telConfig": sim.config.tel,
            "atmosConfig": sim.config.atmos
        }

        for i in range(sim.config.sim.nGS):
            usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i]
        for i in range(sim.config.sim.nDM):
            usefulObjects["dm{}Config".format(i)] = sim.config.dms[i]
        for i in range(sim.config.sim.nSci):
            usefulObjects["sci{}Config".format(i)] = sim.config.scis[i]

        self.kernel.shell.push(usefulObjects)
        #kernel.shell.push({'foo': 43, 'print_process_id': print_process_id})

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        control = RichIPythonWidget()
        control.kernel_manager = self.kernel_manager
        control.kernel_client = self.kernel_client
        control.exit_requested.connect(self.stop)
        layout.addWidget(control)

        self.kernel.shell.ex("")
        #control.show()

        #self.kernel.show
    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def write(self, message):
        self.kernel.shell.write(message)
        self.kernel.shell.ex("")
Пример #7
0
class ConsoleWidget(RichJupyterWidget):
    """
    Convenience class for a live IPython console widget.
    We can replace the standard banner using the customBanner argument
    """

    def __init__(self, customBanner=None, *args, **kwargs):
        RichJupyterWidget.__init__(self, *args, **kwargs)

        if customBanner is not None:
            self.banner = customBanner

        self.font_size = 6
        self.gui_completion = 'droplist'
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel(show_banner=False)
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel_client = kernel_client = self._kernel_manager.client()
        kernel_client.start_channels()

        def stop():
            kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()
            # guisupport.get_app_qt().exit()

        self.exit_requested.connect(stop)

    def push_vars(self, variableDict):
        """
        Given a dictionary containing name / value pairs, push those variables
        to the IPython console widget
        """
        self.kernel_manager.kernel.shell.push(variableDict)

    def clear(self):
        """
        Clears the terminal
        """
        self._control.clear()

        # self.kernel_manager

    def print_text(self, text):
        """
        Prints some plain text to the console
        """
        self._append_plain_text(text)

    def execute_command(self, command):
        """
        Execute a command in the frame of the console widget
        """
        self._execute(command, False)
Пример #8
0
class IPythonConsole:
    def __init__(self, layout, sim, gui):
        # Create an in-process kernel
        # >>> print_process_id()
        # will print the same process ID as the main process
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        self.kernel.gui = 'qt4'

        self.kernel.shell.write("Welcome to AO Sim!")

        config = sim.config
        #Pass some useful objects to the user
        usefulObjects = {    "sim" : sim,
                            "gui" : gui,
                            "config" : config,
                            "simConfig" : sim.config.sim,
                            "telConfig" : sim.config.tel,
                            "atmosConfig" : sim.config.atmos}

        for i in range(sim.config.sim.nGS):
            usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i]
        for i in range(sim.config.sim.nDM):
            usefulObjects["dm{}Config".format(i)] = sim.config.dms[i]
        for i in range(sim.config.sim.nSci):
            usefulObjects["sci{}Config".format(i)] = sim.config.scis[i]

        self.kernel.shell.push(usefulObjects)
        #kernel.shell.push({'foo': 43, 'print_process_id': print_process_id})

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()


        control = RichIPythonWidget()
        control.kernel_manager = self.kernel_manager
        control.kernel_client = self.kernel_client
        control.exit_requested.connect(self.stop)
        layout.addWidget(control)

        self.kernel.shell.ex("")
        #control.show()

        #self.kernel.show
    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def write(self,message):
        self.kernel.shell.write(message)
        self.kernel.shell.ex("")
Пример #9
0
class IPythonConsole:
    def __init__(self, layout, sim, gui):
        # Create an in-process kernel

        self.kernel_manager = QtInProcessKernelManager()
        # self.kernel_manager = QtKernelManager()
        self.kernel_manager.start_kernel()

        self.kernel = self.kernel_manager.kernel

        # self.kernel.shell.write("Welcome to AO Sim!\n")

        config = sim.config
        #Pass some useful objects to the user
        usefulObjects = {
            "sim": sim,
            "gui": gui,
            "config": config,
            "simConfig": sim.config.sim,
            "telConfig": sim.config.tel,
            "atmosConfig": sim.config.atmos,
            "np": numpy,
            "plt": pyplot
        }

        for i in range(sim.config.sim.nGS):
            usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i]
        for i in range(sim.config.sim.nDM):
            usefulObjects["dm{}Config".format(i)] = sim.config.dms[i]
        for i in range(sim.config.sim.nSci):
            usefulObjects["sci{}Config".format(i)] = sim.config.scis[i]

        self.kernel.shell.push(usefulObjects)

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        control = RichIPythonWidget()
        control.kernel_manager = self.kernel_manager
        control.kernel_client = self.kernel_client
        control.exit_requested.connect(self.stop)
        layout.addWidget(control)

        # self.kernel.shell.ex("")

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def write(self, message):
        pass
Пример #10
0
class ConsoleWidget(RichJupyterWidget):
    def __init__(self, *args, customBanner=None, myWidget=None, **kwargs):
        super(ConsoleWidget, self).__init__(*args, **kwargs)

        if customBanner is not None:
            self.banner = customBanner

        self.font_size = 6
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel(show_banner=False)
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel_client = self._kernel_manager.client()
        self.kernel_client.start_channels()

        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()

        self.exit_requested.connect(stop)

        self.kernel_manager.kernel.shell.push({
            'widget': self,
            'myWidget': myWidget
        })

    def push_vars(self, variableDict):
        """
        Given a dictionary containing name / value pairs, push those variables
        to the Jupyter console widget
        """
        self.kernel_manager.kernel.shell.push(variableDict)

    def clear(self):
        """
        Clears the terminal
        """
        self._control.clear()

        # self.kernel_manager

    def print_text(self, text):
        """
        Prints some plain text to the console
        """
        self._append_plain_text(text)

    def execute_command(self, command):
        """
        Execute a command in the frame of the console widget
        """
        self._execute(command, False)
Пример #11
0
class IPythonConsole:
    def __init__(self, layout, sim, gui):
        # Create an in-process kernel

        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel

        self.kernel.shell.write("Welcome to AO Sim!\n")

        config = sim.config
        #Pass some useful objects to the user
        usefulObjects = {    "sim" : sim,
                            "gui" : gui,
                            "config" : config,
                            "simConfig" : sim.config.sim,
                            "telConfig" : sim.config.tel,
                            "atmosConfig" : sim.config.atmos,
                            "np" : numpy,
                            "plt" : pyplot}

        for i in range(sim.config.sim.nGS):
            usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i]
        for i in range(sim.config.sim.nDM):
            usefulObjects["dm{}Config".format(i)] = sim.config.dms[i]
        for i in range(sim.config.sim.nSci):
            usefulObjects["sci{}Config".format(i)] = sim.config.scis[i]

        self.kernel.shell.push(usefulObjects)

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()


        control = RichIPythonWidget()
        control.kernel_manager = self.kernel_manager
        control.kernel_client = self.kernel_client
        control.exit_requested.connect(self.stop)
        layout.addWidget(control)

        self.kernel.shell.ex("")

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def write(self,message):
        self.kernel.shell.write(message)
        self.kernel.shell.ex("")
Пример #12
0
Файл: gui.py Проект: ufwt/hase
class MainWindow(form_class, QtWidgets.QMainWindow):
    def __init__(self, *args):
        super(MainWindow, self).__init__(*args)
        self.setupUi(self)
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        self.jupiter_widget.kernel_manager = self.kernel_manager
        self.jupiter_widget.kernel_client = self.kernel_client
        self.jupiter_widget.reset()

    def set_location(self, source_file, line):
        lexer = pygments.lexers.CppLexer()
        formatter = pygments.formatters.HtmlFormatter(
            linenos="inline", linespans="line", hl_lines=[line])
        css = formatter.get_style_defs('.highlight')
        with open(source_file) as f:
            tokens = lexer.get_tokens(f.read())
        source = pygments.format(tokens, formatter)
        self.code_view.setHtml(code_template.format(css, source))
        self.code_view.scrollToAnchor("line-%d" % max(0, line - 10))

    def setup_ipython(self, app, window):
        """
        Might break with future versions of IPython, but nobody got time for
        this!
        """
        shell = self.kernel_client.kernel.shell
        shell.magic("clear")
        user_ns = shell.user_ns
        user_ns["app"] = app
        user_ns["window"] = self
        config = shell.config
        config.TerminalIPythonApp.display_banner = ""
        shell.register_magics(commands(shell, app, window))

    def shutdown_kernel(self):
        print('Shutting down kernel...')
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
Пример #13
0
class NGSJupyterWidget(QtInProcessRichJupyterWidget):
    def __init__(self, gui,*args, **kwargs):
        import ngsolve
        super().__init__(*args,**kwargs)
        self.gui = gui
        self.banner = """NGSolve %s
Developed by Joachim Schoeberl at
2010-xxxx Vienna University of Technology
2006-2010 RWTH Aachen University
1996-2006 Johannes Kepler University Linz

""" % ngsolve.__version__
        multikernel_manager = gui.multikernel_manager
        if multikernel_manager is not None:
            self.kernel_id = multikernel_manager.start_kernel()
            self.kernel_manager = multikernel_manager.get_kernel(self.kernel_id)
        else:
            self.kernel_manager = QtInProcessKernelManager()
            self.kernel_manager.start_kernel()
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        class dummyioloop():
            def call_later(self,a,b):
                return
            def stop(self):
                return
        self.kernel_manager.kernel.io_loop = dummyioloop()

        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()
        self.exit_requested.connect(stop)

    @inmain_decorator(wait_for_return=True)
    def pushVariables(self, varDict):
        self.kernel_manager.kernel.shell.push(varDict)

    @inmain_decorator(wait_for_return=True)
    def clearTerminal(self):
        self._control.clear()
Пример #14
0
class IPythonDebugger(RichJupyterWidget):
    def __init__(self, widget: QWidget):
        super(IPythonDebugger, self).__init__()

        # Setup the kernel
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        kernel = self.kernel_manager.kernel
        kernel.gui = "qt"

        # Push QWidget to the console
        kernel.shell.push({"widget": widget})

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        # Setup console widget
        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()

        self.exit_requested.connect(stop)
Пример #15
0
class QIPythonWidget(RichJupyterWidget):
    def __init__(self, parent=None, custom_banner=None, **kwargs):
        super(QIPythonWidget, self).__init__(parent=parent, **kwargs)

        self.plugin = parent

        if custom_banner is not None:
            self.banner = custom_banner

        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel_manager.kernel.gui = 'qt'
        self.kernel_client = self._kernel_manager.client()
        self.kernel_client.start_channels()

        def stop():
            self.kernel_client.stop_channels()
            self.kernel_manager.shutdown_kernel()

        self.exit_requested.connect(stop)

    def push_variables(self, variableDict):
        """ Given a dictionary containing name / value pairs,
        push those variables to the IPython console widget """
        self.kernel_manager.kernel.shell.push(variableDict)

    def clear_terminal(self):
        """ Clears the terminal """
        self._control.clear()

    def print_text(self, text):
        """ Prints some plain text to the console """
        self._append_plain_text(text, True)

    def execute_command(self, command):
        """ Execute a command in the frame of the console widget """
        self._execute(command, False)
Пример #16
0
class ManagerGui(GUIBase):

    """This class provides a GUI to the Qudi manager.

      @signal sigStartAll: sent when all modules should be loaded
      @signal str str sigStartThis: load a specific module
      @signal str str sigReloadThis reload a specific module from Python code
      @signal str str sigStopThis: stop all actions of a module and remove
                                   references
      It supports module loading, reloading, logging and other
      administrative tasks.
    """

    # status vars
    consoleFontSize = StatusVar('console_font_size', 10)

    # signals
    sigStartAll = QtCore.Signal()
    sigStartModule = QtCore.Signal(str, str)
    sigReloadModule = QtCore.Signal(str, str)
    sigCleanupStatus = QtCore.Signal(str, str)
    sigStopModule = QtCore.Signal(str, str)
    sigLoadConfig = QtCore.Signal(str, bool)
    sigSaveConfig = QtCore.Signal(str)
    sigRealQuit = QtCore.Signal()

    def __init__(self, **kwargs):
        """Create an instance of the module.

          @param object manager:
          @param str name:
          @param dict config:
        """
        super().__init__(**kwargs)
        self.modlist = list()
        self.modules = set()

    def on_activate(self):
        """ Activation method called on change to active state.

        This method creates the Manager main window.
        """
        if _has_pyqtgraph:
            # set background of pyqtgraph
            testwidget = QWidget()
            testwidget.ensurePolished()
            bgcolor = testwidget.palette().color(QPalette.Normal,
                                                 testwidget.backgroundRole())
            # set manually the background color in hex code according to our
            # color scheme:
            pg.setConfigOption('background', bgcolor)

            # opengl usage
            if 'useOpenGL' in self._manager.tree['global']:
                pg.setConfigOption('useOpenGL',
                                   self._manager.tree['global']['useOpenGL'])
        self._mw = ManagerMainWindow()
        self.restoreWindowPos(self._mw)
        self.errorDialog = ErrorDialog(self)
        self._about = AboutDialog()
        version = self.getSoftwareVersion()
        configFile = self._manager.configFile
        self._about.label.setText(
            '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"'
            ' style=\"color: cyan;\"> {0} </a>, on branch {1}.'.format(
                version[0], version[1]))
        self.versionLabel = QtWidgets.QLabel()
        self.versionLabel.setText(
            '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"'
            ' style=\"color: cyan;\"> {0} </a>,'
            ' on branch {1}, configured from {2}'.format(
                version[0], version[1], configFile))
        self.versionLabel.setOpenExternalLinks(True)
        self._mw.statusBar().addWidget(self.versionLabel)
        # Connect up the buttons.
        self._mw.actionQuit.triggered.connect(self._manager.quit)
        self._mw.actionLoad_configuration.triggered.connect(self.getLoadFile)
        self._mw.actionReload_current_configuration.triggered.connect(self.reloadConfig)
        self._mw.actionSave_configuration.triggered.connect(self.getSaveFile)
        self._mw.action_Load_all_modules.triggered.connect(self._manager.startAllConfiguredModules)
        self._mw.actionAbout_Qt.triggered.connect(QtWidgets.QApplication.aboutQt)
        self._mw.actionAbout_Qudi.triggered.connect(self.showAboutQudi)
        self._mw.actionReset_to_default_layout.triggered.connect(self.resetToDefaultLayout)

        self._manager.sigShowManager.connect(self.show)
        self._manager.sigConfigChanged.connect(self.updateConfigWidgets)
        self._manager.sigModulesChanged.connect(self.updateConfigWidgets)
        self._manager.sigShutdownAcknowledge.connect(self.promptForShutdown)
        # Log widget
        self._mw.logwidget.setManager(self._manager)
        for loghandler in logging.getLogger().handlers:
            if isinstance(loghandler, core.logger.QtLogHandler):
                loghandler.sigLoggedMessage.connect(self.handleLogEntry)
        # Module widgets
        self.sigStartModule.connect(self._manager.startModule)
        self.sigReloadModule.connect(self._manager.restartModuleRecursive)
        self.sigCleanupStatus.connect(self._manager.removeStatusFile)
        self.sigStopModule.connect(self._manager.deactivateModule)
        self.sigLoadConfig.connect(self._manager.loadConfig)
        self.sigSaveConfig.connect(self._manager.saveConfig)
        self.sigRealQuit.connect(self._manager.realQuit)
        # Module state display
        self.checkTimer = QtCore.QTimer()
        self.checkTimer.start(1000)
        self.updateGUIModuleList()
        # IPython console widget
        self.startIPython()
        self.updateIPythonModuleList()
        self.startIPythonWidget()
        # thread widget
        self._mw.threadWidget.threadListView.setModel(self._manager.tm)
        # remote widget
        # hide remote menu item if rpyc is not available
        self._mw.actionRemoteView.setVisible(self._manager.rm is not None)
        if (self._manager.rm is not None):
            self._mw.remoteWidget.remoteModuleListView.setModel(self._manager.rm.remoteModules)
            if (self._manager.remote_server):
                self._mw.remoteWidget.hostLabel.setText('Server URL:')
                self._mw.remoteWidget.portLabel.setText(
                    'rpyc://{0}:{1}/'.format(self._manager.rm.server.host,
                                             self._manager.rm.server.port))
                self._mw.remoteWidget.sharedModuleListView.setModel(
                    self._manager.rm.sharedModules)
            else:
                self._mw.remoteWidget.hostLabel.setVisible(False)
                self._mw.remoteWidget.portLabel.setVisible(False)
                self._mw.remoteWidget.sharedModuleListView.setVisible(False)

        self._mw.configDisplayDockWidget.hide()
        self._mw.remoteDockWidget.hide()
        self._mw.threadDockWidget.hide()
        self._mw.show()

    def on_deactivate(self):
        """Close window and remove connections.
        """
        self.stopIPythonWidget()
        self.stopIPython()
        self.checkTimer.stop()
        if len(self.modlist) > 0:
            self.checkTimer.timeout.disconnect()
        self.sigStartModule.disconnect()
        self.sigReloadModule.disconnect()
        self.sigStopModule.disconnect()
        self.sigLoadConfig.disconnect()
        self.sigSaveConfig.disconnect()
        self._mw.actionQuit.triggered.disconnect()
        self._mw.actionLoad_configuration.triggered.disconnect()
        self._mw.actionSave_configuration.triggered.disconnect()
        self._mw.action_Load_all_modules.triggered.disconnect()
        self._mw.actionAbout_Qt.triggered.disconnect()
        self._mw.actionAbout_Qudi.triggered.disconnect()
        self.saveWindowPos(self._mw)
        self._mw.close()

    def show(self):
        """Show the window and bring it t the top.
        """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def showAboutQudi(self):
        """Show a dialog with details about Qudi.
        """
        self._about.show()

    @QtCore.Slot(bool, bool)
    def promptForShutdown(self, locked, broken):
        """ Display a dialog, asking the user to confirm shutdown. """
        text = "Some modules are locked right now, really quit?"
        result = QtWidgets.QMessageBox.question(
            self._mw,
            'Qudi: Really Quit?',
            text,
            QtWidgets.QMessageBox.Yes,
            QtWidgets.QMessageBox.No
        )
        if result == QtWidgets.QMessageBox.Yes:
            self.sigRealQuit.emit()

    def resetToDefaultLayout(self):
        """ Return the dockwidget layout and visibility to its default state """
        self._mw.configDisplayDockWidget.setVisible(False)
        self._mw.consoleDockWidget.setVisible(True)
        self._mw.remoteDockWidget.setVisible(False)
        self._mw.threadDockWidget.setVisible(False)
        self._mw.logDockWidget.setVisible(True)

        self._mw.actionConfigurationView.setChecked(False)
        self._mw.actionConsoleView.setChecked(True)
        self._mw.actionRemoteView.setChecked(False)
        self._mw.actionThreadsView.setChecked(False)
        self._mw.actionLogView.setChecked(True)

        self._mw.configDisplayDockWidget.setFloating(False)
        self._mw.consoleDockWidget.setFloating(False)
        self._mw.remoteDockWidget.setFloating(False)
        self._mw.threadDockWidget.setFloating(False)
        self._mw.logDockWidget.setFloating(False)

        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.configDisplayDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), self._mw.consoleDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.remoteDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.threadDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.logDockWidget)

    def handleLogEntry(self, entry):
        """ Forward log entry to log widget and show an error popup if it is
            an error message.

            @param dict entry: Log entry
        """
        self._mw.logwidget.addEntry(entry)
        if entry['level'] == 'error' or entry['level'] == 'critical':
            self.errorDialog.show(entry)

    def startIPython(self):
        """ Create an IPython kernel manager and kernel.
            Add modules to its namespace.
        """
        # make sure we only log errors and above from ipython
        logging.getLogger('ipykernel').setLevel(logging.WARNING)
        self.log.debug('IPy activation in thread {0}'.format(
            QtCore.QThread.currentThreadId()))
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        self.namespace = self.kernel.shell.user_ns
        self.namespace.update({
            'np': np,
            'config': self._manager.tree['defined'],
            'manager': self._manager
        })
        if _has_pyqtgraph:
            self.namespace['pg'] = pg
        self.updateIPythonModuleList()
        self.kernel.gui = 'qt4'
        self.log.info('IPython has kernel {0}'.format(
            self.kernel_manager.has_kernel))
        self.log.info('IPython kernel alive {0}'.format(
            self.kernel_manager.is_alive()))
        self._manager.sigModulesChanged.connect(self.updateIPythonModuleList)

    def startIPythonWidget(self):
        """ Create an IPython console widget and connect it to an IPython
        kernel.
        """
        if (_has_pyqtgraph):
            banner_modules = 'The numpy and pyqtgraph modules have already ' \
                             'been imported as ''np'' and ''pg''.'
        else:
            banner_modules = 'The numpy module has already been imported ' \
                             'as ''np''.'
        banner = """
This is an interactive IPython console. {0}
Configuration is in 'config', the manager is 'manager' and all loaded modules are in this namespace with their configured name.
View the current namespace with dir().
Go, play.
""".format(banner_modules)
        self._mw.consolewidget.banner = banner
        # font size
        self.consoleSetFontSize(self.consoleFontSize)
        # settings
        self._csd = ConsoleSettingsDialog()
        self._csd.accepted.connect(self.consoleApplySettings)
        self._csd.rejected.connect(self.consoleKeepSettings)
        self._csd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.consoleApplySettings)
        self._mw.actionConsoleSettings.triggered.connect(self._csd.exec_)
        self.consoleKeepSettings()

        self._mw.consolewidget.kernel_manager = self.kernel_manager
        self._mw.consolewidget.kernel_client = \
            self._mw.consolewidget.kernel_manager.client()
        self._mw.consolewidget.kernel_client.start_channels()
        # the linux style theme which is basically the monokai theme
        self._mw.consolewidget.set_default_style(colors='linux')

    def stopIPython(self):
        """ Stop the IPython kernel.
        """
        self.log.debug('IPy deactivation: {0}'.format(QtCore.QThread.currentThreadId()))
        self.kernel_manager.shutdown_kernel()

    def stopIPythonWidget(self):
        """ Disconnect the IPython widget from the kernel.
        """
        self._mw.consolewidget.kernel_client.stop_channels()

    def updateIPythonModuleList(self):
        """Remove non-existing modules from namespace,
            add new modules to namespace, update reloaded modules
        """
        currentModules = set()
        newNamespace = dict()
        for base in ['hardware', 'logic', 'gui']:
            for module in self._manager.tree['loaded'][base]:
                currentModules.add(module)
                newNamespace[module] = self._manager.tree[
                    'loaded'][base][module]
        discard = self.modules - currentModules
        self.namespace.update(newNamespace)
        for module in discard:
            self.namespace.pop(module, None)
        self.modules = currentModules

    def consoleKeepSettings(self):
        """ Write old values into config dialog.
        """
        self._csd.fontSizeBox.setProperty('value', self.consoleFontSize)

    def consoleApplySettings(self):
        """ Apply values from config dialog to console.
        """
        self.consoleSetFontSize(self._csd.fontSizeBox.value())

    def consoleSetFontSize(self, fontsize):
        self._mw.consolewidget.font_size = fontsize
        self.consoleFontSize = fontsize
        self._mw.consolewidget.reset_font()

    def updateConfigWidgets(self):
        """ Clear and refill the tree widget showing the configuration.
        """
        self.fillTreeWidget(self._mw.treeWidget, self._manager.tree)

    def updateGUIModuleList(self):
        """ Clear and refill the module list widget
        """
        # self.clearModuleList(self)
        self.fillModuleList(self._mw.guilayout, 'gui')
        self.fillModuleList(self._mw.logiclayout, 'logic')
        self.fillModuleList(self._mw.hwlayout, 'hardware')

    def fillModuleList(self, layout, base):
        """ Fill the module list widget with module widgets for defined gui
            modules.

          @param QLayout layout: layout of th module list widget where
                                 module widgest should be addad
          @param str base: module category to fill
        """
        for module in self._manager.tree['defined'][base]:
            if module not in self._manager.tree['global']['startup']:
                widget = ModuleListItem(self._manager, base, module)
                self.modlist.append(widget)
                layout.addWidget(widget)
                widget.sigLoadThis.connect(self.sigStartModule)
                widget.sigReloadThis.connect(self.sigReloadModule)
                widget.sigDeactivateThis.connect(self.sigStopModule)
                widget.sigCleanupStatus.connect(self.sigCleanupStatus)
                self.checkTimer.timeout.connect(widget.checkModuleState)

    def fillTreeItem(self, item, value):
        """ Recursively fill a QTreeWidgeItem with the contents from a
            dictionary.

          @param QTreeWidgetItem item: the widget item to fill
          @param (dict, list, etc) value: value to fill in
        """
        item.setExpanded(True)
        if type(value) is OrderedDict or type(value) is dict:
            for key in value:
                child = QtWidgets.QTreeWidgetItem()
                child.setText(0, key)
                item.addChild(child)
                self.fillTreeItem(child, value[key])
        elif type(value) is list:
            for val in value:
                child = QtWidgets.QTreeWidgetItem()
                item.addChild(child)
                if type(val) is dict:
                    child.setText(0, '[dict]')
                    self.fillTreeItem(child, val)
                elif type(val) is OrderedDict:
                    child.setText(0, '[odict]')
                    self.fillTreeItem(child, val)
                elif type(val) is list:
                    child.setText(0, '[list]')
                    self.fillTreeItem(child, val)
                else:
                    child.setText(0, str(val))
                child.setExpanded(True)
        else:
            child = QtWidgets.QTreeWidgetItem()
            child.setText(0, str(value))
            item.addChild(child)

    def getSoftwareVersion(self):
        """ Try to determine the software version in case the program is in
            a git repository.
        """
        try:
            repo = Repo(get_main_dir())
            branch = repo.active_branch
            rev = str(repo.head.commit)
            return (rev, str(branch))

        except Exception as e:
            print('Could not get git repo because:', e)
            return ('unknown', -1)

    def fillTreeWidget(self, widget, value):
        """ Fill a QTreeWidget with the content of a dictionary

          @param QTreeWidget widget: the tree widget to fill
          @param dict,OrderedDict value: the dictionary to fill in
        """
        widget.clear()
        self.fillTreeItem(widget.invisibleRootItem(), value)

    def reloadConfig(self):
        """  Reload the current config. """

        reply = QtWidgets.QMessageBox.question(
            self._mw,
            'Restart',
            'Do you want to restart the current configuration?',
            QtWidgets.QMessageBox.Yes,
            QtWidgets.QMessageBox.No
        )

        configFile = self._manager._getConfigFile()
        restart = (reply == QtWidgets.QMessageBox.Yes)
        self.sigLoadConfig.emit(configFile, restart)

    def getLoadFile(self):
        """ Ask the user for a file where the configuration should be loaded
            from
        """
        defaultconfigpath = os.path.join(get_main_dir(), 'config')
        filename = QtWidgets.QFileDialog.getOpenFileName(
            self._mw,
            'Load Configration',
            defaultconfigpath,
            'Configuration files (*.cfg)')[0]
        if filename != '':
            reply = QtWidgets.QMessageBox.question(
                self._mw,
                'Restart',
                'Do you want to restart to use the configuration?',
                QtWidgets.QMessageBox.Yes,
                QtWidgets.QMessageBox.No
            )
            restart = (reply == QtWidgets.QMessageBox.Yes)
            self.sigLoadConfig.emit(filename, restart)

    def getSaveFile(self):
        """ Ask the user for a file where the configuration should be saved
            to.
        """
        defaultconfigpath = os.path.join(get_main_dir(), 'config')
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self._mw,
            'Save Configration',
            defaultconfigpath,
            'Configuration files (*.cfg)')[0]
        if filename != '':
            self.sigSaveConfig.emit(filename)
Пример #17
0
class ManagerGui(GUIBase):
    """This class provides a GUI to the Qudi manager.

      @signal sigStartAll: sent when all modules should be loaded
      @signal str str sigStartThis: load a specific module
      @signal str str sigReloadThis reload a specific module from Python code
      @signal str str sigStopThis: stop all actions of a module and remove
                                   references
      It supports module loading, reloading, logging and other
      administrative tasks.
    """
    sigStartAll = QtCore.Signal()
    sigStartModule = QtCore.Signal(str, str)
    sigReloadModule = QtCore.Signal(str, str)
    sigCleanupStatus = QtCore.Signal(str, str)
    sigStopModule = QtCore.Signal(str, str)
    sigLoadConfig = QtCore.Signal(str, bool)
    sigSaveConfig = QtCore.Signal(str)

    def __init__(self, **kwargs):
        """Create an instance of the module.

          @param object manager:
          @param str name:
          @param dict config:
        """
        super().__init__(**kwargs)
        self.modlist = list()
        self.modules = set()

    def on_activate(self, e=None):
        """ Activation method called on change to active state.

        @param object e: Fysom.event object from Fysom class.
                         An object created by the state machine module Fysom,
                         which is connected to a specific event (have a look
                         in the Base Class). This object contains the passed
                         event, the state before the event happened and the
                         destination of the state which should be reached
                         after the event had happened.

        This method creates the Manager main window.
        """
        if _has_pyqtgraph:
            # set background of pyqtgraph
            testwidget = QWidget()
            testwidget.ensurePolished()
            bgcolor = testwidget.palette().color(QPalette.Normal,
                                                 testwidget.backgroundRole())
            # set manually the background color in hex code according to our
            # color scheme:
            pg.setConfigOption('background', bgcolor)

            # opengl usage
            if 'useOpenGL' in self._manager.tree['global']:
                pg.setConfigOption('useOpenGL',
                                   self._manager.tree['global']['useOpenGL'])
        self._mw = ManagerMainWindow()
        self.restoreWindowPos(self._mw)
        self.errorDialog = ErrorDialog(self)
        self._about = AboutDialog()
        version = self.getSoftwareVersion()
        configFile = self._manager.configFile
        self._about.label.setText(
            '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"'
            ' style=\"color: cyan;\"> {0} </a>, on branch {1}.'.format(
                version[0], version[1]))
        self.versionLabel = QtWidgets.QLabel()
        self.versionLabel.setText(
            '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"'
            ' style=\"color: cyan;\"> {0} </a>,'
            ' on branch {1}, configured from {2}'.format(
                version[0], version[1], configFile))
        self.versionLabel.setOpenExternalLinks(True)
        self._mw.statusBar().addWidget(self.versionLabel)
        # Connect up the buttons.
        self._mw.actionQuit.triggered.connect(self._manager.quit)
        self._mw.actionLoad_configuration.triggered.connect(self.getLoadFile)
        self._mw.actionReload_current_configuration.triggered.connect(self.reloadConfig)
        self._mw.actionSave_configuration.triggered.connect(self.getSaveFile)
        self._mw.action_Load_all_modules.triggered.connect(self._manager.startAllConfiguredModules)
        self._mw.actionAbout_Qt.triggered.connect(QtWidgets.QApplication.aboutQt)
        self._mw.actionAbout_Qudi.triggered.connect(self.showAboutQudi)
        self._mw.actionReset_to_default_layout.triggered.connect(self.resetToDefaultLayout)

        self._manager.sigShowManager.connect(self.show)
        self._manager.sigConfigChanged.connect(self.updateConfigWidgets)
        self._manager.sigModulesChanged.connect(self.updateConfigWidgets)
        # Log widget
        self._mw.logwidget.setManager(self._manager)
        for loghandler in logging.getLogger().handlers:
            if isinstance(loghandler, core.logger.QtLogHandler):
                loghandler.sigLoggedMessage.connect(self.handleLogEntry)
        # Module widgets
        self.sigStartModule.connect(self._manager.startModule)
        self.sigReloadModule.connect(self._manager.restartModuleSimple)
        self.sigCleanupStatus.connect(self._manager.removeStatusFile)
        self.sigStopModule.connect(self._manager.deactivateModule)
        self.sigLoadConfig.connect(self._manager.loadConfig)
        self.sigSaveConfig.connect(self._manager.saveConfig)
        # Module state display
        self.checkTimer = QtCore.QTimer()
        self.checkTimer.start(1000)
        self.updateGUIModuleList()
        # IPython console widget
        self.startIPython()
        self.updateIPythonModuleList()
        self.startIPythonWidget()
        # thread widget
        self._mw.threadWidget.threadListView.setModel(self._manager.tm)
        # remote widget
        self._mw.remoteWidget.hostLabel.setText('URL:')
        self._mw.remoteWidget.portLabel.setText(
            'rpyc://{0}:{1}/'.format(self._manager.rm.host,
                                     self._manager.rm.server.port))
        self._mw.remoteWidget.remoteModuleListView.setModel(
            self._manager.rm.remoteModules)
        self._mw.remoteWidget.sharedModuleListView.setModel(
            self._manager.rm.sharedModules)

        self._mw.configDisplayDockWidget.hide()
        self._mw.remoteDockWidget.hide()
        self._mw.threadDockWidget.hide()
        self._mw.show()

    def on_deactivate(self, e):
        """Close window and remove connections.

        @param object e: Fysom.event object from Fysom class. A more detailed
                         explanation can be found in the method activation.
        """
        self.stopIPythonWidget()
        self.stopIPython()
        self.checkTimer.stop()
        if len(self.modlist) > 0:
            self.checkTimer.timeout.disconnect()
        self.sigStartModule.disconnect()
        self.sigReloadModule.disconnect()
        self.sigStopModule.disconnect()
        self.sigLoadConfig.disconnect()
        self.sigSaveConfig.disconnect()
        self._mw.actionQuit.triggered.disconnect()
        self._mw.actionLoad_configuration.triggered.disconnect()
        self._mw.actionSave_configuration.triggered.disconnect()
        self._mw.action_Load_all_modules.triggered.disconnect()
        self._mw.actionAbout_Qt.triggered.disconnect()
        self._mw.actionAbout_Qudi.triggered.disconnect()
        self.saveWindowPos(self._mw)
        self._mw.close()

    def show(self):
        """Show the window and bring it t the top.
        """
        QtWidgets.QMainWindow.show(self._mw)
        self._mw.activateWindow()
        self._mw.raise_()

    def showAboutQudi(self):
        """Show a dialog with details about Qudi.
        """
        self._about.show()

    def resetToDefaultLayout(self):
        """ Return the dockwidget layout and visibility to its default state """
        self._mw.configDisplayDockWidget.setVisible(False)
        self._mw.consoleDockWidget.setVisible(True)
        self._mw.remoteDockWidget.setVisible(False)
        self._mw.threadDockWidget.setVisible(False)
        self._mw.logDockWidget.setVisible(True)

        self._mw.actionConfigurationView.setChecked(False)
        self._mw.actionConsoleView.setChecked(True)
        self._mw.actionRemoteView.setChecked(False)
        self._mw.actionThreadsView.setChecked(False)
        self._mw.actionLogView.setChecked(True)

        self._mw.configDisplayDockWidget.setFloating(False)
        self._mw.consoleDockWidget.setFloating(False)
        self._mw.remoteDockWidget.setFloating(False)
        self._mw.threadDockWidget.setFloating(False)
        self._mw.logDockWidget.setFloating(False)

        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.configDisplayDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), self._mw.consoleDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.remoteDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.threadDockWidget)
        self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.logDockWidget)

    def handleLogEntry(self, entry):
        """ Forward log entry to log widget and show an error popup if it is
            an error message.

            @param dict entry: Log entry
        """
        self._mw.logwidget.addEntry(entry)
        if entry['level'] == 'error' or entry['level'] == 'critical':
            self.errorDialog.show(entry)

    def startIPython(self):
        """ Create an IPython kernel manager and kernel.
            Add modules to its namespace.
        """
        # make sure we only log errors and above from ipython
        logging.getLogger('ipykernel').setLevel(logging.WARNING)
        self.log.debug('IPy activation in thread {0}'.format(
            QtCore.QThread.currentThreadId()))
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        self.namespace = self.kernel.shell.user_ns
        self.namespace.update({
            'np': np,
            'config': self._manager.tree['defined'],
            'manager': self._manager
        })
        if _has_pyqtgraph:
            self.namespace['pg'] = pg
        self.updateIPythonModuleList()
        self.kernel.gui = 'qt4'
        self.log.info('IPython has kernel {0}'.format(
            self.kernel_manager.has_kernel))
        self.log.info('IPython kernel alive {0}'.format(
            self.kernel_manager.is_alive()))
        self._manager.sigModulesChanged.connect(self.updateIPythonModuleList)

    def startIPythonWidget(self):
        """ Create an IPython console widget and connect it to an IPython
        kernel.
        """
        if (_has_pyqtgraph):
            banner_modules = 'The numpy and pyqtgraph modules have already ' \
                             'been imported as ''np'' and ''pg''.'
        else:
            banner_modules = 'The numpy module has already been imported ' \
                             'as ''np''.'
        banner = """
This is an interactive IPython console. {0}
Configuration is in 'config', the manager is 'manager' and all loaded modules are in this namespace with their configured name.
View the current namespace with dir().
Go, play.
""".format(banner_modules)
        self._mw.consolewidget.banner = banner
        # font size
        if 'console_font_size' in self._statusVariables:
            self.consoleSetFontSize(self._statusVariables['console_font_size'])
        # settings
        self._csd = ConsoleSettingsDialog()
        self._csd.accepted.connect(self.consoleApplySettings)
        self._csd.rejected.connect(self.consoleKeepSettings)
        self._csd.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(
                self.consoleApplySettings)
        self._mw.actionConsoleSettings.triggered.connect(self._csd.exec_)
        self.consoleKeepSettings()

        self._mw.consolewidget.kernel_manager = self.kernel_manager
        self._mw.consolewidget.kernel_client = \
            self._mw.consolewidget.kernel_manager.client()
        self._mw.consolewidget.kernel_client.start_channels()
        # the linux style theme which is basically the monokai theme
        self._mw.consolewidget.set_default_style(colors='linux')

    def stopIPython(self):
        """ Stop the IPython kernel.
        """
        self.log.debug('IPy deactivation: {0}'.format(QtCore.QThread.currentThreadId()))
        self.kernel_manager.shutdown_kernel()

    def stopIPythonWidget(self):
        """ Disconnect the IPython widget from the kernel.
        """
        self._mw.consolewidget.kernel_client.stop_channels()

    def updateIPythonModuleList(self):
        """Remove non-existing modules from namespace,
            add new modules to namespace, update reloaded modules
        """
        currentModules = set()
        newNamespace = dict()
        for base in ['hardware', 'logic', 'gui']:
            for module in self._manager.tree['loaded'][base]:
                currentModules.add(module)
                newNamespace[module] = self._manager.tree[
                    'loaded'][base][module]
        discard = self.modules - currentModules
        self.namespace.update(newNamespace)
        for module in discard:
            self.namespace.pop(module, None)
        self.modules = currentModules

    def consoleKeepSettings(self):
        """ Write old values into config dialog.
        """
        if 'console_font_size' in self._statusVariables:
            self._csd.fontSizeBox.setProperty(
                'value', self._statusVariables['console_font_size'])
        else:
            self._csd.fontSizeBox.setProperty('value', 10)

    def consoleApplySettings(self):
        """ Apply values from config dialog to console.
        """
        self.consoleSetFontSize(self._csd.fontSizeBox.value())

    def consoleSetFontSize(self, fontsize):
        self._mw.consolewidget.font_size = fontsize
        self._statusVariables['console_font_size'] = fontsize
        self._mw.consolewidget.reset_font()

    def updateConfigWidgets(self):
        """ Clear and refill the tree widget showing the configuration.
        """
        self.fillTreeWidget(self._mw.treeWidget, self._manager.tree)

    def updateGUIModuleList(self):
        """ Clear and refill the module list widget
        """
        # self.clearModuleList(self)
        self.fillModuleList(self._mw.guilayout, 'gui')
        self.fillModuleList(self._mw.logiclayout, 'logic')
        self.fillModuleList(self._mw.hwlayout, 'hardware')

    def fillModuleList(self, layout, base):
        """ Fill the module list widget with module widgets for defined gui
            modules.

          @param QLayout layout: layout of th module list widget where
                                 module widgest should be addad
          @param str base: module category to fill
        """
        for module in self._manager.tree['defined'][base]:
            if not module in self._manager.tree['global']['startup']:
                widget = ModuleListItem(self._manager, base, module)
                self.modlist.append(widget)
                layout.addWidget(widget)
                widget.sigLoadThis.connect(self.sigStartModule)
                widget.sigReloadThis.connect(self.sigReloadModule)
                widget.sigDeactivateThis.connect(self.sigStopModule)
                widget.sigCleanupStatus.connect(self.sigCleanupStatus)
                self.checkTimer.timeout.connect(widget.checkModuleState)

    def fillTreeItem(self, item, value):
        """ Recursively fill a QTreeWidgeItem with the contents from a
            dictionary.

          @param QTreeWidgetItem item: the widget item to fill
          @param (dict, list, etc) value: value to fill in
        """
        item.setExpanded(True)
        if type(value) is OrderedDict or type(value) is dict:
            for key in value:
                child = QtWidgets.QTreeWidgetItem()
                child.setText(0, key)
                item.addChild(child)
                self.fillTreeItem(child, value[key])
        elif type(value) is list:
            for val in value:
                child = QtWidgets.QTreeWidgetItem()
                item.addChild(child)
                if type(val) is dict:
                    child.setText(0, '[dict]')
                    self.fillTreeItem(child, val)
                elif type(val) is OrderedDict:
                    child.setText(0, '[odict]')
                    self.fillTreeItem(child, val)
                elif type(val) is list:
                    child.setText(0, '[list]')
                    self.fillTreeItem(child, val)
                else:
                    child.setText(0, str(val))
                child.setExpanded(True)
        else:
            child = QtWidgets.QTreeWidgetItem()
            child.setText(0, str(value))
            item.addChild(child)

    def getSoftwareVersion(self):
        """ Try to determine the software version in case the program is in
            a git repository.
        """
        try:
            repo = Repo(self.get_main_dir())
            branch = repo.active_branch
            rev = str(repo.head.commit)
            return (rev, str(branch))

        except Exception as e:
            print('Could not get git repo because:', e)
            return ('unknown', -1)

    def fillTreeWidget(self, widget, value):
        """ Fill a QTreeWidget with the content of a dictionary

          @param QTreeWidget widget: the tree widget to fill
          @param dict,OrderedDict value: the dictionary to fill in
        """
        widget.clear()
        self.fillTreeItem(widget.invisibleRootItem(), value)

    def reloadConfig(self):
        """  Reload the current config. """

        reply = QtWidgets.QMessageBox.question(
            self._mw,
            'Restart',
            'Do you want to restart the current configuration?',
            QtWidgets.QMessageBox.Yes,
            QtWidgets.QMessageBox.No
        )

        configFile = self._manager._getConfigFile()
        restart = (reply == QtWidgets.QMessageBox.Yes)
        self.sigLoadConfig.emit(configFile, restart)

    def getLoadFile(self):
        """ Ask the user for a file where the configuration should be loaded
            from
        """
        defaultconfigpath = os.path.join(self.get_main_dir(), 'config')
        filename = QtWidgets.QFileDialog.getOpenFileName(
            self._mw,
            'Load Configration',
            defaultconfigpath,
            'Configuration files (*.cfg)')
        if filename != '':
            reply = QtWidgets.QMessageBox.question(
                self._mw,
                'Restart',
                'Do you want to restart to use the configuration?',
                QtWidgets.QMessageBox.Yes,
                QtWidgets.QMessageBox.No
            )
            restart = (reply == QtWidgets.QMessageBox.Yes)
            self.sigLoadConfig.emit(filename, restart)

    def getSaveFile(self):
        """ Ask the user for a file where the configuration should be saved
            to.
        """
        defaultconfigpath = os.path.join(self.get_main_dir(), 'config')
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self._mw,
            'Save Configration',
            defaultconfigpath,
            'Configuration files (*.cfg)')
        if filename != '':
            self.sigSaveConfig.emit(filename)
Пример #18
0
from qtconsole.inprocess import QtInProcessKernelManager
from IPython import get_ipython

# Check if there is an ipython shell
shell = get_ipython()
assert shell == None

# Start in process kernel manager and client
kernel_manager = QtInProcessKernelManager()
kernel_manager.start_kernel(show_banner=False)
kernel_manager.kernel.gui = 'qt'
kernel_client = kernel_manager.client()
kernel_client.start_channels()

# Shutdown kernel manager and client
kernel_client.stop_channels()
kernel_manager.shutdown_kernel()

# Check there is no longer an ipython shell
shell = get_ipython()
assert shell == None
Пример #19
0
class ConsoleWidget(QtGui.QWidget):
    createdPlot = QtCore.Signal(object)
    updatedVar = QtCore.Signal()

    def __init__(self, parent=None):
        super(ConsoleWidget, self).__init__()
        self.variable_list = get_variables()
        self.vbox = QtGui.QVBoxLayout()
        self.setLayout(self.vbox)
        self.kernel_manager = None
        self.kernel_client = None
        self.kernel = None
        self.jupyter_widget = None
        self.values = []
        self.display_plots = []
        self.shell_vars = {}
        self.gm_count = {}
        self.letters = list(string.ascii_uppercase)
        self.reserved_words = [
            'and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or',
            'with', 'assert', 'else', 'if', 'pass', 'yield', 'break', 'except',
            'import', 'print', 'class', 'exec', 'in', 'raise', 'continue',
            'finally', 'is', 'return', 'def', 'for', 'lambda', 'try'
        ]

        # Create ipython widget
        self.kernel_manager = QtInProcessKernelManager()

        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        self.kernel_client.execute("import vcs, cdms2", silent=True)

        self.jupyter_widget = RichJupyterWidget()
        self.jupyter_widget.kernel_manager = self.kernel_manager
        self.jupyter_widget.kernel_client = self.kernel_client
        self.jupyter_widget.exit_requested.connect(self.stop)
        self.jupyter_widget.executed.connect(self.codeExecuted)
        self.original_ns = dict(self.kernel.shell.user_ns)

        # Push variableList variables
        self.variable_list.listUpdated.connect(self.updateVariables)
        self.updateVariables()

        self.vbox.addWidget(self.jupyter_widget)

    def clearShellVars(self):
        self.gm_count = {}
        for key, var_dict in self.shell_vars.items():
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['canvas'])
            except KeyError:
                pass
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['gm'])
            except KeyError:
                pass
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['template'])
            except KeyError:
                pass

        for var in self.values:
            self.values.remove(var)
            try:
                self.kernel.shell.user_ns.pop(var)
            except KeyError:
                pass

    def updateVariables(self, plot=None):
        for var in get_variables().values:
            if var[0] not in self.values:
                self.values.append(var[0])
            self.kernel.shell.push({var[0]: var[1]})
        if plot and plot.variables:
            for var in plot.variables:
                try:
                    self.kernel.shell.push({var.id: var})
                except AttributeError:
                    pass

    def updateCanvases(self, plot):
        canvas_var_label = "canvas_{0}{1}".format(plot.row + 1,
                                                  self.letters[plot.col])
        self.shell_vars[plot]['canvas'] = canvas_var_label
        self.kernel.shell.push({canvas_var_label: plot.canvas})

    def updateGMS(self, plot):
        if plot.graphics_method:
            gm = plot.graphics_method.name
            if gm[:2] == '__':
                gm_prefix = vcs.graphicsmethodtype(plot.graphics_method)
                gm_prefix = self.fixInvalidVariables(gm_prefix)
                if gm_prefix not in self.gm_count.keys():
                    self.gm_count[gm_prefix] = 1
                else:
                    self.gm_count[gm_prefix] += 1
                gm = "{0}_{1}".format(gm_prefix, self.gm_count[gm_prefix])
            else:
                gm = self.fixInvalidVariables(gm)
            if gm == 'default':
                "{0}_default".format(
                    vcs.graphicsmethodtype(plot.graphics_method))
            self.shell_vars[plot]['gm'] = gm
            self.kernel.shell.push({gm: plot.graphics_method})

    def updateTemplates(self, plot):
        if plot.template:
            tmp = plot.template.name
            tmp = self.fixInvalidVariables(tmp)
            if tmp == 'default':
                tmp = 'temp_default'
            self.shell_vars[plot]['template'] = tmp
            self.kernel.shell.push({tmp: plot.template})

    def updateAllPlots(self, plots):
        self.clearShellVars()
        for plot in plots:
            self.shell_vars[plot] = {'canvas': '', 'template': '', 'gm': ''}
            if plot.name() != "(Untitled)":
                self.updateVariables(plot)
                self.updateCanvases(plot)
                self.updateGMS(plot)
                self.updateTemplates(plot)
            else:
                self.updateVariables(plot)
                self.updateCanvases(plot)

    def codeExecuted(self, *varargs):
        namespace = self.kernel.shell.user_ns
        cur_keys = set(namespace)

        # get last output
        out_dict = namespace["Out"]
        if out_dict:
            last_line = out_dict[max(out_dict)]
        else:
            last_line = None
        for key in cur_keys - set(self.original_ns):
            if key[0] == "_":
                continue
            value = namespace[key]

            if isinstance(value, cdms2.dataset.CdmsFile):
                namespace[key] = FileMetadataWrapper(value)

            if is_cdms_var(value):
                cdms_var = value()
                cdms_var.id = key
                if not self.variable_list.variable_exists(cdms_var):
                    self.variable_list.add_variable(cdms_var)
                else:
                    self.variable_list.update_variable(cdms_var, key)
                    self.updatedVar.emit()

            elif is_displayplot(value) and value not in self.display_plots:
                self.display_plots.append(value)
                self.createdPlot.emit(value)

        if is_displayplot(last_line) and last_line not in self.display_plots:
            self.display_plots.append(last_line)
            self.createdPlot.emit(last_line)

    def fixInvalidVariables(self, var):
        var = re.sub(' +', '_', var)
        var = re.sub("[^a-zA-Z0-9_]+", '', var)
        if var in self.reserved_words or not re.match("^[a-zA-Z_]", var):
            var = 'cdat_' + var
        return var

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
        app.exit()
Пример #20
0
class ConsoleWidget(QtGui.QWidget):
    createdPlot = QtCore.Signal(object)
    updatedVar = QtCore.Signal()

    def __init__(self, parent=None):
        super(ConsoleWidget, self).__init__()
        self.variable_list = get_variables()
        self.vbox = QtGui.QVBoxLayout()
        self.setLayout(self.vbox)
        self.kernel_manager = None
        self.kernel_client = None
        self.kernel = None
        self.jupyter_widget = None
        self.values = []
        self.display_plots = []
        self.shell_vars = {}
        self.gm_count = {}
        self.letters = list(string.ascii_uppercase)
        self.reserved_words = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or', 'with',
                               'assert', 'else', 'if', 'pass', 'yield', 'break', 'except', 'import', 'print', 'class',
                               'exec', 'in', 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for', 'lambda',
                               'try']

        # Create ipython widget
        self.kernel_manager = QtInProcessKernelManager()

        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        self.kernel_client.execute("import vcs, cdms2", silent=True)

        self.jupyter_widget = RichJupyterWidget()
        self.jupyter_widget.kernel_manager = self.kernel_manager
        self.jupyter_widget.kernel_client = self.kernel_client
        self.jupyter_widget.exit_requested.connect(self.stop)
        self.jupyter_widget.executed.connect(self.codeExecuted)
        self.original_ns = dict(self.kernel.shell.user_ns)

        # Push variableList variables
        self.variable_list.listUpdated.connect(self.updateVariables)
        self.updateVariables()

        self.vbox.addWidget(self.jupyter_widget)

    def clearShellVars(self):
        self.gm_count = {}
        for key, var_dict in self.shell_vars.items():
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['canvas'])
            except KeyError:
                pass
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['gm'])
            except KeyError:
                pass
            try:
                self.kernel.shell.user_ns.pop(self.shell_vars[key]['template'])
            except KeyError:
                pass

        for var in self.values:
            self.values.remove(var)
            try:
                self.kernel.shell.user_ns.pop(var)
            except KeyError:
                pass

    def updateVariables(self, plot=None):
        for var in get_variables().values:
            if var[0] not in self.values:
                self.values.append(var[0])
            self.kernel.shell.push({var[0]: var[1]})
        if plot and plot.variables:
            for var in plot.variables:
                try:
                    self.kernel.shell.push({var.id: var})
                except AttributeError:
                    pass

    def updateCanvases(self, plot):
        canvas_var_label = "canvas_{0}{1}".format(plot.row + 1, self.letters[plot.col])
        self.shell_vars[plot]['canvas'] = canvas_var_label
        self.kernel.shell.push({canvas_var_label: plot.canvas})

    def updateGMS(self, plot):
        if plot.graphics_method:
            gm = plot.graphics_method.name
            if gm[:2] == '__':
                gm_prefix = vcs.graphicsmethodtype(plot.graphics_method)
                gm_prefix = self.fixInvalidVariables(gm_prefix)
                if gm_prefix not in self.gm_count.keys():
                    self.gm_count[gm_prefix] = 1
                else:
                    self.gm_count[gm_prefix] += 1
                gm = "{0}_{1}".format(gm_prefix, self.gm_count[gm_prefix])
            else:
                gm = self.fixInvalidVariables(gm)
            if gm == 'default':
                "{0}_default".format(vcs.graphicsmethodtype(plot.graphics_method))
            self.shell_vars[plot]['gm'] = gm
            self.kernel.shell.push({gm: plot.graphics_method})

    def updateTemplates(self, plot):
        if plot.template:
            tmp = plot.template.name
            tmp = self.fixInvalidVariables(tmp)
            if tmp == 'default':
                tmp = 'temp_default'
            self.shell_vars[plot]['template'] = tmp
            self.kernel.shell.push({tmp: plot.template})

    def updateAllPlots(self, plots):
        self.clearShellVars()
        for plot in plots:
            self.shell_vars[plot] = {'canvas': '', 'template': '', 'gm': ''}
            if plot.name() != "(Untitled)":
                self.updateVariables(plot)
                self.updateCanvases(plot)
                self.updateGMS(plot)
                self.updateTemplates(plot)
            else:
                self.updateVariables(plot)
                self.updateCanvases(plot)

    def codeExecuted(self, *varargs):
        namespace = self.kernel.shell.user_ns
        cur_keys = set(namespace)

        # get last output
        out_dict = namespace["Out"]
        if out_dict:
            last_line = out_dict[max(out_dict)]
        else:
            last_line = None
        for key in cur_keys - set(self.original_ns):
            if key[0] == "_":
                continue
            value = namespace[key]

            if isinstance(value, cdms2.dataset.CdmsFile):
                namespace[key] = FileMetadataWrapper(value)

            if is_cdms_var(value):
                cdms_var = value()
                cdms_var.id = key
                if not self.variable_list.variable_exists(cdms_var):
                    self.variable_list.add_variable(cdms_var)
                else:
                    self.variable_list.update_variable(cdms_var, key)
                    self.updatedVar.emit()

            elif is_displayplot(value) and value not in self.display_plots:
                self.display_plots.append(value)
                self.createdPlot.emit(value)

        if is_displayplot(last_line) and last_line not in self.display_plots:
            self.display_plots.append(last_line)
            self.createdPlot.emit(last_line)

    def fixInvalidVariables(self, var):
        var = re.sub(' +', '_', var)
        var = re.sub("[^a-zA-Z0-9_]+", '', var)
        if var in self.reserved_words or not re.match("^[a-zA-Z_]", var):
            var = 'cdat_' + var
        return var

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
        app.exit()
Пример #21
0
class QIPythonWidget(RichJupyterWidget):
    def __init__(self,
                 customBanner=None,
                 colors='lightbg',
                 baseimport=None,
                 *args,
                 **kwargs):
        """Convenience class for a live IPython console widget.
        Adapted from the pyQT example

        Attributes:
            banner (str): banner on top of the console
            kernel_client (kernel_manager.client): client for the kernel
            kernel_manager (QtInProcessKernelManager): kernel manager

        Args:
            customBanner (str, optional): Custom banner
            colors (str, optional): Colorschem for the console: lightbg,linux,nocolor
            *args: Description
            **kwargs: Description
        """
        super(QIPythonWidget, self).__init__(*args, **kwargs)

        if not customBanner is None:
            self.banner = customBanner

        # create an Inprocess kernel
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel_manager.kernel.gui = 'qt4'

        self.kernel_client = self._kernel_manager.client()
        self.kernel_client.start_channels()

        # set the colorscheme
        self.set_default_style(colors=colors)

        # exectute the base import
        if baseimport is not None:
            if os.path.isfile(baseimport):
                with open(baseimport, 'r') as f:
                    cmd = f.readlines()
                cmd = ''.join(cmd)
                try:
                    self._execute(cmd, False)
                except:
                    self.printText('Import of %s failed' % baseimport)

        self.exit_requested.connect(self.stop)

    def pushVariables(self, variableDict):
        """ Given a dictionary containing name / value pairs,
        push those variables to the IPython console widget

        Args:
            variableDict: dict of var {names: value}

        """
        self.kernel_manager.kernel.shell.push(variableDict)

    def clearTerminal(self):
        """ Clears the terminal """
        self._control.clear()

    def printText(self, text):
        """ Prints some plain text to the console.

        Args:
            text (str): text to be printed

        """
        self._append_plain_text(text)

    def executeCommand(self, command, hidden=False, interactive=False):
        """Execute a command in the frame of the console widget

        Args:
            command (str): Command to execute
            hidden (bool, optional): hid the command or not
            interactive (bool, optional): Interactive Mode
        """
        self.execute(source=command, hidden=hidden, interactive=interactive)

    def import_value(self, HDF5Object):
        """Import the value of a HDF5 object

        Args:
            HDF5Object (HDF5 item): Instance of a HDF5 item
        """
        HDF5Object.emitDict.connect(self.get_value)

    @pyqtSlot(dict)
    def get_value(self, variableDict):
        """Get the dict of variables emmitted by the treeview.
        Note: if the name of variable starts with _ the value is NOT
        printed in the console.

        Args:
            variableDict (dict): dict of variables {name: value}
        """
        # exectute a command
        keys = list(variableDict.keys())
        if keys[0].startswith('exec_cmd'):
            for k, cmd in variableDict.items():
                self._execute(cmd, False)

        # push a variable in the console
        # print it if the name doesnt start with _
        else:
            self.pushVariables(variableDict)
            for k in variableDict:
                if not k.startswith('_'):
                    self.executeCommand('%s' % k)

    def stop():
        """Stop the kernel."""
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
        guisupport.get_app_qt4().exit()
Пример #22
0
class MainWindow(form_class, QtWidgets.QMainWindow):
    def __init__(self, *args):
        super(MainWindow, self).__init__(*args)
        self.setupUi(self)
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        self.jupiter_widget.kernel_manager = self.kernel_manager
        self.jupiter_widget.kernel_client = self.kernel_client
        self.jupiter_widget.reset()

        self.reg_view.setColumnCount(2)
        self.reg_view.setHorizontalHeaderLabels(['Name', 'Value'])

        self.var_view.setColumnCount(4)
        self.var_view.setHorizontalHeaderLabels(
            ['Name', 'Type', 'Address', 'Value'])

        # NOTE: icons are from Google Material Design
        self.up_button.setIcon(
            QIcon(str(APP_ROOT.join('frontend/icon/up.png'))))
        self.up_button.setIconSize(QSize(15, 15))
        self.up_button.clicked.connect(self.push_up)
        self.up_button.setEnabled(False)

        self.upto_button.setIcon(
            QIcon(str(APP_ROOT.join('frontend/icon/upto.png'))))
        self.upto_button.setIconSize(QSize(15, 15))
        self.upto_button.clicked.connect(self.push_upto)
        self.upto_button.setEnabled(False)

        self.down_button.setIcon(
            QIcon(str(APP_ROOT.join('frontend/icon/down.png'))))
        self.down_button.setIconSize(QSize(15, 15))
        self.down_button.clicked.connect(self.push_down)
        self.down_button.setEnabled(False)

        self.downto_button.setIcon(
            QIcon(str(APP_ROOT.join('frontend/icon/downto.png'))))
        self.downto_button.setIconSize(QSize(15, 15))
        self.downto_button.clicked.connect(self.push_downto)
        self.downto_button.setEnabled(False)

        self.cg_button.clicked.connect(self.push_callgraph)
        self.cg_button.setEnabled(False)

        self.info_button.clicked.connect(self.push_info)
        self.info_button.setEnabled(False)

        self.switch_button.clicked.connect(self.push_switch)
        self.switch_button.setEnabled(False)

        self.time_slider.setEnabled(False)

        self.file_cache = {}
        self.file_read_cache = {}
        self.callgraph = CallGraphManager()

        self.coredump_constraints = []

    def cache_coredump_constraints(self):
        user_ns = self.kernel_client.kernel.shell.user_ns
        tracer = user_ns['tracer']
        start_state = tracer.start_state
        active_state = self.states.major_states[-1]
        coredump = user_ns['coredump']
        low = active_state.simstate.regs.rsp
        MAX_FUNC_FRAME = 0x200
        high = start_state.regs.rsp + MAX_FUNC_FRAME

        try:
            low_v = active_state.simstate.se.eval(low)
        except:
            # very large range
            low_v = coredump.stack.start
        try:
            high_v = start_state.se.eval(high)
        except:
            high_v = coredump.stack.stop

        for addr in range(low_v, high_v):
            value = active_state.simstate.memory.load(addr,
                                                      1,
                                                      endness='Iend_LE')
            if value.variables == frozenset():
                continue
            cmem = coredump.stack[addr]
            self.coredump_constraints.append(value == cmem)

    def eval_variable(self, active_state, loc, addr, size):
        # type: (Any, int, Any, int) -> Tuple[str, str]
        # NOTE: * -> uninitialized / 'E' -> symbolic
        if not getattr(active_state, 'had_coredump_constraints', False):
            for c in self.coredump_constraints:
                old_solver = active_state.simstate.solver._solver.branch()
                active_state.simstate.se.add(c)
                if not active_state.simstate.se.satisfiable():
                    print('Unsatisfiable coredump constraints: ' + str(c))
                    active_state.simstate.solver._stored_solver = old_solver
            active_state.had_coredump_constraints = True

        if loc == 1:
            mem = active_state.simstate.memory.load(addr,
                                                    size,
                                                    endness='Iend_LE')
        elif loc == 2:
            mem = getattr(active_state.simstate.regs, addr)
        elif loc == -1:
            return 'optimized', 'unknown'
        else:
            return 'gdb error', 'unknown'
        if mem.uninitialized and mem.variables != frozenset() and loc == 1:
            result = ''
            for i in range(size):
                value = active_state.simstate.memory.load(addr + i,
                                                          1,
                                                          endness='Iend_LE')
                if value.uninitialized:
                    result += '** '
                    continue
                try:
                    v = hex(active_state.simstate.se.eval(value))[2:]
                    if len(v) == 1:
                        v = '0' + v
                except:
                    v = 'Er'
                result += v + ' '
            result = result[:-1]
            return result, 'array'
        else:
            v = self.eval_value(active_state, mem)
            if v == 'uninitialized' or v == 'symbolic':
                return v, 'unknown'
            return v, 'hex'

    def eval_value(self, active_state, value):
        # type: (Any, Any) -> str
        if value.uninitialized:
            return 'uninitialized'
        try:
            v = hex(active_state.simstate.se.eval(value))
        except:
            v = 'symbolic'
        return v

    def update_active(self, new_active):
        # type: (Any) -> None
        user_ns = self.kernel_client.kernel.shell.user_ns
        user_ns['active_state'] = new_active
        user_ns['gdbs'].active_state = new_active
        # NOTE: gdb c for every operation is slow
        # user_ns['gdbs'].update_active()
        addr = new_active.address()
        self.set_location(*self.addr_map[addr])

    def update_active_index(self, active_index):
        # type: (int) -> None
        new_state, is_new = self.states[active_index]
        user_ns = self.kernel_client.kernel.shell.user_ns
        if is_new:
            self.callgraph.add_node(new_state, user_ns['tracer'])
        major_index = self.states.major_index
        if active_index in major_index:
            slider_index = len(major_index) - major_index.index(
                active_index) - 1
            self.time_slider.setValue(slider_index)
        self.update_active(new_state)

    def push_upto(self):
        # type: () -> None
        v = self.time_slider.value()
        self.time_slider.setValue(min(self.time_slider.maximum(), v + 1))
        self.slider_change()

    def push_downto(self):
        # type: () -> None
        v = self.time_slider.value()
        self.time_slider.setValue(max(self.time_slider.minimum(), v - 1))
        self.slider_change()

    def push_up(self):
        # type: () -> None
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns['active_state']
        state_index = max(0, active_state.index - 1)
        self.update_active_index(state_index)

    def push_down(self):
        # type: () -> None
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns['active_state']
        tracer = user_ns['tracer']
        state_index = min(len(tracer.trace) - 1, active_state.index + 1)
        self.update_active_index(state_index)

    def push_callgraph(self):
        # type: () -> None
        self.view = CallGraphView(self.callgraph, self)

    def push_info(self):
        # type: () -> None
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns['active_state']
        self.set_regs()
        user_ns['gdbs'].update_active()
        if self.addr_map[active_state.address()][0] != '??':
            user_ns['gdbs'].write_request('bt')
            self.set_variable()
        else:
            print("Cannot retrieve variables on unresolvable source code")

    def push_switch(self):
        # type: () -> None
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns['active_state']
        active_state.is_to_simstate = not active_state.is_to_simstate
        self.update_active(active_state)

    def slider_change(self):
        # type: () -> None
        v = self.time_slider.value()
        new_active = self.states.get_major(-(v + 1))
        self.update_active(new_active)

    def set_slider(self, addr_map, states):
        # type: (List[Union[str, int]], Any) -> None
        # NOTE: slider is for major states
        self.addr_map = addr_map
        self.states = states
        self.time_slider.setEnabled(True)
        self.time_slider.setMinimum(0)
        self.time_slider.setMaximum(states.len_major - 1)
        self.time_slider.setTickPosition(QtWidgets.QSlider.TicksLeft)
        self.time_slider.setTickInterval(states.len_major - 1)
        self.time_slider.setValue(0)
        self.time_slider.valueChanged.connect(self.slider_change)

    def set_location(self, source_file, line):
        # type: (str, int) -> None
        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        active_state = user_ns['active_state']
        insns = active_state.simstate.block().capstone.insns
        # fmt = QTextCharFormat()
        # fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline)
        if source_file != '??':
            css, source = self.file_cache[source_file][line]
            if css:
                self.code_view.setHtml(
                    code_template.format(css, source.encode('utf-8')))
                cursor = self.code_view.textCursor()
                cursor.movePosition(QTextCursor.Start)
                minl = max(0, line - 30)
                if self.file_read_cache[source_file][2]:
                    cursor.movePosition(QTextCursor.Down, n=line - minl - 1)
                else:
                    cursor.movePosition(QTextCursor.Down, n=line - 1)
                cursor.movePosition(QTextCursor.EndOfLine)
                cursor.insertText('\t' + str(insns[0]))
                if not self.file_read_cache[source_file][2]:
                    self.code_view.scrollToAnchor("line-%d" %
                                                  max(0, line - 10))
                else:
                    self.code_view.scrollToAnchor("line-%d" %
                                                  max(0, line - minl - 10))
            else:
                self.code_view.clear()
                self.code_view.append("{}:{}".format(source_file, line))
        else:
            self.code_view.clear()
            self.code_view.append("Unresolved source code")
            for insn in insns:
                self.code_view.append('\t' + str(insn))

    def set_variable(self):
        # type: () -> None
        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        var = user_ns['gdbs'].read_variables()
        self.var_view.setRowCount(0)
        i = 0
        for v in var:
            if v['loc'] != -2:
                self.var_view.insertRow(i)
                value, value_type = self.eval_variable(user_ns['active_state'],
                                                       v['loc'], v['addr'],
                                                       v['size'])
                self.var_view.set_var(i, v, value, value_type)
                i += 1
        self.var_view.resizeColumnsToContents()

    def set_regs(self):
        # type: () -> None
        def fix_new_regname(rname):
            # HACK: angr has no access to register like r9w, r8d, r15b
            for i in range(8, 16):
                if 'r' + str(i) in rname:
                    return 'r' + str(i)
            return rname

        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        active_state = user_ns['active_state']
        insns = active_state.simstate.block().capstone.insns
        insn = insns[0].insn
        self.reg_view.setRowCount(0)
        for op in insn.operands:
            # OP_REG
            if op.type == 1:
                rname = insn.reg_name(op.value.reg)
                rname = fix_new_regname(rname)
                value = self.eval_value(
                    active_state, getattr(active_state.simstate.regs, rname))
                self.reg_view.append_reg(rname, value)
            # OP_MEM
            elif op.type == 3:
                if op.value.mem.base:
                    rname = insn.reg_name(op.value.mem.base)
                    rname = fix_new_regname(rname)
                    value = self.eval_value(
                        active_state, getattr(active_state.simstate.regs,
                                              rname))
                    self.reg_view.append_reg(rname, value)
                if op.value.mem.index:
                    rname = insn.reg_name(op.value.mem.index)
                    rname = fix_new_regname(rname)
                    value = self.eval_value(
                        active_state, getattr(active_state.simstate.regs,
                                              rname))
                    self.reg_view.append_reg(rname, value)
        self.reg_view.resizeColumnsToContents()

    def setup_ipython(self, app, window):
        # type: (QtWidgets.QApplication, MainWindow) -> None
        """
        Might break with future versions of IPython, but nobody got time for
        this!
        """
        shell = self.kernel_client.kernel.shell
        shell.magic("clear")
        user_ns = shell.user_ns
        user_ns["app"] = app
        user_ns["window"] = self
        config = shell.config
        config.TerminalIPythonApp.display_banner = ""
        from . import ipython_extension
        shell.extension_manager.load_extension(ipython_extension.__name__)

    def cache_tokens(self, addr_map):
        for filename, line in addr_map.values():
            l.warning('caching file: ' + str(filename) + ' at line: ' +
                      str(line))
            if filename != '??':
                if filename not in self.file_read_cache.keys():
                    self.file_cache[filename] = {}
                    self.file_read_cache[filename] = {}
                    try:
                        lexer = pygments.lexers.get_lexer_for_filename(
                            str(filename))
                        formatter_opts = dict(linenos="inline",
                                              linespans="line",
                                              hl_lines=[line])
                        html_formatter = pygments.formatters.get_formatter_by_name(
                            "html", **formatter_opts)
                        css = html_formatter.get_style_defs('.highlight')
                        with open(str(filename)) as f:
                            content = f.readlines()
                        if len(content) < 1000:
                            content = ''.join(content)
                            tokens = lexer.get_tokens(content)
                            source = pygments.format(tokens, html_formatter)
                            self.file_cache[filename][line] = (css, source)
                            self.file_read_cache[filename] = (lexer, content,
                                                              False)
                        else:
                            minl = max(0, line - 30)
                            maxl = min(len(content), line + 30)
                            formatter_opts = dict(linenos="inline",
                                                  linespans="line",
                                                  hl_lines=[line])
                            html_formatter = pygments.formatters.get_formatter_by_name(
                                "html", **formatter_opts)
                            css = html_formatter.get_style_defs('.highlight')
                            source = pygments.format(
                                lexer.get_tokens(''.join(content[minl:maxl])),
                                html_formatter)
                            self.file_cache[filename][line] = (css, source)
                            self.file_read_cache[filename] = (lexer, content,
                                                              True)
                    except Exception as e:
                        print(e)
                        self.file_cache[filename][line] = (None, None)
                        self.file_read_cache[filename] = (None, None, False)
                else:
                    lexer, content, is_largefile = self.file_read_cache[
                        filename]
                    if content:
                        try:
                            if not is_largefile:
                                formatter_opts = dict(linenos="inline",
                                                      linespans="line",
                                                      hl_lines=[line])
                                html_formatter = pygments.formatters.get_formatter_by_name(
                                    "html", **formatter_opts)
                                css = html_formatter.get_style_defs(
                                    '.highlight')
                                source = pygments.format(
                                    lexer.get_tokens(content), html_formatter)
                                self.file_cache[filename][line] = (css, source)
                            else:
                                minl = max(0, line - 30)
                                maxl = min(len(content), line + 30)
                                formatter_opts = dict(linenos="inline",
                                                      linespans="line",
                                                      hl_lines=[line - minl])
                                html_formatter = pygments.formatters.get_formatter_by_name(
                                    "html", **formatter_opts)
                                css = html_formatter.get_style_defs(
                                    '.highlight')
                                source = pygments.format(
                                    lexer.get_tokens(''.join(
                                        content[minl:maxl])), html_formatter)
                                self.file_cache[filename][line] = (css, source)
                        except Exception as e:
                            print(e)
                            self.file_cache[filename][line] = (None, None)
                    else:
                        self.file_cache[filename][line] = (None, None)

    def add_states(self, states, tracer):
        # type: (Any, Any) -> None
        for s in states.major_states[1:]:
            self.callgraph.add_node(s, tracer)

    def clear_viewer(self):
        # type: () -> None
        self.code_view.clear()

    def append_archive(self):
        # type: () -> None
        files = DEFAULT_LOG_DIR.listdir()
        files.sort()
        self.code_view.append("\nAvailable files:")
        for f in files:
            if str(f.basename()).endswith(".tar.gz"):
                self.code_view.append(str(f.basename()))

    def enable_buttons(self):
        # type: () -> None
        # TODO: maintain a button list
        self.up_button.setEnabled(True)
        self.upto_button.setEnabled(True)
        self.down_button.setEnabled(True)
        self.downto_button.setEnabled(True)
        self.cg_button.setEnabled(True)
        self.info_button.setEnabled(True)
        self.switch_button.setEnabled(True)

    def clear_cache(self):
        self.file_cache = {}
        self.coredump_constraints = []
        self.callgraph.clear_cache()

    def shutdown_kernel(self):
        # type: () -> None
        print('Shutting down kernel...')
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()
Пример #23
0
class MainWindow(form_class, QtWidgets.QMainWindow):
    def __init__(self, *args: Any) -> None:
        super(MainWindow, self).__init__(*args)
        self.setupUi(self)
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()
        self.jupiter_widget.kernel_manager = self.kernel_manager
        self.jupiter_widget.kernel_client = self.kernel_client
        self.jupiter_widget.reset()

        self.reg_view.setColumnCount(2)
        self.reg_view.setHorizontalHeaderLabels(["Name", "Value"])

        self.var_view.setColumnCount(4)
        self.var_view.setHorizontalHeaderLabels(
            ["Name", "Type", "Address", "Value"])

        # NOTE: icons are from Google Material Design
        self.up_button.setIcon(
            QIcon(str(APP_ROOT.joinpath("frontend/icon/up.png"))))
        self.up_button.setIconSize(QSize(15, 15))
        self.up_button.clicked.connect(self.push_up)
        self.up_button.setEnabled(False)

        self.upto_button.setIcon(
            QIcon(str(APP_ROOT.joinpath("frontend/icon/upto.png"))))
        self.upto_button.setIconSize(QSize(15, 15))
        self.upto_button.clicked.connect(self.push_upto)
        self.upto_button.setEnabled(False)

        self.down_button.setIcon(
            QIcon(str(APP_ROOT.joinpath("frontend/icon/down.png"))))
        self.down_button.setIconSize(QSize(15, 15))
        self.down_button.clicked.connect(self.push_down)
        self.down_button.setEnabled(False)

        self.downto_button.setIcon(
            QIcon(str(APP_ROOT.joinpath("frontend/icon/downto.png"))))
        self.downto_button.setIconSize(QSize(15, 15))
        self.downto_button.clicked.connect(self.push_downto)
        self.downto_button.setEnabled(False)

        self.cg_button.clicked.connect(self.push_callgraph)
        self.cg_button.setEnabled(False)

        self.info_button.clicked.connect(self.push_info)
        self.info_button.setEnabled(False)

        self.switch_button.clicked.connect(self.push_switch)
        self.switch_button.setEnabled(False)

        self.time_slider.setEnabled(False)

        self.file_cache = (
            DefaultDict(dict)
        )  # type: DefaultDict[str, Dict[int, Tuple[Optional[str], Optional[str]]]]
        self.file_read_cache = (
            {}
        )  # type: Dict[str, Tuple[Optional[RegexLexer], Optional[Union[str, List[str]]], bool]]
        # self.callgraph = CallGraphManager()

        self.coredump_constraints = []  # type:List[claripy.ast.bool.Bool]

    def cache_coredump_constraints(self) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        tracer = user_ns["tracer"]
        start_state = tracer.start_state
        active_state = self.states.major_states[-1]
        coredump = user_ns["coredump"]
        low = active_state.simstate.regs.rsp
        MAX_FUNC_FRAME = 0x200
        high = start_state.regs.rsp + MAX_FUNC_FRAME

        try:
            low_v = active_state.simstate.solver.eval(low)
        except Exception:
            # very large range
            low_v = coredump.stack.start
        try:
            high_v = start_state.solver.eval(high)
        except Exception:
            high_v = coredump.stack.stop

        for addr in range(low_v, high_v):
            value = active_state.simstate.memory.load(addr,
                                                      1,
                                                      endness="Iend_LE")
            if value.variables == frozenset():
                continue
            cmem = coredump.stack[addr]
            self.coredump_constraints.append(value == cmem)

    def eval_variable(self, active_state: State, loc: int, addr: Any,
                      size: int) -> Tuple[str, str]:
        # NOTE: * -> uninitialized / 'E' -> symbolic
        if not active_state.had_coredump_constraints:
            for c in self.coredump_constraints:
                old_solver = active_state.simstate.solver._solver.branch()
                active_state.simstate.solver.add(c)
                if not active_state.simstate.solver.satisfiable():
                    print("Unsatisfiable coredump constraints: {}".format(c))
                    active_state.simstate.solver._stored_solver = old_solver
            active_state.had_coredump_constraints = True

        if loc == 1:
            mem = active_state.simstate.memory.load(addr,
                                                    size,
                                                    endness="Iend_LE")
        elif loc == 2:
            mem = getattr(active_state.simstate.regs, addr)
        elif loc == -1:
            return "optimized", "unknown"
        else:
            return "gdb error", "unknown"
        if mem.uninitialized and mem.variables != frozenset() and loc == 1:
            result = ""
            for i in range(size):
                value = active_state.simstate.memory.load(addr + i,
                                                          1,
                                                          endness="Iend_LE")
                if value.uninitialized:
                    result += "** "
                    continue
                try:
                    v = hex(active_state.simstate.solver.eval(value))[2:]
                    if len(v) == 1:
                        v = "0" + v
                except Exception:
                    v = "Er"
                result += v + " "
            result = result[:-1]
            return result, "array"
        else:
            v = self.eval_value(active_state, mem)
            if v == "uninitialized" or v == "symbolic":
                return v, "unknown"
            return v, "hex"

    def eval_value(self, active_state: State, value: Any) -> str:
        if value.uninitialized:
            return "uninitialized"
        try:
            v = hex(active_state.simstate.solver.eval(value))
        except Exception:
            v = "symbolic"
        return v

    def update_active(self, new_active: State) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        user_ns["active_state"] = new_active
        user_ns["gdbs"].active_state = new_active
        # NOTE: gdb c for every operation is slow
        # user_ns['gdbs'].update_active()
        addr = new_active.address()
        source_file, line = self.addr_map[addr]
        self.set_location(source_file, line)

    def update_active_index(self, active_index: int) -> None:
        new_state, is_new = self.states[active_index]
        # user_ns = self.kernel_client.kernel.shell.user_ns
        if is_new:
            # self.callgraph.add_node(new_state, user_ns['tracer'])
            pass
        major_index = self.states.major_index
        if active_index in major_index:
            slider_index = len(major_index) - major_index.index(
                active_index) - 1
            self.time_slider.setValue(slider_index)
        self.update_active(new_state)

    def push_upto(self) -> None:
        v = self.time_slider.value()
        self.time_slider.setValue(min(self.time_slider.maximum(), v + 1))
        self.slider_change()

    def push_downto(self) -> None:
        v = self.time_slider.value()
        self.time_slider.setValue(max(self.time_slider.minimum(), v - 1))
        self.slider_change()

    def push_up(self) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns["active_state"]
        state_index = max(0, active_state.index - 1)
        self.update_active_index(state_index)

    def push_down(self) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns["active_state"]
        tracer = user_ns["tracer"]
        state_index = min(len(tracer.trace) - 1, active_state.index + 1)
        self.update_active_index(state_index)

    def push_callgraph(self) -> None:
        pass
        # self.view = CallGraphView(self.callgraph, self)

    def push_info(self) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns["active_state"]
        self.set_regs()
        user_ns["gdbs"].update_active()
        if self.addr_map[active_state.address()][0] != "??":
            user_ns["gdbs"].write_request("bt")
            self.set_variable()
        else:
            print("Cannot retrieve variables on unresolvable source code")

    def push_switch(self) -> None:
        user_ns = self.kernel_client.kernel.shell.user_ns
        active_state = user_ns["active_state"]
        active_state.is_to_simstate = not active_state.is_to_simstate
        self.update_active(active_state)

    def slider_change(self) -> None:
        v = self.time_slider.value()
        new_active = self.states.get_major(-(v + 1))
        self.update_active(new_active)

    def set_slider(self, addr_map: List[Tuple[str, int]],
                   states: StateManager) -> None:
        # NOTE: slider is for major states
        self.addr_map = addr_map
        self.states = states
        self.time_slider.setEnabled(True)
        self.time_slider.setMinimum(0)
        self.time_slider.setMaximum(states.len_major - 1)
        self.time_slider.setTickPosition(QtWidgets.QSlider.TicksLeft)
        self.time_slider.setTickInterval(states.len_major - 1)
        self.time_slider.setValue(0)
        self.time_slider.valueChanged.connect(self.slider_change)

    def set_location(self, source_file: str, line: int) -> None:
        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        active_state = user_ns["active_state"]
        insns = active_state.simstate.block().capstone.insns
        # fmt = QTextCharFormat()
        # fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline)
        if source_file != "??":
            css, source = self.file_cache[source_file][line]
            if css and source:
                self.code_view.setHtml(code_template.format(css, source))
                cursor = self.code_view.textCursor()
                cursor.movePosition(QTextCursor.Start)
                minl = max(0, line - 30)
                if self.file_read_cache[source_file][2]:
                    cursor.movePosition(QTextCursor.Down, n=line - minl - 1)
                else:
                    cursor.movePosition(QTextCursor.Down, n=line - 1)
                cursor.movePosition(QTextCursor.EndOfLine)
                cursor.insertText("\t" + str(insns[0]))
                if not self.file_read_cache[source_file][2]:
                    self.code_view.scrollToAnchor("line-%d" %
                                                  max(0, line - 10))
                else:
                    self.code_view.scrollToAnchor("line-%d" %
                                                  max(0, line - minl - 10))
            else:
                self.code_view.clear()
                self.code_view.append("{}:{}".format(source_file, line))
        else:
            self.code_view.clear()
            self.code_view.append("Unresolved source code")
            for insn in insns:
                self.code_view.append("\t" + str(insn))

    def set_variable(self) -> None:
        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        var = user_ns["gdbs"].read_variables()
        self.var_view.setRowCount(0)
        i = 0
        for v in var:
            if v["loc"] != -2:
                self.var_view.insertRow(i)
                value, value_type = self.eval_variable(user_ns["active_state"],
                                                       v["loc"], v["addr"],
                                                       v["size"])
                self.var_view.set_var(i, v, value, value_type)
                i += 1
        self.var_view.resizeColumnsToContents()

    def set_regs(self) -> None:
        def fix_new_regname(rname: str) -> str:
            # HACK: angr has no access to register like r9w, r8d, r15b
            for i in range(8, 16):
                if "r" + str(i) in rname:
                    return "r" + str(i)
            return rname

        shell = self.kernel_client.kernel.shell
        user_ns = shell.user_ns
        active_state = user_ns["active_state"]
        insns = active_state.simstate.block().capstone.insns
        insn = insns[0].insn
        self.reg_view.setRowCount(0)
        for op in insn.operands:
            # OP_REG
            if op.type == 1:
                rname = insn.reg_name(op.value.reg)
                rname = fix_new_regname(rname)
                value = self.eval_value(
                    active_state, getattr(active_state.simstate.regs, rname))
                self.reg_view.append_reg(rname, value)
            # OP_MEM
            elif op.type == 3:
                if op.value.mem.base:
                    rname = insn.reg_name(op.value.mem.base)
                    rname = fix_new_regname(rname)
                    value = self.eval_value(
                        active_state, getattr(active_state.simstate.regs,
                                              rname))
                    self.reg_view.append_reg(rname, value)
                if op.value.mem.index:
                    rname = insn.reg_name(op.value.mem.index)
                    rname = fix_new_regname(rname)
                    value = self.eval_value(
                        active_state, getattr(active_state.simstate.regs,
                                              rname))
                    self.reg_view.append_reg(rname, value)
        self.reg_view.resizeColumnsToContents()

    def setup_ipython(self, app: QtWidgets.QApplication,
                      window: "MainWindow") -> None:
        """
        Might break with future versions of IPython, but nobody got time for
        this!
        """
        shell = self.kernel_client.kernel.shell
        shell.magic("clear")
        user_ns = shell.user_ns
        user_ns["app"] = app
        user_ns["window"] = self
        config = shell.config
        config.TerminalIPythonApp.display_banner = ""
        from . import ipython_extension

        shell.extension_manager.load_extension(ipython_extension.__name__)

    def fill_read_cache(self, filename: str, line: int) -> None:
        try:
            lexer = pygments.lexers.get_lexer_for_filename(
                str(filename))  # type: RegexLexer
            formatter_opts = dict(linenos="inline",
                                  linespans="line",
                                  hl_lines=[line])
            html_formatter = pygments.formatters.get_formatter_by_name(
                "html", **formatter_opts)
            css = html_formatter.get_style_defs(".highlight")
            with open(str(filename)) as f:
                lines = f.readlines()
            if len(lines) < 1000:
                content = "".join(lines)
                tokens = lexer.get_tokens(content)
                source = pygments.format(tokens, html_formatter)
                self.file_cache[filename][line] = (css, source)
                self.file_read_cache[filename] = (lexer, content, False)
            else:
                minl = max(0, line - 30)
                maxl = min(len(lines), line + 30)
                formatter_opts = dict(linenos="inline",
                                      linespans="line",
                                      hl_lines=[line])
                html_formatter = pygments.formatters.get_formatter_by_name(
                    "html", **formatter_opts)
                css = html_formatter.get_style_defs(".highlight")
                source = pygments.format(
                    lexer.get_tokens("".join(lines[minl:maxl])),
                    html_formatter)
                self.file_cache[filename][line] = (css, source)
                self.file_read_cache[filename] = (lexer, lines, True)
        except Exception as e:
            l.exception(e)
            self.file_cache[filename][line] = (None, None)
            self.file_read_cache[filename] = (None, None, False)

    def fill_file_cache(self, filename: str, line: int) -> None:
        lexer, content, is_largefile = self.file_read_cache[filename]
        if lexer and content:
            try:
                if not is_largefile:
                    formatter_opts = dict(linenos="inline",
                                          linespans="line",
                                          hl_lines=[line])
                    html_formatter = pygments.formatters.get_formatter_by_name(
                        "html", **formatter_opts)
                    css = html_formatter.get_style_defs(".highlight")
                    source = pygments.format(lexer.get_tokens(content),
                                             html_formatter)
                    self.file_cache[filename][line] = (css, source)
                else:
                    minl = max(0, line - 30)
                    maxl = min(len(content), line + 30)
                    formatter_opts = dict(linenos="inline",
                                          linespans="line",
                                          hl_lines=[line - minl])
                    html_formatter = pygments.formatters.get_formatter_by_name(
                        "html", **formatter_opts)
                    css = html_formatter.get_style_defs(".highlight")
                    source = pygments.format(
                        lexer.get_tokens("".join(content[minl:maxl])),
                        html_formatter)
                    self.file_cache[filename][line] = (css, source)
            except Exception as e:
                l.exception(e)
                self.file_cache[filename][line] = (None, None)
        else:
            self.file_cache[filename][line] = (None, None)

    def cache_tokens(self, addr_map: Dict[int, Tuple[str, int]]) -> None:
        for filename, line in addr_map.values():
            l.info("caching file: " + str(filename) + " at line: " + str(line))
            if filename != "??":
                if filename in self.file_read_cache.keys():
                    self.fill_file_cache(filename, line)
                else:
                    self.fill_read_cache(filename, line)

    def add_states(self, states: StateManager, tracer: Tracer) -> None:
        for s in states.major_states[1:]:
            pass
            # self.callgraph.add_node(s, tracer)

    def clear_viewer(self) -> None:
        self.code_view.clear()

    def append_archive(self) -> None:
        files = list(DEFAULT_LOG_DIR.glob("*.tar.gz"))
        files.sort()
        self.code_view.append("\nAvailable files:")
        for f in files:
            self.code_view.append(f.name)

    def enable_buttons(self) -> None:
        # TODO: maintain a button list
        self.up_button.setEnabled(True)
        self.upto_button.setEnabled(True)
        self.down_button.setEnabled(True)
        self.downto_button.setEnabled(True)
        # self.cg_button.setEnabled(True)
        self.info_button.setEnabled(True)
        self.switch_button.setEnabled(True)

    def clear_cache(self) -> None:
        self.file_cache = DefaultDict(dict)
        self.coredump_constraints = []
        # self.callgraph.clear_cache()

    def shutdown_kernel(self) -> None:
        print("Shutting down kernel...")
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()