class TestSplitEditorAreaPane(unittest.TestCase, GuiTestAssistant):
    def setUp(self):
        GuiTestAssistant.setUp(self)
        self.area_pane = SplitEditorAreaPane()

    def tearDown(self):
        if self.area_pane.control is not None:
            with self.delete_widget(self.area_pane.control):
                self.area_pane.destroy()
        GuiTestAssistant.tearDown(self)

    def test_create_destroy(self):
        # test that creating and destroying works as expected
        with self.event_loop():
            self.area_pane.create(None)
        with self.event_loop():
            self.area_pane.destroy()
 def setUp(self):
     GuiTestAssistant.setUp(self)
     self.area_pane = SplitEditorAreaPane()
예제 #3
0
 def create_central_pane(self):
     self.editor_area = SplitEditorAreaPane(
         callbacks={'open': self._new_file})
     return self.editor_area
 def create_central_pane(self):
     """ Create an DataViews pane as the main task UI.
     """
     self.central_pane = SplitEditorAreaPane()
     return self.central_pane
class KromatographyTask(Task):
    """ Task providing central pane & dock panes to view a KromatographyProject
    """

    # -------------------------------------------------------------------------
    # 'Task' interface
    # -------------------------------------------------------------------------

    id = 'krom.kromatography_task'

    name = Str

    # -------------------------------------------------------------------------
    # 'UndoableTask' interface
    # -------------------------------------------------------------------------

    #: The task's command stack for Undo/Redo
    command_stack = Instance(ICommandStack)

    #: The global undo manager for the application
    undo_manager = Instance(IUndoManager)

    # -------------------------------------------------------------------------
    # 'KromatographyTask' interface
    # -------------------------------------------------------------------------

    #: 'Project' filepath storing the current task (to store UI elements too)
    project_filepath = Unicode

    #: Project to support the GUI.
    project = Instance(KromatographyProject)

    # -------------------------------------------------------------------------
    # 'KromatographyTask' private interface
    # -------------------------------------------------------------------------

    #: hook to the central pane
    central_pane = Instance(SplitEditorAreaPane)

    #: Map between the object displayed in the central pane and editors for it
    # Note: there could be several editors for the same object. For example, a
    # simulation might be open, for there might be a chrom plot and an
    # animation plot open for it too.
    central_pane_editor_map = Dict

    # Other panes -------------------------------------------------------------

    datasource_pane = Instance('kromatography.ui.tasks.data_source_pane.'
                               'DataSourceDockPane')

    study_data_pane = Instance('kromatography.ui.tasks.study_browser_pane.'
                               'StudyDataDockPane')

    performance_param_pane = Instance(
        'kromatography.ui.tasks.performance_param_pane.PerformanceParamPane')

    job_manager_pane = Instance('app_common.encore.job_manager_pane.'
                                'JobManagerPane')

    #: Flags to analyze if certain objects exist
    simulations_exist = Property(Bool,
                                 depends_on="project.study.simulations[]")

    experiments_exist = Property(Bool,
                                 depends_on="project.study.experiments[]")

    experiments_and_sim_exist = Property(
        Bool, depends_on="simulations_exist, experiments_exist")

    simulation_groups_exist = Property(
        Bool, depends_on="project.study.analysis_tools.simulation_grids[]")

    _strip_component_exist = Property(Bool, depends_on="project.study.product")

    #: Handle on the application object which created the task
    _app = Instance('kromatography.app.krom_app.KromatographyApp')

    #: View class for the active central pane tab editor
    _view_central_pane = Property(Any, depends_on="central_pane.active_editor")

    #: Is the view class for active central pane tab editor a plot?
    _central_pane_is_plot = Property(Bool, depends_on="_view_central_pane")

    # -------------------------------------------------------------------------
    # 'Task' interface methods
    # -------------------------------------------------------------------------

    def create_central_pane(self):
        """ Create an DataViews pane as the main task UI.
        """
        self.central_pane = SplitEditorAreaPane()
        return self.central_pane

    def create_dock_panes(self):
        """ Create all dock panes for the main task UI """
        from kromatography.ui.tasks.data_source_pane import \
            DataSourceDockPane
        from kromatography.ui.tasks.study_browser_pane import StudyDataDockPane
        from kromatography.ui.tasks.performance_param_pane import \
            PerformanceParamPane
        from app_common.encore.job_manager_pane import \
            JobManagerPane

        self.datasource_pane = DataSourceDockPane(
            datasource=self.project.datasource)
        self.study_data_pane = StudyDataDockPane(study=self.project.study)
        self.performance_param_pane = PerformanceParamPane(
            study=self.project.study)
        self.job_manager_pane = JobManagerPane(
            job_manager=self._app.job_manager,
            name='Cadet Job Manager',
            run_time_result_key="run time")

        return [
            self.datasource_pane, self.study_data_pane,
            self.performance_param_pane, self.job_manager_pane
        ]

    def activated(self):
        """ Actions to be taken once the task panes have been created and the
        window has been created:
        1. Ensure that the command stack is the active command stack
        2. Open a view on the project's study
        """
        super(KromatographyTask, self).activated()

        # Set up the undo infrastructure
        self.command_stack.undo_manager = self.undo_manager
        self.undo_manager.active_stack = self.command_stack
        self.is_activated = True

        # Open the current project's study
        self.edit_object_in_central_pane(self.project.study)
        if self.project.study.experiments:
            self.new_model_calibration_plot()

    def prepare_destroy(self):
        self.job_manager_pane.prepare_destroy()

    # -------------------------------------------------------------------------
    # 'KromatographyTask' interface methods
    # -------------------------------------------------------------------------

    def edit_object_in_central_pane(self, obj, factory=None, uuid_to_map=None):
        """ Select appropriate editor to visualize/edit Traits object in the
        central pane.

        Parameters
        ----------
        obj : any
            Object to be edited in the central pane.

        factory : type [OPTIONAL]
            Class used to build the editor.

        uuid_to_map : UUID
            UUID of the object to track as holding the data for the resulting
            editor. If/when that object gets deleted, the corresponding editor
            will get closed.
        """
        if factory is None:
            if isinstance(obj, DataElement):
                factory = DataElementEditor
            else:
                msg = "No editor yet for a {}".format(type(obj))
                logger.error(msg)
                raise NotImplementedError(msg)

        editor = self.central_pane.edit(obj, factory=factory)
        if editor.obj_view:
            # Provide the modelView with access to the task in case of need:
            editor.obj_view._task = self

        # Track whose uuid we should associate with this editor (so that if
        # that object gets deleted, this editor gets closed)
        if uuid_to_map is None:
            uuid_to_map = obj.uuid

        if uuid_to_map not in self.central_pane_editor_map:
            self.central_pane_editor_map[uuid_to_map] = []

        self.central_pane_editor_map[uuid_to_map].append(editor)

    def close_central_pane_for_object(self, obj_info):
        """ Close the central pane editor(s) for specified edited_object.
        """
        editors = self.central_pane_editor_map.pop(obj_info["uuid"], None)
        if editors is None:
            return

        for editor in editors:
            try:
                self.central_pane.remove_editor(editor)
            except Exception as e:
                msg = "Failed to remove editor for object {} (type {}). " \
                      "Error was {}."
                msg = msg.format(obj_info["name"], obj_info["type"], e)
                logger.warning(msg)

    # Serialization methods ---------------------------------------------------

    def save_request(self):
        """ Save current project to a new file.
        """
        dlg_attrs = {
            'title': 'Save Project',
            'action': 'save as',
            'wildcard': KROM_WILDCARD
        }
        # If the project already has
        if self.project_filepath:
            curr_folder, curr_filename = split(self.project_filepath)
            dlg_attrs["default_directory"] = curr_folder
            dlg_attrs["default_filename"] = curr_filename

        file_dialog = FileDialogWithMemory(**dlg_attrs)
        file_dialog.open()

        if file_dialog.return_code == OK:
            path = file_dialog.path
            self.save_project_as(path=path)

    def save_project_as(self, path=""):
        """ Store the current task to the filepath provided and set project
        file path.
        """
        from kromatography.io.task import save_project

        if not path:
            msg = "Attempted to save a project but no file path provided " \
                  "(found '{}').".format(path)
            logger.error(msg)
            return False

        save_project(path, self)

    def save(self):
        """ Store the current task to its file path.
        """
        from kromatography.io.reader_writer import save_object

        if not self.project_filepath:
            self.save_request()
            return

        save_object(self.project_filepath, self)

    def save_user_ds(self):
        """ Store the user datasource to a new timed local file.
        """
        from kromatography.utils.app_utils import \
            save_user_datasource_to

        save_user_datasource_to(self.project.datasource)
        self.project.datasource.make_clean()

    def request_export_user_ds(self):
        """ Store the user datasource to a new timed local file.
        """
        from kromatography.utils.app_utils import save_user_datasource_to

        file_dialog = FileDialogWithMemory(title='Export User Data',
                                           action='save as',
                                           wildcard=KROM_DS_WILDCARD)
        file_dialog.open()

        if file_dialog.return_code == OK:
            path = file_dialog.path
            basepath, path_ext = splitext(path)
            if path_ext != KROM_DS_EXTENSION:
                path = basepath + KROM_DS_EXTENSION

            save_user_datasource_to(self.project.datasource, filepath=path)

    # New object creation methods ---------------------------------------------

    def new_simulation_from_datasource(self):
        """ Create a new simulation from DataSource data.
        """
        self.project.study.request_new_simulation_from_datasource(
            self.project.datasource)

    def new_simulation_from_experiments(self):
        """ Add new simulations mirroring experiment(s) in the current study.
        """
        self.project.study.request_new_simulations_from_experiments()

    def new_simulation_grid(self):
        """ Build a SimulationGroup around a center point simulation
        """
        grid = self.project.study.request_new_simulation_group()
        if grid is not None:
            self.edit_object_in_central_pane(grid)

    # Configuration tool methods ----------------------------------------------

    def open_strip_fraction_editor(self):
        """ Open the editor for strip fractions. """
        self.project.study.request_strip_fraction_tool()

    # Run launch methods ------------------------------------------------------

    def run_simulations(self, sims=None):
        """ Submit the selected simulations to CADET and update them with
        its output.
        """
        self.project.study.run_simulations(self.project.job_manager, sims=sims)

    def run_simulation_groups(self, group=None):
        """ Submit the selected SimulationGroup to CADET and update its
        simulations with output once run.
        """
        self.project.study.run_simulation_group(self.project.job_manager,
                                                sim_group=group)

    def run_optimizer(self, optimizer):
        """ Submit passed optimizer to run.
        """
        self.project.study.run_optimizer(self.project.job_manager, optimizer)

    def new_optimizer(self):
        """ Create a new optimizer.
        """
        optim = self.project.study.create_new_optimizer()
        if optim is not None:
            self.edit_object_in_central_pane(optim)

    # New plot creation methods -----------------------------------------------

    def new_animation_plot(self):
        from kromatography.ui.tasks.plot_editors import \
            AnimationPlotEditor

        result = build_animation_plot_model(self.project.study)
        if result:
            animation_plot_model, source_sim_uuid = result
            self.edit_object_in_central_pane(animation_plot_model,
                                             factory=AnimationPlotEditor,
                                             uuid_to_map=source_sim_uuid)

    def new_model_calibration_plot(self):
        """ Open a general chromatogram window to compare simulations and
        experiments to each other.
        """
        from kromatography.ui.tasks.plot_editors import ChromatogramPlotEditor

        study = self.project.study
        chromatogram_model = build_chromatogram_model(study)
        self.edit_object_in_central_pane(chromatogram_model,
                                         factory=ChromatogramPlotEditor,
                                         uuid_to_map=study.uuid)

    # Python execution methods ------------------------------------------------

    def request_run_python_script(self):
        """ Prompt the user to select a python script, and run it if dialog
        isn't cancelled.
        """
        from kromatography.tools.python_script_file_selector import \
            PythonScriptFileSelector

        selector = PythonScriptFileSelector()
        # Live modal so that changes to the known_scripts doesn't lead to
        # TraitErrors when the copy object is build and eval-ed in the context.
        ui = selector.edit_traits(kind="livemodal")
        if ui.result:
            self.run_python_script(selector.filepath, selector.code)

    def run_python_script(self, path="", code=""):
        """ Run the content of the python file in-process.

        Parameters
        ----------
        path : str [OPTIONAL]
            Path to the script file. Cannot be empty if the code is empty.

        code : str [OPTIONAL]
            Content of the script file. Cannot be empty if the path is empty.
        """
        from kromatography.tools.python_script_runner import PythonScriptRunner

        if not code:
            if not path:
                msg = "Cannot run any script as neither a path nor code has" \
                      " been provided (path={}, code={}).".format(path, code)
                logger.exception(msg)
                raise ValueError(msg)

            code = open(path).read()

        script = PythonScriptRunner(code=code,
                                    task=self,
                                    app=self._app,
                                    path=path)
        try:
            output = script.run()
        except Exception as e:
            msg = "Failed to run the script {}: error as {}"
            msg = msg.format(path, e)
            logger.exception(msg)
            error(None, msg)
        else:
            msg = "Script {} ran successfully with the following output:\n\n{}"
            msg = msg.format(path, output)
            information(None, msg)

        logger.debug(msg)

    def request_launch_python_console(self, confirm_on_exit=True):
        """ Launch the qt_console as a separate process.

        TODO: Make this an in-process, in-app terminal.
        """
        import sys
        from subprocess import PIPE, Popen
        from app_common.std_lib.sys_utils import get_bin_folder, IS_WINDOWS

        if IS_WINDOWS:
            # For some reason, the OSX command doesn't work in all installed
            # environments on Windows...
            prefix = sys.prefix
            cmd = [
                join(prefix, "pythonw.exe"),
                join(prefix, "Scripts", "jupyter-qtconsole-script.pyw")
            ]
        else:
            executable = join(get_bin_folder(), "jupyter")
            cmd = [executable, "qtconsole"]

        if not confirm_on_exit:
            cmd.append("--no-confirm-exit")

        try:
            Popen(cmd, stdout=PIPE, stderr=PIPE)
        except Exception as e:
            msg = "Jupyter Qtconsole has failed to launch with error {}"
            msg = msg.format(e)
            logger.debug(msg)

    # Listeners to trigger actions --------------------------------------------

    @on_trait_change(
        'project:study:simulations:plot_request, '
        'project:study:analysis_tools:simulation_grids:plot_request, '  # noqa
        'project:study:analysis_tools:simulation_grids:simulations:plot_request, '  # noqa
        'project:study:analysis_tools:optimizations:optimal_simulations:plot_request'
    )  # noqa
    def trigger_plot_simulation(self, obj, name, new):
        """ Open chromatogram for simulation/SimulationGroup that was requested
        """
        from kromatography.ui.tasks.plot_editors import \
            ChromatogramPlotEditor
        from kromatography.model.simulation import Simulation

        with action_monitoring("Plotting Simulation/Simulation group"):
            if isinstance(obj, Simulation):
                kw = {"sims": [obj]}
            else:
                kw = {"sim_group": obj}

            chrome_model = build_chromatogram_model(self.project.study, **kw)

        self.edit_object_in_central_pane(chrome_model,
                                         factory=ChromatogramPlotEditor,
                                         uuid_to_map=obj.uuid)

    @on_trait_change('project:study:simulations:cadet_request')
    def trigger_run_simulation(self, obj, name, new):
        with action_monitoring("Running CADET on simulation"):
            self.run_simulations([obj])

    @on_trait_change('project:study:analysis_tools:simulation_grids:'
                     'cadet_request, '
                     'project:study:analysis_tools:monte_carlo_explorations:'
                     'cadet_request')
    def trigger_run_simulation_group(self, obj, name, new):
        with action_monitoring("Running CADET on simulation group"):
            self.run_simulation_groups(obj)

    @on_trait_change('project:study:analysis_tools:optimizations:'
                     'cadet_request')
    def trigger_run_optimizer(self, obj, name, new):
        with action_monitoring("Running CADET on optimizer"):
            self.run_optimizer(obj)

    @on_trait_change("project:deleted_objects[]")
    def update_central_pane_tabs(self, obj, attr, _, deleted_obj_info):
        for info in deleted_obj_info:
            self.close_central_pane_for_object(info)

    # app level requests ------------------------------------------------------

    def open_proj_file(self):
        self._app.request_project_from_file()

    def open_recent_projects(self):
        self._app.open_recent_project()

    # Plot control methods ----------------------------------------------------

    def _get__view_central_pane(self):
        no_active_view = (self.central_pane is None
                          or self.central_pane.active_editor is None)
        if no_active_view:
            return None

        return self.central_pane.active_editor.traits_ui.context['object']

    def _get__central_pane_is_plot(self):
        if self._view_central_pane is None:
            return False

        return isinstance(self._view_central_pane, ChromatogramModelView)

    def show_hide_legend(self):
        plot_view = self._view_central_pane
        plot_view._show_legend = not plot_view._show_legend

    def show_hide_plot_controls(self):
        plot_view = self._view_central_pane
        plot_view._show_control = not plot_view._show_control

    # Trait listeners ---------------------------------------------------------

    @on_trait_change('project_filepath, project.study.exp_study_filepath')
    def update_name(self):
        self.name = self._build_name()
        if self.window is not None:
            self.window.title = self.name

    # traits defaults ---------------------------------------------------------

    def _name_default(self):
        return self._build_name()

    def _tool_bars_default(self):
        # No accelerators here: they are added to menu entries

        tool_bars = [
            # General action toolbar
            SToolBar(TaskAction(
                name="Open recent projects",
                method="open_recent_projects",
                tooltip="Open recent project(s)",
                image=ImageResource("document-open-recent.png")),
                     TaskAction(name='Open project file',
                                method='open_proj_file',
                                tooltip='Open project file',
                                image=ImageResource('document-open')),
                     TaskAction(name='Save current project',
                                method='save',
                                tooltip='Save current project',
                                image=ImageResource('document-save')),
                     TaskAction(name='Save user data',
                                method='save_user_ds',
                                tooltip='Save user data',
                                image=ImageResource('drive-harddisk')),
                     image_size=ICON_SIZE,
                     show_tool_names=False),
            SToolBar(TaskAction(name='New simulation(s) from experiment(s)',
                                method='new_simulation_from_experiments',
                                tooltip='New simulation(s) from experiment(s)',
                                image=ImageResource('kchart')),
                     TaskAction(name='Run simulation(s)',
                                method='run_simulations',
                                tooltip='Run simulation(s)',
                                enabled_name='simulations_exist',
                                image=ImageResource('arrow-right')),
                     TaskAction(name='Run simulation grid(s)',
                                tooltip='Run simulation grid(s)',
                                method='run_simulation_groups',
                                enabled_name='simulation_groups_exist',
                                image=ImageResource('arrow-right-double')),
                     image_size=ICON_SIZE,
                     show_tool_names=False),

            # Plot action toolbar
            SToolBar(TaskAction(name='Plot all simulations',
                                method='new_model_calibration_plot',
                                tooltip='Plot all simulations',
                                image=ImageResource('office-chart-line')),
                     TaskAction(name='Show/hide plot controls',
                                method='show_hide_plot_controls',
                                tooltip='Show/hide plot controls',
                                image=ImageResource('format-list-unordered'),
                                enabled_name='_central_pane_is_plot'),
                     TaskAction(name='Show/hide plot legend',
                                method='show_hide_legend',
                                tooltip='Show/hide plot legend',
                                image=ImageResource('preferences-activities'),
                                enabled_name='_central_pane_is_plot'),
                     image_size=ICON_SIZE,
                     show_tool_names=False)
        ]
        return tool_bars

    def _menu_bar_default(self):
        menu_bar = SMenuBar(
            SMenu(SMenu(SGroup(
                TaskAction(name='New Simulation',
                           method='new_simulation_from_datasource',
                           image=ImageResource('office-chart-pie')),
                TaskAction(name='New Simulation from Experiment',
                           method='new_simulation_from_experiments',
                           image=ImageResource('kchart'),
                           accelerator='Ctrl+N'),
                id='NewSimulationGroup',
                name='NewSimulationGroup',
            ),
                        id='NewMenu',
                        name='&New Simulation'),
                  SGroup(TaskAction(name='Save Project',
                                    accelerator='Ctrl+S',
                                    method='save',
                                    image=ImageResource('document-save')),
                         TaskAction(name='Save Project As...',
                                    accelerator='Ctrl+Shift+S',
                                    method='save_request',
                                    image=ImageResource('document-save-as')),
                         id='SaveGroup',
                         name='SaveGroup'),
                  SGroup(
                      TaskAction(name='Save User Data',
                                 method='save_user_ds',
                                 image=ImageResource('drive-harddisk')),
                      TaskAction(name='Export User Data As...',
                                 method='request_export_user_ds',
                                 image=ImageResource('document-import')),
                      id='SaveUserDataGroup',
                      name='SaveUserDataGroup',
                  ),
                  SGroup(
                      TaskWindowAction(
                          name='Close',
                          accelerator='Ctrl+W',
                          method='close',
                      ),
                      id='CloseGroup',
                      name='CloseGroup',
                  ),
                  id='File',
                  name='&File'), SMenu(id='Edit', name='&Edit'),
            SMenu(DockPaneToggleGroup(), id='View', name='&View'),
            SMenu(
                SGroup(
                    TaskAction(name='Parameter Explorer',
                               accelerator='Ctrl+Shift+N',
                               method='new_simulation_grid',
                               enabled_name='simulations_exist'),
                    TaskAction(name='Parameter Optimizer',
                               accelerator='Ctrl+Shift+M',
                               method='new_optimizer',
                               enabled_name='experiments_and_sim_exist'),
                    id='ParamExplorationGroup',
                    name='ParamExplorationGroup',
                ),
                SGroup(
                    TaskAction(name='Run Simulations',
                               method='run_simulations',
                               accelerator='Ctrl+R',
                               enabled_name='simulations_exist',
                               image=ImageResource('arrow-right')),
                    TaskAction(name='Run Simulation Group',
                               method='run_simulation_groups',
                               accelerator='Ctrl+Shift+R',
                               enabled_name='simulation_groups_exist',
                               image=ImageResource('arrow-right-double')),
                    id='RunSimulationGroup',
                    name='RunSimulationGroup',
                ),
                SGroup(
                    TaskAction(name='Plot Chomatogram(s)',
                               method='new_model_calibration_plot',
                               accelerator='Ctrl+P',
                               image=ImageResource('office-chart-line')),
                    TaskAction(name='Particle data animation',
                               method='new_animation_plot'),
                    id='PlotsGroup',
                    name='PlotsGroup',
                ),
                SGroup(
                    TaskAction(name=STRIP_TOOL_NAME,
                               method='open_strip_fraction_editor',
                               enabled_name='_strip_component_exist'),
                    id='ConfigurationGroup',
                    name='ConfigurationGroup',
                ),
                SGroup(TaskAction(name='Custom Python script...',
                                  accelerator='Ctrl+I',
                                  method='request_run_python_script',
                                  tooltip='Modify the current project with '
                                  'custom script.',
                                  image=ImageResource('text-x-python')),
                       TaskAction(name='Interactive Python console...',
                                  accelerator='Ctrl+J',
                                  tooltip="(Jupyter) Python console to "
                                  "interactively explore Reveal's code "
                                  "and develop new tools/scripts.",
                                  method='request_launch_python_console',
                                  image=ImageResource('ipython_icon')),
                       id='RunPythonGroup',
                       name='RunPythonGroup'),
                id='Tools',
                name='&Tools',
            ), SMenu(id='Help', name='&Help'))
        return menu_bar

    def _default_layout_default(self):
        """ Control where to place each dock panes.
        """
        bottom_height = 270

        return TaskLayout(id=self.id,
                          left=Splitter(PaneItem('krom.data_source_pane'),
                                        PaneItem('krom.study_data_pane'),
                                        orientation='vertical'),
                          bottom=Splitter(PaneItem(
                              'krom.performance_param_pane',
                              height=bottom_height),
                                          PaneItem('common.job_manager_pane',
                                                   height=bottom_height,
                                                   width=250),
                                          orientation='horizontal'))

    def _undo_manager_default(self):
        from apptools.undo.api import UndoManager

        undo_manager = UndoManager()
        return undo_manager

    def _command_stack_default(self):
        from app_common.apptools.undo.single_clean_state_command_stack import\
            SingleCleanStateCommandStack

        command_stack = SingleCleanStateCommandStack(
            undo_manager=self.undo_manager)
        return command_stack

    # traits property getters/setters -----------------------------------------

    def _get_experiments_exist(self):
        return len(self.project.study.experiments) > 0

    def _get_simulations_exist(self):
        return len(self.project.study.simulations) > 0

    def _get_experiments_and_sim_exist(self):
        return self.experiments_exist and self.simulations_exist

    def _get_simulation_groups_exist(self):
        return len(self.project.study.analysis_tools.simulation_grids) > 0

    def _get__strip_component_exist(self):
        return self.project.study.product_contains_strip

    # -------------------------------------------------------------------------
    # 'KromatographyTask' private interface methods
    # -------------------------------------------------------------------------

    def _build_name(self):
        title = APP_FAMILY + " " + APP_TITLE
        if self.project_filepath:
            title += ": {}".format(self.project_filepath)

        study_path_exists = (self.project and self.project.study
                             and self.project.study.exp_study_filepath)
        if study_path_exists:
            basename = os.path.basename(self.project.study.exp_study_filepath)
            title += " ({})".format(basename)
        return title
예제 #6
0
class DebuggerTask(Task):
    """ A simple task for editing Python code.
    """

    #### Task interface #######################################################

    id = 'debugger.debugger_task'
    name = 'Editor'

    active_editor = Property(Instance(IEditor),
                             depends_on='editor_area.active_editor')

    editor_area = Instance(IEditorAreaPane)

    stack_pane = Instance(StackPane)

    menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new',
                                         accelerator='Ctrl+N'),
                              TaskAction(name='Open...', method='open',
                                         accelerator='Ctrl+O'),
                              TaskAction(name='Save', method='save',
                                         accelerator='Ctrl+S'),
                              id='File', name='&File'),
                        SMenu(DockPaneToggleGroup(),
                              id='View', name='&View'))

    tool_bars = [ SToolBar(TaskAction(method='new',
                                      tooltip='New file',
                                      image=ImageResource('document_new')),
                           TaskAction(method='open',
                                      tooltip='Open a file',
                                      image=ImageResource('document_open')),
                           TaskAction(method='save',
                                      tooltip='Save the current file',
                                      image=ImageResource('document_save')),
                           image_size = (24, 24)),
                  SToolBar(StartContinueTaskAction(
                                      image=ImageResource('debugger_start')),
                           TaskAction(method='stop_debugger',
                                      tooltip='Stop debugger',
                                      enabled_name = 'debug_process.readyToDebug',
                                      image=ImageResource('debugger_stop')),
                           TaskAction(method='step_over_line',
                                      tooltip='Step over next line',
                                      enabled_name = 'debug_process.readyToDebug',
                                      image=ImageResource('debugger_step_over')),
                           TaskAction(method='step_into_line',
                                      tooltip='Step into next line',
                                      enabled_name = 'debug_process.readyToDebug',
                                      image=ImageResource('debugger_step_into')),
                           TaskAction(method='step_out',
                                      tooltip='Step out of the current function',
                                      enabled_name = 'debug_process.readyToDebug',
                                      image=ImageResource('debugger_step_out')),
                           image_size = (24, 24)),
                ]

    ###########################################################################
    # 'Task' interface.
    ###########################################################################

    def _default_layout_default(self):
        return TaskLayout(
            left=PaneItem('debugger.python_script_browser_pane'),
            right=PaneItem('debugger.stack_pane'))

    def activated(self):
        """ Overriden to set the window's title.
        """
        return
        filename = self.active_editor.path if self.active_editor else ''
        self.window.title = filename if filename else 'Untitled'

    def create_central_pane(self):
        """ Create the central pane: the script editor.
        """
        self.editor_area = SplitEditorAreaPane()
        return self.editor_area

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        browser = PythonScriptBrowserPane()
        handler = lambda: self._open_file(browser.selected_file)
        browser.on_trait_change(handler, 'activated')
        self.stack_pane = StackPane()
        return [ browser, self.stack_pane ]

    ###########################################################################
    # 'DebuggerTask' interface.
    ###########################################################################

    debugger_service = Instance('plugins.debugger.debugger_service.DebuggerService')
    debug_process = Instance('plugins.debugger.python_process.PythonProcess')

    ready_to_debug = Property(Bool, depends_on='active_editor')

    def _get_ready_to_debug(self):
        return self.active_editor != None

    @on_trait_change('debug_process:_threads_items')
    def threads_changed(self, name, event):
        for k, thread in event.added.items():
            thread.on_trait_change(self.update_stack, '_frames')
        for k, thread in event.removed.items():
            thread.on_trait_change(self.update_stack, '_frames', remove=True)
            self.update_stack('', [])

    def update_stack(self, name, new):
        self.stack_pane.stack_frames = new

    @on_trait_change('stack_pane:selected')
    def show_frame(self, selected):
        if selected:
            editor = self.active_editor
            if selected._filename != editor.path:
                editor.path = selected._filename
            editor.select_line(selected._lineNo)

    def new(self):
        """ Opens a new empty window
        """
        editor = PythonEditor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def open(self):
        """ Shows a dialog to open a file.
        """
        dialog = FileDialog(parent=self.window.control, wildcard='*.py')
        if dialog.open() == OK:
            self._open_file(dialog.path)

    def save(self):
        """ Attempts to save the current file, prompting for a path if
            necessary. Returns whether the file was saved.
        """
        editor = self.active_editor
        try:
            editor.save()
        except IOError:
            # If you are trying to save to a file that doesn't exist, open up a
            # FileDialog with a 'save as' action.
            dialog = FileDialog(parent=self.window.control,
                                action='save as', wildcard='*.py')
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    def start_debugger(self):
        """ Start debugging the current file
        """
        editor = self.active_editor
        # Get new debug process
        self.debug_process = self.debugger_service.debug()
        self.debug_process.Start(editor.path)

    def stop_debugger(self):
        """ Stop the currently running debug instance
        """
        self.debug_process.Detach()

    def continue_debugger(self):
        """ Continue the currently running debug instance
        """
        thread = self.debug_process._threads.values()[0]
        thread.Resume()

    def step_into_line(self):
        """ Step into the next line
        """
        thread = self.debug_process._threads.values()[0]
        thread.StepInto()

    def step_over_line(self):
        """ Step over the next line
        """
        thread = self.debug_process._threads.values()[0]
        thread.StepOver()

    def step_out(self):
        """ Step out of the current line
        """
        thread = self.debug_process._threads.values()[0]
        thread.StepOut()

    @on_trait_change('debug_process:completedDebugging')
    def completed_debugging(self):
        self.debug_process = None

    @on_trait_change('debug_process:moduleLoaded')
    def module_loaded(self, filename):
        # send any breakpoints for that module
        for editor in self.editor_area.editors:
            if editor.path == filename:
                for breakpoint in editor.breakpoints:
                    bp = self.debug_process.AddBreakPoint(filename, breakpoint, '')
                    bp.Add()

    @on_trait_change('active_editor:breakpoints')
    def added_breakpoint(self, name, event):
        if self.debug_process:
            editor = self.active_editor
            for bp in event.added:
                bp = self.debug_process.AddBreakPoint(editor.path, bp, '')
                bp.Add()
            for bp in event.removed:
                # XXX This is ugly - probably need a breakpoint manager
                for brkp in self.debug_process._breakpoints.values():
                    if brkp.Filename == editor.path and brkp.LineNo == bp:
                        self.debug_process.RemoveBreakPoint(brkp)
                        break

    ###########################################################################
    # Protected interface.
    ###########################################################################

    def _open_file(self, filename):
        """ Opens the file at the specified path in the editor.
        """
        editor = PythonEditor(path=filename)
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def _prompt_for_save(self):
        """ Prompts the user to save if necessary. Returns whether the dialog
            was cancelled.
        """
        dirty_editors = dict([(editor.name, editor)
                              for editor in self.editor_area.editors
                              if editor.dirty])
        if not dirty_editors.keys():
            return True
        message = 'You have unsaved files. Would you like to save them?'
        dialog = ConfirmationDialog(parent=self.window.control,
                                    message=message, cancel=True,
                                    default=CANCEL, title='Save Changes?')
        result = dialog.open()
        if result == CANCEL:
            return False
        elif result == YES:
            for name, editor in dirty_editors.items():
                editor.save(editor.path)
        return True

    #### Trait change handlers ################################################

    @on_trait_change('window:closing')
    def _prompt_on_close(self, event):
        """ Prompt the user to save when exiting.
        """
        close = self._prompt_for_save()
        event.veto = not close

    #### Trait property getter/setters ########################################

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
예제 #7
0
 def create_central_pane(self):
     """ Create the central pane: the script editor.
     """
     self.editor_area = SplitEditorAreaPane()
     return self.editor_area
예제 #8
0
class ExampleTask(Task):
    """ A simple task for editing Python code.
    """

    #### Task interface #######################################################

    id = 'example.example_task'
    name = 'Multi-Tab Editor'

    active_editor = Property(Instance(IEditor),
                             depends_on='editor_area.active_editor')

    editor_area = Instance(IEditorAreaPane)

    menu_bar = SMenuBar(SMenu(TaskAction(name='New', method='new',
                                         accelerator='Ctrl+N'),
                              TaskAction(name='Open...', method='open',
                                         accelerator='Ctrl+O'),
                              TaskAction(name='Save', method='save',
                                         accelerator='Ctrl+S'),
                              id='File', name='&File'),
                        SMenu(DockPaneToggleGroup(),
                              id='View', name='&View'))

    tool_bars = [ SToolBar(TaskAction(method='new',
                                      tooltip='New file',
                                      image=ImageResource('document_new')),
                           TaskAction(method='open',
                                      tooltip='Open a file',
                                      image=ImageResource('document_open')),
                           TaskAction(method='save',
                                      tooltip='Save the current file',
                                      image=ImageResource('document_save')),
                           image_size = (32, 32)), ]

    ###########################################################################
    # 'Task' interface.
    ###########################################################################

    def _default_layout_default(self):
        return TaskLayout(
            left=PaneItem('example.python_script_browser_pane'))

    def activated(self):
        """ Overriden to set the window's title.
        """
        return
        filename = self.active_editor.path if self.active_editor else ''
        self.window.title = filename if filename else 'Untitled'

    def create_central_pane(self):
        """ Create the central pane: the script editor.
        """
        self.editor_area = SplitEditorAreaPane()
        return self.editor_area

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        browser = PythonScriptBrowserPane()
        handler = lambda: self._open_file(browser.selected_file)
        browser.on_trait_change(handler, 'activated')
        return [ browser ]

    ###########################################################################
    # 'ExampleTask' interface.
    ###########################################################################

    def new(self):
        """ Opens a new empty window
        """
        editor = PythonEditor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def open(self):
        """ Shows a dialog to open a file.
        """
        dialog = FileDialog(parent=self.window.control, wildcard='*.py')
        if dialog.open() == OK:
            self._open_file(dialog.path)

    def save(self):
        """ Attempts to save the current file, prompting for a path if
            necessary. Returns whether the file was saved.
        """
        editor = self.active_editor
        try:
            editor.save()
        except IOError:
            # If you are trying to save to a file that doesn't exist, open up a
            # FileDialog with a 'save as' action.
            dialog = FileDialog(parent=self.window.control,
                                action='save as', wildcard='*.py')
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    ###########################################################################
    # Protected interface.
    ###########################################################################

    def _open_file(self, filename):
        """ Opens the file at the specified path in the editor.
        """
        editor = PythonEditor(path=filename)
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def _prompt_for_save(self):
        """ Prompts the user to save if necessary. Returns whether the dialog
            was cancelled.
        """
        dirty_editors = dict([(editor.name, editor)
                              for editor in self.editor_area.editors
                              if editor.dirty])
        if not dirty_editors.keys():
            return True
        message = 'You have unsaved files. Would you like to save them?'
        dialog = ConfirmationDialog(parent=self.window.control,
                                    message=message, cancel=True,
                                    default=CANCEL, title='Save Changes?')
        result = dialog.open()
        if result == CANCEL:
            return False
        elif result == YES:
            for name, editor in dirty_editors.items():
                editor.save(editor.path)
        return True

    #### Trait change handlers ################################################

    @on_trait_change('window:closing')
    def _prompt_on_close(self, event):
        """ Prompt the user to save when exiting.
        """
        close = self._prompt_for_save()
        event.veto = not close

    #### Trait property getter/setters ########################################

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
예제 #9
0
 def create_central_pane(self):
     """ Create the central pane: the script editor.
     """
     self.editor_area = SplitEditorAreaPane()
     return self.editor_area
예제 #10
0
class ExampleTask(Task):
    """ A simple task for editing Python code.
    """

    #### Task interface #######################################################

    id = "example.example_task"
    name = "Multi-Tab Editor"

    active_editor = Property(Instance(IEditor),
                             observe="editor_area.active_editor")

    editor_area = Instance(IEditorAreaPane)

    menu_bar = SMenuBar(
        SMenu(
            TaskAction(name="New", method="new", accelerator="Ctrl+N"),
            TaskAction(name="Open...", method="open", accelerator="Ctrl+O"),
            TaskAction(name="Save", method="save", accelerator="Ctrl+S"),
            id="File",
            name="&File",
        ),
        SMenu(DockPaneToggleGroup(), id="View", name="&View"),
    )

    tool_bars = [
        SToolBar(
            TaskAction(
                method="new",
                tooltip="New file",
                image=ImageResource("document_new"),
            ),
            TaskAction(
                method="open",
                tooltip="Open a file",
                image=ImageResource("document_open"),
            ),
            TaskAction(
                method="save",
                tooltip="Save the current file",
                image=ImageResource("document_save"),
            ),
            image_size=(32, 32),
        )
    ]

    ###########################################################################
    # 'Task' interface.
    ###########################################################################

    def _default_layout_default(self):
        return TaskLayout(left=PaneItem("example.python_script_browser_pane"))

    def activated(self):
        """ Overriden to set the window's title.
        """
        return
        filename = self.active_editor.path if self.active_editor else ""
        self.window.title = filename if filename else "Untitled"

    def create_central_pane(self):
        """ Create the central pane: the script editor.
        """
        self.editor_area = SplitEditorAreaPane()
        return self.editor_area

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        browser = PythonScriptBrowserPane()
        handler = lambda: self._open_file(browser.selected_file)
        browser.on_trait_change(handler, "activated")
        return [browser]

    ###########################################################################
    # 'ExampleTask' interface.
    ###########################################################################

    def new(self):
        """ Opens a new empty window
        """
        editor = PythonEditor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def open(self):
        """ Shows a dialog to open a file.
        """
        dialog = FileDialog(parent=self.window.control, wildcard="*.py")
        if dialog.open() == OK:
            self._open_file(dialog.path)

    def save(self):
        """ Attempts to save the current file, prompting for a path if
            necessary. Returns whether the file was saved.
        """
        editor = self.active_editor
        try:
            editor.save()
        except IOError:
            # If you are trying to save to a file that doesn't exist, open up a
            # FileDialog with a 'save as' action.
            dialog = FileDialog(parent=self.window.control,
                                action="save as",
                                wildcard="*.py")
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    ###########################################################################
    # Protected interface.
    ###########################################################################

    def _open_file(self, filename):
        """ Opens the file at the specified path in the editor.
        """
        editor = PythonEditor(path=filename)
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    def _prompt_for_save(self):
        """ Prompts the user to save if necessary. Returns whether the dialog
            was cancelled.
        """
        dirty_editors = dict([(editor.name, editor)
                              for editor in self.editor_area.editors
                              if editor.dirty])
        if not dirty_editors.keys():
            return True
        message = "You have unsaved files. Would you like to save them?"
        dialog = ConfirmationDialog(
            parent=self.window.control,
            message=message,
            cancel=True,
            default=CANCEL,
            title="Save Changes?",
        )
        result = dialog.open()
        if result == CANCEL:
            return False
        elif result == YES:
            for name, editor in dirty_editors.items():
                editor.save(editor.path)
        return True

    #### Trait change handlers ################################################

    @on_trait_change("window:closing")
    def _prompt_on_close(self, event):
        """ Prompt the user to save when exiting.
        """
        close = self._prompt_for_save()
        event.veto = not close

    #### Trait property getter/setters ########################################

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None