Esempio n. 1
0
    def OnInit(self):
        """ Initialize the GUI

        This method is automatically called from the :wx:`App` constructor

        """

        gui.legend_logo = "legend_logo_delmic.png"
        if self._is_standalone:
            microscope = None
            gui.icon = img.getIcon("icon/ico_gui_viewer_256.png")
            gui.name = odemis.__shortname__ + " Viewer"

            if "delphi" == self._is_standalone:
                gui.logo = img.getBitmap("logo_delphi.png")
                gui.legend_logo = "legend_logo_delphi.png"
        else:
            gui.icon = img.getIcon("icon/ico_gui_full_256.png")
            gui.name = odemis.__shortname__
            try:
                microscope = model.getMicroscope()
            except (IOError, Pyro4.errors.CommunicationError) as e:
                logging.exception("Failed to connect to back-end")
                msg = ("The Odemis GUI could not connect to the Odemis back-end:"
                       "\n\n{0}\n\n"
                       "Launch user interface anyway?").format(e)

                answer = wx.MessageBox(msg,
                                       "Connection error",
                                       style=wx.YES | wx.NO | wx.ICON_ERROR)
                if answer == wx.NO:
                    sys.exit(1)
                microscope = None
            else:
                if microscope.role == "delphi":
                    gui.logo = img.getBitmap("logo_delphi.png")
                    gui.legend_logo = "legend_logo_delphi.png"

        # TODO: if microscope.ghost is not empty => wait and/or display a special
        # "hardware status" tab.

        if microscope and microscope.role == "mbsem":
            self.main_data = guimodel.FastEMMainGUIData(microscope)
        else:
            self.main_data = guimodel.MainGUIData(microscope)
        # Load the main frame
        self.main_frame = main_xrc.xrcfr_main(None)

        self.init_gui()

        try:
            from odemis.gui.dev.powermate import Powermate
            self.dev_powermate = Powermate(self.main_data)
        except (LookupError, NotImplementedError) as ex:
            logging.debug("Not using Powermate: %s", ex)
        except Exception:
            logging.exception("Failed to load Powermate support")

        # Application successfully launched
        return True
Esempio n. 2
0
    def test_mirror_arc_overlay(self):
        cnvs = miccanvas.SparcARCanvas(self.panel)
        cnvs.scale = 20000
        cnvs.add_world_overlay(cnvs.mirror_ol)
        cnvs.mirror_ol.active.value = True
        self.add_control(cnvs, wx.EXPAND, proportion=1, clear=True)

        def zoom(evt):
            mi, ma = 1000, 80000
            abs_val = abs(evt.step_value)

            if evt.direction == wx.RIGHT:
                old = cnvs.scale
                cnvs.scale *= 1.1**abs_val
                print("bigger %0.2f > %0.2f" % (old, cnvs.scale))

                if not mi <= cnvs.scale <= ma:
                    cnvs.scale = ma
            else:
                print("smaller")
                cnvs.scale *= 0.9**abs_val
                if not mi <= cnvs.scale <= ma:
                    cnvs.scale = mi

            wx.CallAfter(cnvs.update_drawing)

        try:
            self.pm = Powermate(self.frame)
        except LookupError:
            if TEST_NOHW:
                self.skipTest("No hardware detected, skipping test")

        cnvs.Bind(EVT_KNOB_ROTATE, zoom)

        test.gui_loop()
Esempio n. 3
0
class OdemisGUIApp(wx.App):
    """ This is Odemis' main GUI application class
    """

    def __init__(self, standalone=False, file_name=None):
        """

        Args:
            standalone: (bool or str) False, if not standalone, name string otherwise
            file_name: (str) Path to the file to open on launch

        """
        # Replace the standard 'get_resources' with our augmented one, that
        # can handle more control types. See the xhandler package for more info.
        main_xrc.get_resources = odemis_get_resources

        # Declare attributes BEFORE calling the super class constructor
        # because it will call 'OnInit' which uses them.

        self.main_data = None
        self.main_frame = None
        self.tab_controller = None
        self._is_standalone = standalone
        self._snapshot_controller = None
        self._temperature_controller = None
        self._menu_controller = None
        self.plugins = []  # List of instances of plugin.Plugins

        # User input devices
        self.dev_powermate = None

        l = logging.getLogger()
        self.log_level = l.getEffectiveLevel()

        # Output catcher using a helper class
        wx.App.outputWindowClass = OdemisOutputWindow

        # Constructor of the parent class
        # ONLY CALL IT AT THE END OF :py:method:`__init__` BECAUSE OnInit will
        # be called
        # and it needs the attributes defined in this constructor!
        wx.App.__init__(self, redirect=True)

        if file_name:
            tab = self.main_data.getTabByName('analysis')
            self.main_data.tab.value = tab
            wx.CallLater(500, tab.load_data, file_name)

    def OnInit(self):
        """ Initialize the GUI

        This method is automatically called from the :wx:`App` constructor

        """

        gui.legend_logo = "legend_logo_delmic.png"
        if self._is_standalone:
            microscope = None
            gui.icon = img.getIcon("icon/ico_gui_viewer_256.png")
            gui.name = odemis.__shortname__ + " Viewer"

            if "delphi" == self._is_standalone:
                gui.logo = img.getBitmap("logo_delphi.png")
                gui.legend_logo = "legend_logo_delphi.png"
        else:
            gui.icon = img.getIcon("icon/ico_gui_full_256.png")
            gui.name = odemis.__shortname__
            try:
                microscope = model.getMicroscope()
            except (IOError, Pyro4.errors.CommunicationError) as e:
                logging.exception("Failed to connect to back-end")
                msg = ("The Odemis GUI could not connect to the Odemis back-end:"
                       "\n\n{0}\n\n"
                       "Launch user interface anyway?").format(e)

                answer = wx.MessageBox(msg,
                                       "Connection error",
                                       style=wx.YES | wx.NO | wx.ICON_ERROR)
                if answer == wx.NO:
                    sys.exit(1)
                microscope = None
            else:
                if microscope.role == "delphi":
                    gui.logo = img.getBitmap("logo_delphi.png")
                    gui.legend_logo = "legend_logo_delphi.png"

        # TODO: if microscope.ghost is not empty => wait and/or display a special
        # "hardware status" tab.

        if microscope and microscope.role == "mbsem":
            self.main_data = guimodel.FastEMMainGUIData(microscope)
        else:
            self.main_data = guimodel.MainGUIData(microscope)
        # Load the main frame
        self.main_frame = main_xrc.xrcfr_main(None)

        self.init_gui()

        try:
            from odemis.gui.dev.powermate import Powermate
            self.dev_powermate = Powermate(self.main_data)
        except (LookupError, NotImplementedError) as ex:
            logging.debug("Not using Powermate: %s", ex)
        except Exception:
            logging.exception("Failed to load Powermate support")

        # Application successfully launched
        return True

    def init_gui(self):
        """ This method binds events to menu items and initializes GUI controls """

        try:
            # Add frame icon
            ib = wx.IconBundle()
            ib.AddIcon(gui.icon)
            self.main_frame.SetIcons(ib)
            self.main_frame.SetTitle(gui.name)

            # IMPORTANT NOTE:
            # As all tab panels are hidden on start-up, the MinSize attribute
            # of the main GUI frame will be set to such a low value that most of
            # the interface will be invisible if the user takes the interface out of
            # 'full screen' view.
            # Also, Gnome's GDK library will start spewing error messages, saying
            # it cannot draw certain images, because the dimensions are 0x0.
            self.main_frame.SetMinSize((1000, 550))
            self.main_frame.Maximize()  # must be done before Show()

            # List of all possible tabs used in Odemis' main GUI
            tab_defs = [
                {
                    # Unique name of the tab
                    "name": "secom_live",
                    # Tab controller for this tab
                    "controller": tabs.SecomStreamsTab,
                    # Tab button for this tab
                    "button": self.main_frame.btn_tab_secom_streams,
                    # Constructor of the tab panel
                    "panel": main_xrc.xrcpnl_tab_secom_streams
                },
                {
                    "name": "cryosecom-localization",
                    "controller": tabs.LocalizationTab,
                    "button": self.main_frame.btn_tab_localization,
                    "panel": main_xrc.xrcpnl_tab_localization
                },
                {
                    "name": "secom_align",
                    "controller": tabs.SecomAlignTab,
                    "button": self.main_frame.btn_tab_align,
                    "panel": main_xrc.xrcpnl_tab_secom_align
                },
                {
                    "name": "sparc_align",
                    "controller": tabs.SparcAlignTab,
                    "button": self.main_frame.btn_tab_align,
                    "panel": main_xrc.xrcpnl_tab_sparc_align
                },
                {
                    "name": "sparc2_align",
                    "controller": tabs.Sparc2AlignTab,
                    "button": self.main_frame.btn_tab_align,
                    "panel": main_xrc.xrcpnl_tab_sparc2_align
                },
                {
                    "name": "sparc_acqui",
                    "controller": tabs.SparcAcquisitionTab,
                    "button": self.main_frame.btn_tab_sparc_acqui,
                    "panel": main_xrc.xrcpnl_tab_sparc_acqui
                },
                {
                    "name": "fastem_overview",
                    "controller": tabs.FastEMOverviewTab,
                    "button": self.main_frame.btn_tab_fastem_overview,
                    "panel": main_xrc.xrcpnl_tab_fastem_overview
                },
                {
                    "name": "fastem_acqui",
                    "controller": tabs.FastEMAcquisitionTab,
                    "button": self.main_frame.btn_tab_fastem_acqui,
                    "panel": main_xrc.xrcpnl_tab_fastem_acqui
                },
                {"name": "fastem_chamber",
                    "controller": tabs.FastEMChamberTab,
                    "button": self.main_frame.btn_tab_sparc_chamber,
                    "panel": main_xrc.xrcpnl_tab_fastem_chamber
                },
                {
                    "name": "sparc_chamber",
                    "controller": tabs.ChamberTab,
                    "button": self.main_frame.btn_tab_sparc_chamber,
                    "panel": main_xrc.xrcpnl_tab_sparc_chamber
                },
                {
                    "name": "cryosecom_chamber",
                    "controller": tabs.CryoChamberTab,
                    "button": self.main_frame.btn_tab_cryosecom_chamber,
                    "panel": main_xrc.xrcpnl_tab_cryosecom_chamber
                },
                {
                    "name": "analysis",
                    "controller": tabs.AnalysisTab,
                    "button": self.main_frame.btn_tab_inspection,
                    "panel": main_xrc.xrcpnl_tab_inspection
                },
            ]

            # Create the main tab controller and store a global reference
            # in the odemis.gui.cont package
            self.tab_controller = tabs.TabBarController(tab_defs, self.main_frame, self.main_data)

            # Connect the log panel button of each tab
            def toggle_log_panel(_):
                self.main_data.debug.value = not self.main_frame.pnl_log.IsShown()

            for tab in self.tab_controller.get_tabs():
                if hasattr(tab.panel, 'btn_log'):
                    tab.panel.btn_log.Bind(wx.EVT_BUTTON, toggle_log_panel)
            self.main_frame.btn_log.Bind(wx.EVT_BUTTON, toggle_log_panel)

            self.main_data.debug.subscribe(self.on_debug_va, init=True)
            self.main_data.level.subscribe(self.on_level_va, init=True)
            log.create_gui_logger(self.main_frame.txt_log, self.main_data.debug, self.main_data.level)

            self._menu_controller = MenuController(self.main_data, self.main_frame)
            # Menu events
            self.main_frame.Bind(wx.EVT_MENU, self.on_close_window, id=self.main_frame.menu_item_quit.GetId())

            self.main_frame.Bind(wx.EVT_CLOSE, self.on_close_window)

            # To handle "Save snapshot" menu
            self._snapshot_controller = acquisition.SnapshotController(self.main_data,
                                                                       self.main_frame)

            # Update the logo if a non-default logo is defined
            if gui.logo:
                self.main_frame.logo.SetBitmap(gui.logo)
            # Update legend logo filepath
            self.main_frame.legend_logo = gui.legend_logo

            # Now starts the plugins, after the rest of the GUI is ready
            pfns = plugin.find_plugins()
            for p in pfns:
                pis = plugin.load_plugin(p, self.main_data.microscope, self)
                self.plugins.extend(pis)

            # add temperature controller
            if self.main_data.sample_thermostat:
                self._temperature_controller = TemperatureController(self.main_frame, self.main_data.sample_thermostat)

            # making it very late seems to make it smoother
            wx.CallAfter(self.main_frame.Show)

        except Exception:
            self.excepthook(*sys.exc_info())
            # Re-raise the exception, so the program will exit. If this is not
            # done and exception will prevent the GUI from being shown, while
            # the program keeps running in the background.
            raise

    @call_in_wx_main
    def on_debug_va(self, enabled):
        """
        Sets (or unset) the application into "debug mode", opening the log panel
        """
        self.main_frame.pnl_log.Show(enabled)

        for tab in self.tab_controller.get_tabs():
            if hasattr(tab.panel, 'btn_log'):
                tab.panel.btn_log.Show(not enabled)

        # Reset highest log level
        self.main_data.level.value = 0
        self.main_frame.Layout()

    @call_in_wx_main
    def on_level_va(self, log_level):
        """ Set the log button color """
        # As this function is called in the main thread, it might not be called
        # in the called order. Therefore, the log level might not be up-to-date.
        # => Read the log level from the model, which contains the latest value.
        log_level = self.main_data.level.value

        colour = 'def'

        if log_level >= logging.ERROR:
            colour = 'red'
        elif log_level >= logging.WARNING:
            colour = 'orange'

        for tab in self.tab_controller.get_tabs():
            if hasattr(tab.panel, 'btn_log'):
                tab.panel.btn_log.set_face_colour(colour)

    def on_close_window(self, evt=None):
        """ This method cleans up and closes the Odemis GUI. """
        logging.info("Exiting Odemis")

        if self.main_data.is_acquiring.value:
            msg = ("Acquisition in progress!\n\n"
                   "Please cancel the current acquisition operation before exiting Odemis.")
            dlg = wx.MessageDialog(self.main_frame, msg, "Exit", wx.OK | wx.ICON_STOP)
            # if dlg.ShowModal() == wx.ID_NO:
            dlg.ShowModal()
            dlg.Destroy()  # frame
            return

        # Check if there's any action to do before tab termination
        # Do not terminate if returned False
        if not self.tab_controller.query_terminate():
            return

        for p in self.plugins:
            try:
                p.terminate()
            except Exception:
                logging.exception("Failed to end the plugin properly")
        self.plugins = []

        if self.dev_powermate:
            self.dev_powermate.terminate()

        try:
            pub.unsubAll()
            # let all the tabs know we are stopping
            self.tab_controller.terminate()
        except Exception:
            logging.exception("Error during GUI shutdown")

        try:
            log.stop_gui_logger()
        except Exception:
            logging.exception("Error stopping GUI logging")

        self.main_frame.Destroy()

    def excepthook(self, etype, value, trace):
        """ Method to intercept unexpected errors that are not caught
        anywhere else and redirects them to the logger.
        Note that exceptions caught and logged will appear in the text pane,
        but not cause it to pop-up (as this method will not be called).
        """
        # in case of error here, don't call again, it'd create infinite recursion
        if sys and traceback:
            sys.excepthook = sys.__excepthook__

            try:
                exc = traceback.format_exception(etype, value, trace)
                try:
                    remote_tb = value._pyroTraceback
                    rmt_exc = "Remote exception %s" % ("".join(remote_tb),)
                except AttributeError:
                    rmt_exc = ""
                logging.error("".join(exc) + rmt_exc)

            finally:
                # put us back
                sys.excepthook = self.excepthook
        # python is ending... can't rely on anything
        else:
            print("%s: %s\n%s" % (etype, value, trace))

    def showwarning(self, message, category, filename, lineno, file=None, line=None):
        """
        Called when a warning is generated.
        The default behaviour is to write it on stderr, which would lead to it
        being shown as an error.
        """
        warn = warnings.formatwarning(message, category, filename, lineno, line)
        logging.warning(warn)
Esempio n. 4
0
class OdemisGUIApp(wx.App):
    """ This is Odemis' main GUI application class
    """

    def __init__(self, standalone=False, file_name=None):
        """

        Args:
            standalone: (bool or str) False, if not standalone, name string otherwise
            file_name: (str) Path to the file to open on launch

        """
        # Replace the standard 'get_resources' with our augmented one, that
        # can handle more control types. See the xhandler package for more info.
        main_xrc.get_resources = odemis_get_resources

        # Declare attributes BEFORE calling the super class constructor
        # because it will call 'OnInit' which uses them.

        self.main_data = None
        self.main_frame = None
        self.tab_controller = None
        self._is_standalone = standalone
        self._snapshot_controller = None
        self._menu_controller = None
        self.plugins = []  # List of instances of plugin.Plugins

        # User input devices
        self.dev_powermate = None

        l = logging.getLogger()
        self.log_level = l.getEffectiveLevel()

        if not self._is_standalone:
            try:
                driver.speedUpPyroConnect(model.getMicroscope())
            except Exception:
                logging.exception("Failed to speed up start up")

        # Output catcher using a helper class
        wx.App.outputWindowClass = OdemisOutputWindow

        # Constructor of the parent class
        # ONLY CALL IT AT THE END OF :py:method:`__init__` BECAUSE OnInit will
        # be called
        # and it needs the attributes defined in this constructor!
        wx.App.__init__(self, redirect=True)

        if file_name:
            tab = self.main_data.getTabByName('analysis')
            self.main_data.tab.value = tab
            wx.CallLater(500, tab.load_data, file_name)

    def OnInit(self):
        """ Initialize the GUI

        This method is automatically called from the :wx:`App` constructor

        """

        gui.legend_logo = "legend_logo_delmic.png"
        if self._is_standalone:
            microscope = None
            gui.icon = img.getIcon("icon/ico_gui_viewer_256.png")
            gui.name = odemis.__shortname__ + " Viewer"

            if "delphi" == self._is_standalone:
                gui.logo = img.getBitmap("logo_delphi.png")
                gui.legend_logo = "legend_logo_delphi.png"
        else:
            gui.icon = img.getIcon("icon/ico_gui_full_256.png")
            gui.name = odemis.__shortname__
            try:
                microscope = model.getMicroscope()
            except (IOError, Pyro4.errors.CommunicationError) as e:
                logging.exception("Failed to connect to back-end")
                msg = ("The Odemis GUI could not connect to the Odemis back-end:"
                       "\n\n{0}\n\n"
                       "Launch user interface anyway?").format(e)

                answer = wx.MessageBox(msg,
                                       "Connection error",
                                       style=wx.YES | wx.NO | wx.ICON_ERROR)
                if answer == wx.NO:
                    sys.exit(1)
                microscope = None
            else:
                if microscope.role == "delphi":
                    gui.logo = img.getBitmap("logo_delphi.png")
                    gui.legend_logo = "legend_logo_delphi.png"

        logging.info("\n\n************  Starting Odemis GUI  ************\n")
        logging.info("Odemis GUI v%s (from %s)", odemis.__version__, __file__)
        logging.info("wxPython v%s", wx.version())

        # TODO: if microscope.ghost is not empty => wait and/or display a special
        # "hardware status" tab.

        self.main_data = guimodel.MainGUIData(microscope)
        # Load the main frame
        self.main_frame = main_xrc.xrcfr_main(None)

        self.init_gui()

        try:
            from odemis.gui.dev.powermate import Powermate
            self.dev_powermate = Powermate(self.main_data)
        except (LookupError, NotImplementedError) as ex:
            logging.debug("Not using Powermate: %s", ex)
        except Exception:
            logging.exception("Failed to load Powermate support")

        # Application successfully launched
        return True

    def init_gui(self):
        """ This method binds events to menu items and initializes GUI controls """

        try:
            # Add frame icon
            ib = wx.IconBundle()
            ib.AddIcon(gui.icon)
            self.main_frame.SetIcons(ib)
            self.main_frame.SetTitle(gui.name)

            # IMPORTANT NOTE:
            # As all tab panels are hidden on start-up, the MinSize attribute
            # of the main GUI frame will be set to such a low value that most of
            # the interface will be invisible if the user takes the interface out of
            # 'full screen' view.
            # Also, Gnome's GDK library will start spewing error messages, saying
            # it cannot draw certain images, because the dimensions are 0x0.
            self.main_frame.SetMinSize((1280, 550))
            self.main_frame.Maximize()  # must be done before Show()

            # List of all possible tabs used in Odemis' main GUI

            # TODO: instead of roles + label, have a class method on each
            # StreamTab class that takes the microscope as input, and return a
            # label or None if it shouldn't be displayed. (+ a "priority" to
            # decide which one is the default?)

            tab_defs = [
                {
                    # Unique name of the tab
                    "name": "secom_live",
                    # Tab controller for this tab
                    "controller": tabs.SecomStreamsTab,
                    # Tab button for this tab
                    "button": self.main_frame.btn_tab_secom_streams,
                    # Constructor of the tab panel
                    "panel": main_xrc.xrcpnl_tab_secom_streams
                },
                {
                    "name": "secom_align",
                    "controller": tabs.SecomAlignTab,
                    "button": self.main_frame.btn_tab_secom_align,
                    "panel": main_xrc.xrcpnl_tab_secom_align
                },
                {
                    "name": "sparc_align",
                    "controller": tabs.SparcAlignTab,
                    "button": self.main_frame.btn_tab_sparc_align,
                    "panel": main_xrc.xrcpnl_tab_sparc_align
                },
                {
                    "name": "sparc2_align",
                    "controller": tabs.Sparc2AlignTab,
                    "button": self.main_frame.btn_tab_sparc2_align,
                    "panel": main_xrc.xrcpnl_tab_sparc2_align
                },
                {
                    "name": "sparc_acqui",
                    "controller": tabs.SparcAcquisitionTab,
                    "button": self.main_frame.btn_tab_sparc_acqui,
                    "panel": main_xrc.xrcpnl_tab_sparc_acqui
                },
                {
                    "name": "sparc_chamber",
                    "controller": tabs.ChamberTab,
                    "button": self.main_frame.btn_tab_sparc_chamber,
                    "panel": main_xrc.xrcpnl_tab_sparc_chamber
                },
                {
                    "name": "analysis",
                    "controller": tabs.AnalysisTab,
                    "button": self.main_frame.btn_tab_inspection,
                    "panel": main_xrc.xrcpnl_tab_inspection
                },
            ]

            # Create the main tab controller and store a global reference
            # in the odemis.gui.cont package
            self.tab_controller = tabs.TabBarController(tab_defs, self.main_frame, self.main_data)

            # Connect the log panel button of each tab
            def toggle_log_panel(_):
                self.main_data.debug.value = not self.main_frame.pnl_log.IsShown()

            for tab in self.tab_controller.get_tabs():
                if hasattr(tab.panel, 'btn_log'):
                    tab.panel.btn_log.Bind(wx.EVT_BUTTON, toggle_log_panel)
            self.main_frame.btn_log.Bind(wx.EVT_BUTTON, toggle_log_panel)

            self.main_data.debug.subscribe(self.on_debug_va, init=True)
            self.main_data.level.subscribe(self.on_level_va, init=True)
            log.create_gui_logger(self.main_frame.txt_log, self.main_data.debug, self.main_data.level)

            self._menu_controller = MenuController(self.main_data, self.main_frame)
            # Menu events
            self.main_frame.Bind(wx.EVT_MENU, self.on_close_window, id=self.main_frame.menu_item_quit.GetId())

            self.main_frame.Bind(wx.EVT_CLOSE, self.on_close_window)

            # To handle "Save snapshot" menu
            self._snapshot_controller = acquisition.SnapshotController(self.main_data,
                                                                       self.main_frame)

            # Update the logo if a non-default logo is defined
            if gui.logo:
                self.main_frame.logo.SetBitmap(gui.logo)
            # Update legend logo filepath
            self.main_frame.legend_logo = gui.legend_logo

            # Now starts the plugins, after the rest of the GUI is ready
            pfns = plugin.find_plugins()
            for p in pfns:
                pis = plugin.load_plugin(p, self.main_data.microscope, self)
                self.plugins.extend(pis)

            # making it very late seems to make it smoother
            wx.CallAfter(self.main_frame.Show)

        except Exception:
            self.excepthook(*sys.exc_info())
            # Re-raise the exception, so the program will exit. If this is not
            # done and exception will prevent the GUI from being shown, while
            # the program keeps running in the background.
            raise

    @call_in_wx_main
    def on_debug_va(self, enabled):
        """
        Sets (or unset) the application into "debug mode", opening the log panel
        """
        self.main_frame.pnl_log.Show(enabled)

        for tab in self.tab_controller.get_tabs():
            if hasattr(tab.panel, 'btn_log'):
                tab.panel.btn_log.Show(not enabled)

        # Reset highest log level
        self.main_data.level.value = 0
        self.main_frame.Layout()

    @call_in_wx_main
    def on_level_va(self, log_level):
        """ Set the log button color """
        # As this function is called in the main thread, it might not be called
        # in the called order. Therefore, the log level might not be up-to-date.
        # => Read the log level from the model, which contains the latest value.
        log_level = self.main_data.level.value

        colour = 'def'

        if log_level >= logging.ERROR:
            colour = 'red'
        elif log_level >= logging.WARNING:
            colour = 'orange'

        for tab in self.tab_controller.get_tabs():
            if hasattr(tab.panel, 'btn_log'):
                tab.panel.btn_log.set_face_colour(colour)

    def on_close_window(self, evt=None):
        """ This method cleans up and closes the Odemis GUI. """
        logging.info("Exiting Odemis")

        if self.main_data.is_acquiring.value:
            msg = ("Acquisition in progress!\n\n"
                   "Please cancel the current acquisition operation before exiting Odemis.")
            dlg = wx.MessageDialog(self.main_frame, msg, "Exit", wx.OK | wx.ICON_STOP)
            # if dlg.ShowModal() == wx.ID_NO:
            dlg.ShowModal()
            dlg.Destroy()  # frame
            return

        for p in self.plugins:
            try:
                p.terminate()
            except Exception:
                logging.exception("Failed to end the plugin properly")
        self.plugins = []

        if self.dev_powermate:
            self.dev_powermate.terminate()

        try:
            pub.unsubAll()
            # let all the tabs know we are stopping
            self.tab_controller.terminate()
        except Exception:
            logging.exception("Error during GUI shutdown")

        try:
            log.stop_gui_logger()
        except Exception:
            logging.exception("Error stopping GUI logging")

        self.main_frame.Destroy()

    def excepthook(self, etype, value, trace):
        """ Method to intercept unexpected errors that are not caught
        anywhere else and redirects them to the logger.
        Note that exceptions caught and logged will appear in the text pane,
        but not cause it to pop-up (as this method will not be called).
        """
        # in case of error here, don't call again, it'd create infinite recursion
        if sys and traceback:
            sys.excepthook = sys.__excepthook__

            try:
                exc = traceback.format_exception(etype, value, trace)
                try:
                    remote_tb = value._pyroTraceback
                    rmt_exc = "Remote exception %s" % ("".join(remote_tb),)
                except AttributeError:
                    rmt_exc = ""
                logging.error("".join(exc) + rmt_exc)

            finally:
                # put us back
                sys.excepthook = self.excepthook
        # python is ending... can't rely on anything
        else:
            print("%s: %s\n%s" % (etype, value, trace))

    def showwarning(self, message, category, filename, lineno, file=None, line=None):
        """
        Called when a warning is generated.
        The default behaviour is to write it on stderr, which would lead to it
        being shown as an error.
        """
        warn = warnings.formatwarning(message, category, filename, lineno, line)
        logging.warning(warn)
Esempio n. 5
0
    def OnInit(self):
        """ Initialize the GUI

        This method is automatically called from the :wx:`App` constructor

        """

        gui.legend_logo = "legend_logo_delmic.png"
        if self._is_standalone:
            microscope = None
            gui.icon = img.getIcon("icon/ico_gui_viewer_256.png")
            gui.name = odemis.__shortname__ + " Viewer"

            if "delphi" == self._is_standalone:
                gui.logo = img.getBitmap("logo_delphi.png")
                gui.legend_logo = "legend_logo_delphi.png"
        else:
            gui.icon = img.getIcon("icon/ico_gui_full_256.png")
            gui.name = odemis.__shortname__
            try:
                microscope = model.getMicroscope()
            except (IOError, Pyro4.errors.CommunicationError) as e:
                logging.exception("Failed to connect to back-end")
                msg = ("The Odemis GUI could not connect to the Odemis back-end:"
                       "\n\n{0}\n\n"
                       "Launch user interface anyway?").format(e)

                answer = wx.MessageBox(msg,
                                       "Connection error",
                                       style=wx.YES | wx.NO | wx.ICON_ERROR)
                if answer == wx.NO:
                    sys.exit(1)
                microscope = None
            else:
                if microscope.role == "delphi":
                    gui.logo = img.getBitmap("logo_delphi.png")
                    gui.legend_logo = "legend_logo_delphi.png"

        logging.info("\n\n************  Starting Odemis GUI  ************\n")
        logging.info("Odemis GUI v%s (from %s)", odemis.__version__, __file__)
        logging.info("wxPython v%s", wx.version())

        # TODO: if microscope.ghost is not empty => wait and/or display a special
        # "hardware status" tab.

        self.main_data = guimodel.MainGUIData(microscope)
        # Load the main frame
        self.main_frame = main_xrc.xrcfr_main(None)

        self.init_gui()

        try:
            from odemis.gui.dev.powermate import Powermate
            self.dev_powermate = Powermate(self.main_data)
        except (LookupError, NotImplementedError) as ex:
            logging.debug("Not using Powermate: %s", ex)
        except Exception:
            logging.exception("Failed to load Powermate support")

        # Application successfully launched
        return True