コード例 #1
0
ファイル: step2.py プロジェクト: zyex1108/pyface
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    #### 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'),
              id='File',
              name='&File'),
        SMenu(DockPaneToggleGroup(), id='View', name='&View'))

    tool_bars = [
        SToolBar(TaskAction(method='new',
                            tooltip='New file',
                            image=ImageResource('document_new')),
                 image_size=(32, 32)),
    ]

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

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

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #2
0
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    #### 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)

    tool_bars = [ SToolBar(TaskAction(method='new',
                                      tooltip='New file',
                                      image=ImageResource('document_new')),
                           image_size = (32, 32)), ]

    ###########################################################################
    # 'Task' interface.
    ###########################################################################
    
    def _menu_bar_default(self):
        return SMenuBar(SMenu(TaskAction(name='New', method='new',
                                         accelerator='Ctrl+N'),
                              id='File', name='&File'),
                        SMenu(DockPaneToggleGroup(),
                              TaskToggleGroup(),
                              id='View', name='&View'))

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

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #3
0
    def test_factories(self):
        """ Does registering and unregistering factories work?
        """
        area = EditorAreaPane()
        area.register_factory(Editor, lambda obj: isinstance(obj, int))
        self.assertEqual(area.get_factory(0), Editor)
        self.assertEqual(area.get_factory("foo"), None)

        area.unregister_factory(Editor)
        self.assertEqual(area.get_factory(0), None)
コード例 #4
0
    def test_factories(self):
        """ Does registering and unregistering factories work?
        """
        area = EditorAreaPane()
        area.register_factory(Editor, lambda obj: isinstance(obj, int))
        self.assertEqual(area.get_factory(0), Editor)
        self.assertEqual(area.get_factory('foo'), None)

        area.unregister_factory(Editor)
        self.assertEqual(area.get_factory(0), None)
コード例 #5
0
class TestEditorAreaPane(unittest.TestCase, GuiTestAssistant):
    def setUp(self):
        GuiTestAssistant.setUp(self)
        self.area_pane = EditorAreaPane()

    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()
コード例 #6
0
ファイル: step8.py プロジェクト: enthought/pyface
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    # 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="Add Task",
                       method="add_task",
                       accelerator="Ctrl+A"),
            TaskAction(name="Remove Task",
                       method="remove_task",
                       accelerator="Ctrl+R"),
            id="File",
            name="&File",
        ),
        SMenu(DockPaneToggleGroup(),
              TaskToggleGroup(),
              id="View",
              name="&View"),
    )

    tool_bars = [
        SToolBar(
            TaskAction(
                method="new",
                tooltip="New file",
                image=ImageResource("document_new"),
            ),
            image_size=(32, 32),
        )
    ]

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

    def _default_layout_default(self):
        return TaskLayout(top=VSplitter(
            HSplitter(PaneItem("steps.pane1"), PaneItem("steps.pane2"))))

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        return [Pane1(), Pane2()]

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

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

    def add_task(self):
        """ Opens a new empty window
        """
        task3 = ThirdTask()
        self.window.add_task(task3)
        self.window.activate_task(task3)

    def remove_task(self):
        """ Opens a new empty window
        """
        task = self.window.tasks[0]
        window = self.window
        window.remove_task(self)
        window.activate_task(task)

    # 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 test_create_editor(self):
     """ Does creating an editor work?
     """
     area = EditorAreaPane()
     area.register_factory(Editor, lambda obj: isinstance(obj, int))
     self.assert_(isinstance(area.create_editor(0), Editor))
コード例 #8
0
ファイル: step2.py プロジェクト: bergtholdt/pyface
 def create_central_pane(self):
     """ Create the central pane: the script editor.
     """
     self.editor_area = EditorAreaPane()
     return self.editor_area
コード例 #9
0
ファイル: step5.py プロジェクト: bergtholdt/pyface
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    #### 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'),
                              id='File', name='&File'),
                        SMenu(DockPaneToggleGroup(),
                              TaskToggleGroup(),
                              id='View', name='&View'))

    tool_bars = [ SToolBar(TaskAction(method='new',
                                      tooltip='New file',
                                      image=ImageResource('document_new')),
                           image_size = (32, 32)), ]

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

    def _default_layout_default(self):
        return TaskLayout(
            top=Tabbed(PaneItem('steps.first_pane'),
                       PaneItem('steps.second_pane'),
                       PaneItem('steps.third_pane')))

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        return [ FirstPane(), SecondPane(), ThirdPane() ]

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #10
0
ファイル: task.py プロジェクト: pombreda/peppy2
class SkeletonTask(Task):
    """ A simple task for opening a blank editor.
    """

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

    id = 'peppy.framework.text_edit_task'
    name = 'Skeleton'

    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'),
                              id='File', name='&File'),
                        SMenu(id='Edit', name='&Edit'),
                        SMenu(#DockPaneToggleGroup(),
                              TaskToggleGroup(),
                              id='View', name='&View'))

    tool_bars = [ SToolBar(TaskAction(method='new',
                                      tooltip='New file',
                                      image=ImageResource('document_new')),
                           image_size = (32, 32)), ]

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

    def _default_layout_default(self):
        return TaskLayout(
            left=VSplitter(
                PaneItem('text_edit.pane1'),
                HSplitter(
                    PaneItem('text_edit.pane2'),
                    PaneItem('text_edit.pane3'),
                    ),
                ))

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        return [ SkeletonPane1(), SkeletonPane2(), SkeletonPane3() ]

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #11
0
 def setUp(self):
     GuiTestAssistant.setUp(self)
     self.area_pane = EditorAreaPane()
コード例 #12
0
class SkeletonTask(Task):
    """ A simple task for opening a blank editor.
    """

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

    id = 'omnivore.framework.text_edit_task'
    name = 'Skeleton'

    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'),
              id='File',
              name='&File'),
        SMenu(id='Edit', name='&Edit'),
        SMenu(  #DockPaneToggleGroup(),
            TaskToggleGroup(),
            id='View',
            name='&View'))

    tool_bars = [
        SToolBar(TaskAction(method='new',
                            tooltip='New file',
                            image=ImageResource('document_new')),
                 image_size=(32, 32)),
    ]

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

    def _default_layout_default(self):
        return TaskLayout(left=VSplitter(
            PaneItem('text_edit.pane1'),
            HSplitter(
                PaneItem('text_edit.pane2'),
                PaneItem('text_edit.pane3'),
            ),
        ))

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        return [SkeletonPane1(), SkeletonPane2(), SkeletonPane3()]

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #13
0
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    #### 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'),
              id='File',
              name='&File'),
        SMenu(DockPaneToggleGroup(),
              TaskToggleGroup(),
              id='View',
              name='&View'))

    tool_bars = [
        SToolBar(TaskAction(method='new',
                            tooltip='New file',
                            image=ImageResource('document_new')),
                 image_size=(32, 32)),
    ]

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

    def _default_layout_default(self):
        return TaskLayout(top=Tabbed(PaneItem('steps.first_pane'),
                                     PaneItem('steps.second_pane'),
                                     PaneItem('steps.third_pane')))

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        return [FirstPane(), SecondPane(), ThirdPane()]

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #14
0
ファイル: example_task.py プロジェクト: bergtholdt/pyface
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), show_tool_names=False), ]

    ###########################################################################
    # '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 = EditorAreaPane()
        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
コード例 #15
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),
                 show_tool_names=False),
    ]

    ###########################################################################
    # '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 = EditorAreaPane()
        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 list(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 list(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
コード例 #16
0
ファイル: test_dock_pane.py プロジェクト: enthought/pyface
 def create_central_pane(self):
     return EditorAreaPane()
コード例 #17
0
ファイル: example_task.py プロジェクト: ovevans/pyface
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),
            show_tool_names=False,
        )
    ]

    # ------------------------------------------------------------------------
    # '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 = EditorAreaPane()
        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.observe(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 ------------------------------------------------

    @observe("window:closing")
    def _prompt_on_close(self, event):
        """ Prompt the user to save when exiting.
        """
        close = self._prompt_for_save()
        window = event.new
        window.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
コード例 #18
0
ファイル: task.py プロジェクト: pombreda/peppy2
class FrameworkTask(Task):
    """ A simple task for opening a blank editor.
    """
    
    # Class properties (not traits!)
    
    new_file_text = ''

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

    id = 'peppy.framework.framework_task'
    name = 'Framework'

    icon = Instance(ImageResource)

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

    editor_area = Instance(IEditorAreaPane)
    
    #### FrameworkTask interface ##############################################
    
    preferences_helper = Instance(PreferencesHelper)
    
    status_bar_debug_width = Int(150)
    
    start_new_editor_in_new_window = Bool(False)
    
    #### 'IAbout' interface ###################################################
    
    about_title = Unicode('Peppy2')
    
    about_version = Unicode
    
    about_description = Unicode('Edit stuff.')
    
    about_website = Str('http://peppy.flipturn.org')
    
    about_image = Instance(ImageResource, ImageResource('peppy128'))
    
    #### 'IErrorReporter' interface ###########################################
    
    error_email_from = Str
    
    error_email_passwd = Str
    
    error_email_to = Str
    
    def _about_version_default(self):
        from peppy2 import __version__
        return __version__
    
    ###########################################################################
    # 'Task' interface.
    ###########################################################################
    
    def _icon_default(self):
        return ImageResource('peppy48')

    def _menu_bar_default(self):
        menus = []
        self.add_menu(menus, "Menu", "File", "NewGroup", "OpenGroup", "SaveGroup", "ExitGroup")
        self.add_menu(menus, "Menu", "Edit", "UndoGroup", "CopyPasteGroup", "SelectGroup", "FindGroup", "PrefGroup")
        self.add_menu(menus, "Menu", "View", "TaskGroup")
        self.add_menu(menus, "Menu", "Window", "WindowGroup")
        self.add_menu(menus, "Menu", "Help", "AboutGroup", "DocGroup", "BugReportGroup", "DebugGroup")
        
        return SMenuBar(*menus)

    def _tool_bars_default(self):
        return [ SToolBar(self.get_groups("ToolBar", "File", "NewGroup", "OpenGroup", "SaveGroup"),
                          Group(UndoAction(),
                                RedoAction(),
                                id="Undo"),
                          show_tool_names=False), ]

    def _status_bar_default(self):
        return FrameworkStatusBarManager(message="Hi!", debug_width=self.status_bar_debug_width)

    def _default_layout_default(self):
        return TaskLayout(
            left=VSplitter(
                PaneItem('peppy.framework.file_browser_pane'),
                ))

    def activated(self):
        log.debug("  status bar: %s" % self.status_bar)
        active = self.active_editor
        if active:
            self.status_bar.message = active.name
        else:
            self.status_bar.message = self.name
        self.window.icon = self.icon

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

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

    ###########################################################################
    # 'FrameworkTask' interface.
    ###########################################################################

    def new(self, source=None, **kwargs):
        """ Opens a new tab
        
        :param source: optional :class:`FileGuess` or :class:`Editor` instance
        that will load a new file or create a new view of the existing editor,
        respectively.
        """
        editor = self.get_editor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        if hasattr(source, 'get_metadata') or source is None:
            editor.load(source, **kwargs)
            if source is not None:
                self.window.application.successfully_loaded_event = source.metadata.uri
        else:
            editor.view_of(source, **kwargs)
        self.activated()

    def new_window(self, task=None, view=None):
        """ Opens a new window
        
        With no arguments, opens an empty window with the default task.
        
        :keyword task: optional task to set the task of the new window
        
        :keyword view: optional :class:`Editor` instance that will set the
        task of the new window and will create a new view of the editor in the
        first tab
        """
        log.debug("Opening new window!!!")
        window = self.window.application.create_window()
        log.debug("  window=%s" % str(window))
        log.debug("  self=%s" % str(self.window))
        log.debug("  task type: %s" % str(task))
        log.debug("  view of: %s" % str(view))
        task_id = None
        if view is not None:
            task_cls = view.editor_area.task.__class__
            log.debug("  task_cls: %s" % str(task_cls))
        elif task is not None:
            if isinstance(task, FrameworkTask):
                task_cls = task.__class__
            else:
                task_cls = task
        else:
            task_id = self.window.application.startup_task
        if task_id is None:
            task = task_cls()
            task_id = task.id
        log.debug("  task id: %s" % task_id)
        log.debug("  returned factory: %s" % self.window.application._get_task_factory(task_id))
        for factory in self.window.application.task_factories:
            log.debug("    factory: %s, %s" % (factory.id, factory))
        
        task = self.window.application.create_task(task_id)
        log.debug("  created task: %s" % task)
        window.add_task(task)
        window.activate_task(task)
        if view is not None:
            task.new(view)
        window.open()
        log.debug("All windows: %s" % self.window.application.windows)

    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')
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    def allow_different_task(self, guess, other_task):
        """Hook to allow tasks to abort loading different task window.
        
        This method allows a hook to confirm that the user wants to load a file
        that can't be handled by the current task.  For example, this can be
        used to prompt with a dialog box.
        
        :rtype: Boolean; True means continue with the file load
        """
        return True

    def debug(self):
        """Debug stuff!
        """
        action_schemas = list(self.menu_bar.items)
        action_schemas.extend(self.tool_bars)
        for action in self._iter_schema_items(action_schemas):
            if hasattr(action, 'name'):
                action.name = action.name + "!"

    ###########################################################################
    # 'FrameworkTask' convenience functions.
    ###########################################################################
    
    def get_preferences(self):
        return self.window.application.get_preferences(self.preferences_helper)

    def add_menu(self, menu, location, menu_name, *group_names):
        items = []
        for group_name in group_names:
            self.add_actions_and_groups(items, location, menu_name, group_name)
        menu.append(SMenu(*items, id=menu_name, name=menu_name))

    def add_actions_and_groups(self, menu_items, location, menu_name, group_name):
        actions = self.get_actions(location, menu_name, group_name)
        groups = []
        group_suffix = ""
        group_index = 0
        current = []
        
        for item in actions:
            if isinstance(item, Group) or isinstance(item, SMenu):
                if current:
                    group = Group(*current, id="%s%s" % (group_name, group_suffix))
                    group_index += 1
                    group_suffix = str(group_index)
                    groups.append(group)
                    current = []
                groups.append(item)
            else:
                current.append(item)
        if current:
            group = Group(*current, id="%s%s" % (group_name, group_suffix))
            groups.append(group)

        menu_items.append(Separator(id="%sStart" % group_name, separator=False))
        for group in groups:
            menu_items.append(group)
        menu_items.append(Separator(id="%sEnd" % group_name, separator=False))

    def get_group(self, location, menu_name, group_name):
        actions = self.get_actions(location, menu_name, group_name)
        return Group(*actions, id=group_name)
    
    def get_groups(self, location, menu_name, *group_names):
        actions = []
        for group_name in group_names:
            actions.extend(self.get_actions(location, menu_name, group_name))
        return Group(*actions, id=menu_name)

    def get_actions(self, location, menu_name, group_name):
        if location == "Menu":
            if menu_name == "File":
                if group_name == "NewGroup":
                    return [
                        SMenu(NewFileGroup(), id="NewFileGroup", name="New"),
                        ]
                elif group_name == "OpenGroup":
                    return [
                        OpenAction(),
                        ]
                elif group_name == "SaveGroup":
                    return [
                        SaveAction(),
                        SaveAsAction(),
                        ]
                elif group_name == "ExitGroup":
                    return [
                        ExitAction(),
                        ]
            elif menu_name == "Edit":
                if group_name == "UndoGroup":
                    return [
                        UndoAction(),
                        RedoAction(),
                        ]
                elif group_name == "PrefGroup":
                    return [
                        Group(PreferencesAction(), absolute_position="last"),
                        ]
            elif menu_name == "View":
                if group_name == "TaskGroup":
                    return [
                        DockPaneToggleGroup(),
                        TaskToggleGroup(),
                        ]
            elif menu_name == "Window":
                if group_name == "WindowGroup":
                    return [
                        NewViewAction(),
                        NewWindowAction(),
                        ]
            elif menu_name == "Help":
                if group_name == "AboutGroup":
                    return [
                        AboutAction()
                        ]
                elif group_name == "DebugGroup":
                    return [
                        SMenu(TaskAction(name='Dynamic Menu Names', method='debug',
                                         tooltip='Do some debug stuff',
                                         image=ImageResource('debug')),
                              id="Debug", name="Debug"),
                        ]
        
        if location.startswith("Tool"):
            if menu_name == "File":
                if group_name == "NewGroup":
                    return [
                        TaskAction(method='new',
                                   tooltip='New file',
                                   image=ImageResource('file_new')),
                        ]
                elif group_name == "OpenGroup":
                    return [
                        OpenAction(),
                        ]
                elif group_name == "SaveGroup":
                    return [
                        SaveAction(),
                        SaveAsAction(),
                        ]
                
        return []

    def get_editor(self):
        raise NotImplementedError

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

    def _iter_schema_items(self, items):
        """Generator to pull all Actions out of the list of Schemas
        
        Schemas may contain other schemas, which requires this recursive
        approach.
        
        Usage:
            action_schemas = list(self.menu_bar.items)
            action_schemas.extend(self.tool_bars)
            for action in self._iter_schema_items(action_schemas):
                # do something
        """
        for item in items:
            if hasattr(item, 'items'):
                for a in self._iter_schema_items(item.items):
                    yield a
            else:
                yield item

    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?'
        result = self.window.confirm(message=message, cancel=True,
                                    default=CANCEL, title='Save Changes?')
        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


    ###
    @classmethod
    def can_edit(cls, mime):
        raise NotImplementedError
コード例 #19
0
class FrameworkTask(Task):
    """ A simple task for opening a blank editor.
    """
    
    # Class properties (not traits!) because they must be available in a TaskFactory 
    
    new_file_text = ''
    
    about_application = "about://omnivore"  # URL to load if no document specified on the command line

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

    id = 'omnivore.framework.framework_task'
    name = 'Framework'

    icon = Instance(ImageResource)

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

    editor_area = Instance(IEditorAreaPane)
    
    #### FrameworkTask interface ##############################################
    
    preferences_helper = Instance(PreferencesHelper)
    
    status_bar_debug_width = Int(150)
    
    start_new_editor_in_new_window = Bool(False)
    
    print_data = Any
    
    document_changed = Event
    
    keyboard_shortcuts = Any

    # class attribute

    activated_task_ids = set()
    
    #### 'IAbout' interface ###################################################
    
    about_title = Unicode('Omnivore XL')
    
    about_version = Unicode
    
    about_description = Unicode('Byte into the meat of 8-bit Software!\n\nSend feedback to: [email protected]')
    
    about_website = Str('http://playermissile.com/omnivore')
    
    about_image = Instance(ImageResource, ImageResource('omnivore256'))
    
    #### 'IErrorReporter' interface ###########################################
    
    error_email_from = Str
    
    error_email_passwd = Str
    
    error_email_to = Str
    
    def _about_version_default(self):
        from omnivore import __version__
        return __version__
    
    ###########################################################################
    # 'Task' interface.
    ###########################################################################
    
    def _icon_default(self):
        return ImageResource('omnivore')

    def _menu_bar_default(self):
        menus = []
        self.add_menu(menus, "Menu", "File", "NewGroup", "OpenGroup", "ImportGroup", "SaveGroup", "RevertGroup", "PrintGroup", "ExportGroup", "ExitGroup")
        self.add_menu(menus, "Menu", "Edit", "UndoGroup", "CopyPasteGroup", "SelectGroup", "FindGroup", "PrefGroup")
        self.add_menu(menus, "Menu", "View", "ViewPredefinedGroup", "ViewZoomGroup", "ViewChangeGroup", "ViewConfigGroup", "ViewToggleGroup", "TaskGroup", "ViewDebugGroup")
        self.add_menu(menus, "Menu", "Documents", "DocumentGroup")
        self.add_menu(menus, "Menu", "Window", "NewTaskGroup", "WindowGroup")
        self.add_menu(menus, "Menu", "Help", "AboutGroup", "DocGroup", "BugReportGroup", "DebugGroup")
        
        return SMenuBar(*menus)

    def _tool_bars_default(self):
        return [ SToolBar(self.get_groups("Tool", "File", "NewGroup", "OpenGroup", "SaveGroup"),
                          self.get_groups("Tool", "Edit", "UndoGroup", "CopyPasteGroup", "SelectGroup", "FindGroup"),
                          self.get_groups("Tool", "View", "ViewZoomGroup", "ViewChangeGroup", "ViewConfigGroup"),
                          show_tool_names=False, id="%s:ToolBar" % self.id),
                 ]

    def _status_bar_default(self):
        return FrameworkStatusBarManager(message="Hi!", debug_width=self.status_bar_debug_width)

    def _default_layout_default(self):
        return TaskLayout(
            left=VSplitter(
                PaneItem('omnivore.framework.file_browser_pane'),
                ))
    
    def _keyboard_shortcuts_default(self):
        actions = []
        
        # Give each keyboard action a wx ID so that it can be identified in the
        # menu callback
        for action in self.get_keyboard_actions():
            id = wx.NewId()
            action.keyboard_shortcut_id = id
            actions.append(action)
        return actions

    ##### Task setup/cleanup

    def initialized(self):
        self.window.application.remember_perspectives(self.window)
        self.initialize_class_preferences()
        c = self.editor_area.control
        c.Bind(aui.EVT_AUINOTEBOOK_TAB_RIGHT_DOWN, self.on_tab_context_menu)
        c.Bind(aui.EVT_AUINOTEBOOK_BG_RIGHT_DOWN, self.on_tab_background_context_menu)
        c.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_tab_pane_close)
    
    def initialize_class_preferences(self):
        pass

    def activated(self):
        log.debug("  status bar: %s" % self.status_bar)
        active = self.active_editor
        if active:
            self.status_bar.message = active.name
        else:
            self.status_bar.message = self.name
        self.window.icon = self.icon
        self.set_keyboard_shortcuts()
        self._active_editor_tab_change(None)
        visible = self.pane_layout_initial_visibility()
        for pane in self.window.dock_panes:
            if pane.id in visible:
                pane.visible = visible[pane.id]

        if self.id not in self.activated_task_ids:
            self.activated_task_ids.add(self.id)
            self.first_time_activated()

    def first_time_activated(self):
        """ Called the first time a task is activated in the application.
        """
        pass

    def pane_layout_initial_visibility(self):
        return {}

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

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        browser = FileBrowserPane()
        handler = lambda: self.window.application.load_file(browser.selected_file, self)
        browser.on_trait_change(handler, 'activated')
        return [ browser ]
    
    def prepare_destroy(self):
        self.window.application.remember_perspectives(self.window)
        self.destroy_minibuffer()

    ###########################################################################
    # 'FrameworkTask' interface.
    ###########################################################################

    def new(self, source=None, **kwargs):
        """ Opens a new tab
        
        :param source: optional :class:`FileGuess` or :class:`Editor` instance
        that will load a new file or create a new view of the existing editor,
        respectively.
        """
        editor = self.get_editor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        if hasattr(source, 'get_metadata') or source is None:
            editor.load(source, **kwargs)
            if source is not None:
                self.window.application.successfully_loaded_event = source.metadata.uri
        elif hasattr(source, 'document_id'):
            source.load_permute(editor)
            editor.init_extra_metadata(source)
            editor.view_document(source)
            self.window.application.successfully_loaded_event = source.metadata.uri
        else:
            editor.view_document(source.document, source)
        self.activated()
    
    def find_tab_or_open(self, document):
        for editor in self.editor_area.editors:
            if editor.document == document:
                self.editor_area.activate_editor(editor)
                return
        self.new(document)

    def new_window(self, task=None, view=None):
        """ Opens a new window
        
        With no arguments, opens an empty window with the default task.
        
        :keyword task: optional task to set the task of the new window
        
        :keyword view: optional :class:`Editor` instance that will set the
        task of the new window and will create a new view of the editor in the
        first tab
        """
        log.debug("Opening new window!!!")
        window = self.window.application.create_window()
        log.debug("  window=%s" % str(window))
        log.debug("  self=%s" % str(self.window))
        log.debug("  task type: %s" % str(task))
        log.debug("  view of: %s" % str(view))
        task_id = None
        if view is not None:
            task_cls = view.editor_area.task.__class__
            log.debug("  task_cls: %s" % str(task_cls))
        elif task is not None:
            if isinstance(task, FrameworkTask):
                task_cls = task.__class__
            else:
                task_cls = task
        else:
            task_id = self.window.application.startup_task
        if task_id is None:
            task = task_cls()
            task_id = task.id
        log.debug("  task id: %s" % task_id)
        log.debug("  returned factory: %s" % self.window.application._get_task_factory(task_id))
        for factory in self.window.application.task_factories:
            log.debug("    factory: %s, %s" % (factory.id, factory))
        
        task = self.window.application.create_task(task_id)
        log.debug("  created task: %s" % task)
        window.add_task(task)
        window.activate_task(task)
        if view is not None:
            task.new(view)
        window.open()
        log.debug("All windows: %s" % self.window.application.windows)

    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')
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    def allow_different_task(self, guess, other_task):
        """Hook to allow tasks to abort loading different task window.
        
        This method allows a hook to confirm that the user wants to load a file
        that can't be handled by the current task.  For example, this can be
        used to prompt with a dialog box.
        
        :rtype: Boolean; True means continue with the file load in a separate
        task window
        """
        return True

    def _print_data_default(self):
        data = wx.PrintData()
        data.SetPaperId(wx.PAPER_LETTER)
        data.SetOrientation(wx.PORTRAIT)
        return data

    def page_setup(self):
        data = wx.PageSetupDialogData(self.print_data)
        data.SetDefaultMinMargins(True)

        dlg = wx.PageSetupDialog(self.window.control, data)

        if dlg.ShowModal() == wx.ID_OK:
            data = dlg.GetPageSetupData().GetPrintData()
            self.print_data = wx.PrintData(data)  # Force a copy

        dlg.Destroy()

    def debug(self):
        """Debug stuff!
        """
        action_schemas = list(self.menu_bar.items)
        action_schemas.extend(self.tool_bars)
        for action in self._iter_schema_items(action_schemas):
            if hasattr(action, 'name'):
                action.name = action.name + "!"

    def ask_attempt_loading_as_octet_stream(self, guess, other_task):
        return self.window.confirm("%s\n\nwas identified with a MIME type of %s\nand can also be edited in a %s window.\n\nOpen here in the %s window instead?" % (guess.metadata.uri, guess.metadata.mime, other_task.new_file_text, self.name), "Edit in %s?" % self.name) == YES

    ###########################################################################
    # 'FrameworkTask' convenience functions.
    ###########################################################################
    
    def get_preferences(self):
        return self.window.application.get_preferences(self.preferences_helper)

    def create_menu(self, location, menu_name, *group_names):
        items = []
        for group_name in group_names:
            self.add_actions_and_groups(items, location, menu_name, group_name)
        return SMenu(*items, id=menu_name, name=menu_name)

    def add_menu(self, menu, location, menu_name, *group_names):
        entry = self.create_menu(location, menu_name, *group_names)
        menu.append(entry)

    def add_actions_and_groups(self, menu_items, location, menu_name, group_name):
        actions = self.get_actions_wrapper(location, menu_name, group_name)

        groups = []
        group_suffix = ""
        group_index = 0
        current = []
        
        for item in actions:
            if isinstance(item, Group) or isinstance(item, SMenu):
                if current:
                    group = Group(*current, id="%s%s" % (group_name, group_suffix))
                    group_index += 1
                    group_suffix = str(group_index)
                    groups.append(group)
                    current = []
                groups.append(item)
            else:
                current.append(item)
        if current:
            group = Group(*current, id="%s%s" % (group_name, group_suffix))
            groups.append(group)

        menu_items.append(Separator(id="%sStart" % group_name, separator=False))
        for group in groups:
            menu_items.append(group)
        menu_items.append(Separator(id="%sEnd" % group_name, separator=False))

    def get_group(self, location, menu_name, group_name):
        actions = self.get_actions_wrapper(location, menu_name, group_name)
        return Group(*actions, id=group_name)
    
    def get_groups(self, location, menu_name, *group_names):
        actions = []
        for group_name in group_names:
            actions.extend(self.get_actions_wrapper(location, menu_name, group_name))
        return Group(*actions, id=menu_name)

    def get_actions_wrapper(self, location, menu_name, group_name):
        actions = self.get_actions(location, menu_name, group_name)
        if actions is None:
            # fall back to this class if it's not found in subclass
            actions = FrameworkTask.get_actions(self, location, menu_name, group_name)
        return actions

    def get_actions(self, location, menu_name, group_name):
        # allow spaces in menu names by removing them for function lookup
        menu_lookup = menu_name.replace(" ","")
        method_name = "get_actions_%s_%s_%s" % (location, menu_lookup, group_name)
        try:
            method = getattr(self, method_name)
            actions = method()
        except AttributeError:
            log.info("%s actions not found for %s/%s in %s" % (location, menu_name, group_name, self.id))
            actions = []
        return actions
    
    def get_actions_Menu_File_NewGroup(self):
        return [
            SMenu(NewFileGroup(), id="NewFileGroup", name="New"),
            ]
    
    def get_actions_Menu_File_OpenGroup(self):
        return [
            OpenAction(),
            ]
    
    def get_actions_Menu_File_SaveGroup(self):
        return [
            SaveAction(),
            SaveAsAction(),
            ]
    
    def get_actions_Menu_File_RevertGroup(self):
        return [
            RevertAction(),
            ]
    
    def get_actions_Menu_File_PrintGroup(self):
        return [
            PageSetupAction(),
            PrintPreviewAction(),
            PrintAction(),
            ]
    
    def get_actions_Menu_File_ExportGroup(self):
        return [
            SaveAsPDFAction(),
            ]
    
    def get_actions_Menu_File_ExitGroup(self):
        return [
            ExitAction(),
            ]

    def get_actions_Menu_Edit_UndoGroup(self):
        return [
            UndoAction(),
            RedoAction(),
            ]
    
    def get_actions_Menu_Edit_CopyPasteGroup(self):
        return [
            CutAction(),
            CopyAction(),
            PasteAction(),
            ]
    
    def get_actions_Menu_Edit_SelectGroup(self):
        return [
            SelectAllAction(),
            SelectNoneAction(),
            SelectInvertAction(),
            ]
    
    def get_actions_Menu_Edit_PrefGroup(self):
        return [
            Group(PreferencesAction(), absolute_position="last"),
            ]
    
    def get_actions_Menu_View_TaskGroup(self):
        return [
            DockPaneToggleGroup(),
            TaskToggleGroup(),
            ]
    
    def get_actions_Menu_Documents_DocumentGroup(self):
        return [
            DocumentSelectGroup(),
            ]
    
    def get_actions_Menu_Window_NewTaskGroup(self):
        return [
            SMenu(
                NewViewInGroup(id="a1", separator=True),
                id='WindowTabGroupSubmenu2', name="New View In..."),
            ]
    
    def get_actions_Menu_Window_WindowGroup(self):
        return [
            NewWindowAction(),
            ]
    
    def get_actions_Menu_Help_AboutGroup(self):
        return [
            AboutAction()
            ]
    
    def get_actions_Menu_Help_BugReportGroup(self):
        return [
            OpenLogDirectoryAction(),
            ]
    
    def get_actions_Menu_Help_DebugGroup(self):
        return [
            SMenu(TaskAction(name='Dynamic Menu Names', method='debug',
                             tooltip='Do some debug stuff',
                             image=ImageResource('debug')),
                  WidgetInspectorAction(),
                  id="Debug", name="Debug"),
            ]
    
    def get_actions_Tool_File_NewGroup(self):
        return [
            TaskAction(method='new',
                       tooltip='New file',
                       image=ImageResource('file_new')),
            ]
    
    def get_actions_Tool_File_OpenGroup(self):
        return [
            OpenAction(),
            ]
    
    def get_actions_Tool_File_SaveGroup(self):
        return [
            SaveAction(),
            SaveAsAction(),
            ]
    
    def get_actions_Tool_Edit_UndoGroup(self):
        return [
            UndoAction(),
            RedoAction(),
            ]
    
    def get_keyboard_actions(self):
        """Return a list of actions to be used as keyboard shortcuts only, not
        appearing in a menubar or toolbar
        """
        return []
    
    def parse_accelerator(self, text, id):
        if text:
            entry = wx.AcceleratorEntry(cmdID=id)
            entry.FromString(text)
            return entry
        return None
    
    def create_accelerator_table(self):
        shortcut_map = {}
        table_entries = []
        for action in self.keyboard_shortcuts:
            id = action.keyboard_shortcut_id
            table_entry = self.parse_accelerator(action.accelerator, id)
            if table_entry is not None:
                shortcut_map[id] = action
                table_entries.append(table_entry)
        log.debug("Accelerator table entries: %s" % str([t.ToString() for t in table_entries]))
        return shortcut_map, wx.AcceleratorTable(table_entries)
    
    def on_keyboard_shortcut(self, event):
        id = event.GetId()
        log.debug("Keyboard shortcut! %s", id)
        try:
            action = self.keyboard_shortcut_map[id]
        except KeyError:
            log.error("Keyboard shortcut for %s not in this task" % id)
            return
        event = ActionEvent(task=self)
        # Set the task so that dependent traits (e.g.  active_editor for
        # EditorActions) will be available
        action.task = self
        action.perform(event)
    
    def set_keyboard_shortcuts(self):
        shortcut_map, table = self.create_accelerator_table()
        self.window.control.SetAcceleratorTable(table)
        self.keyboard_shortcut_map = shortcut_map
        for id in shortcut_map.keys():
            self.window.control.Bind(wx.EVT_MENU, self.on_keyboard_shortcut, id=id)

    def get_editor(self):
        raise NotImplementedError
    
    def restore_toolbars(self, window):
        toolbars = window._window_backend.get_toolbars()
        window._window_backend.show_toolbars(toolbars)

    ###########################################################################
    # Minibuffer convenience routines
    ###########################################################################
    
    minibuffer_pane_name = "omnivore.framework.minibuffer"
    
    def create_minibuffer_info(self):
        log.debug("Creating space for minibuffer")
        info = aui.AuiPaneInfo()
        info.Caption("Minibuffer")
        info.LeftDockable(False)
        info.Name(self.minibuffer_pane_name)
        info.RightDockable(False)
        info.Layer(99)
        info.Bottom()
        info.Hide()
        info.DockFixed(True)
        info.CaptionVisible(False)  # hides the caption bar & close button
        info.minibuffer = None
        return info
    
    def show_minibuffer(self, minibuffer, **kwargs):
        # minibuffer_pane_info is stored in the TaskWindow instance because all
        # tasks use the same minibuffer pane in the AUI manager
        try:
            info = self.window.minibuffer_pane_info
        except AttributeError:
            panel = wx.Panel(self.window.control, style=wx.NO_BORDER)
            sizer = wx.BoxSizer(wx.HORIZONTAL)
            close_image = ImageResource('cancel')
            bmp = close_image.create_bitmap()
            close = wx.BitmapButton(panel, -1, bmp, size=(bmp.GetWidth()+10, bmp.GetHeight()+10), style=wx.NO_BORDER)
            close.Bind(wx.EVT_BUTTON, self.on_hide_minibuffer_or_cancel)
            sizer.Add(close, 0, wx.EXPAND)
            panel.SetSizer(sizer)
            info = self.create_minibuffer_info()
            self.window._aui_manager.AddPane(panel, info)
            # info.window is set to panel in the AUI code
            self.window.minibuffer_pane_info = info
        repeat = False
        if info.minibuffer is not None:
            if info.minibuffer.is_repeat(minibuffer):
                log.debug("Reusing old minibuffer control: %s" % info.minibuffer.control)
                repeat = True
            else:
                log.debug("Removing old minibuffer control: %s" % info.minibuffer.control)
                info.window.GetSizer().Hide(0)
                info.window.GetSizer().Remove(0)
                info.minibuffer.destroy_control()
                log.debug("Children: %s" % info.window.GetSizer().Children)
        if not repeat:
            minibuffer.create_control(info.window)
            info.window.GetSizer().Insert(0, minibuffer.control, 1, wx.EXPAND)
            info.window.GetSizer().Layout()
            minibuffer.focus()
            info.minibuffer = minibuffer
            log.debug("Window: %s, info: %s" % (self.window, info))
        else:
            info.minibuffer.focus()
            info.minibuffer.repeat(minibuffer)  # Include new minibuffer
        if not info.IsShown():
            info.Show()
            self.window._aui_manager.Update()
    
    def find_cancel_edit(self, control):
        while control is not None:
            if hasattr(control, "cancel_edit"):
                control.cancel_edit()
                return
            else:
                control = control.GetParent()
    
    def on_hide_minibuffer_or_cancel(self, event):
        try:
            info = self.window.minibuffer_pane_info
        except AttributeError:
            info = None
        if info is None or not info.IsShown():
            focused = self.window.control.FindFocus()
            self.find_cancel_edit(focused)
        else:
            info.Hide()
            self.window._aui_manager.Update()
    
    def change_minibuffer_editor(self, editor):
        """Inform the currently open minibuffer that the editor has changed
        so it can update its internal state to match
        """
        try:
            info = self.window.minibuffer_pane_info
        except AttributeError:
            return
        if info.minibuffer is not None:
            info.minibuffer.change_editor(editor)
    
    def destroy_minibuffer(self):
        try:
            info = self.window.minibuffer_pane_info
        except AttributeError:
            return
        self.window._aui_manager.DetachPane(info.minibuffer.control)
        info.minibuffer.destroy_control()

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

    def _iter_schema_items(self, items):
        """Generator to pull all Actions out of the list of Schemas
        
        Schemas may contain other schemas, which requires this recursive
        approach.
        
        Usage:
            action_schemas = list(self.menu_bar.items)
            action_schemas.extend(self.tool_bars)
            for action in self._iter_schema_items(action_schemas):
                # do something
        """
        for item in items:
            if hasattr(item, 'items'):
                for a in self._iter_schema_items(item.items):
                    yield a
            else:
                yield item

    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?'
        result = self.window.confirm(message=message, cancel=True,
                                    default=CANCEL, title='Save Changes?')
        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

    @on_trait_change('editor_area:active_editor')
    def _active_editor_tab_change(self, event):
        """ Prompt the user to save when exiting.
        """
        active = self.active_editor
        if active is not None:
            self.window._title = "%s - %s %s" % (self.active_editor.name, self.about_title, self.about_version)
            # Can't call the following during the trait handler because the
            # trait handlers for the toolbar actions won't be completed yet.
            # When delayed until afterwards, the toolbar update works properly.
            wx.CallAfter(active.made_current_active_editor)
        else:
            self.window._title = "%s %s" % (self.about_title, self.about_version)

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

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


    ###
    @classmethod
    def can_edit(cls, document):
        raise NotImplementedError
    
    @classmethod
    def get_match_score(cls, document):
        """Return a number based on how good of a match this task is to the
        incoming Document.
        
        0 = generic match
        ...
        10 = absolute match
        """
        return 0

    #### wx event handlers

    def on_tab_context_menu(self, evt):
        pass

    def on_tab_background_context_menu(self, evt):
        pass

    def on_tab_pane_close(self, evt):
        # Close button only appears on active tab, so we can assume the tab
        # being closed is the currenty active tab
        notebook = evt.GetEventObject()
        wx.CallAfter(self.close_dirty_tab, notebook, notebook.GetPageCount() == 1)
        evt.Veto()

    def close_dirty_tab(self, notebook, replace=False):
        active = self.active_editor
        if active.dirty:
            result = self.confirm('This file has unsaved changes. Close anyway?', default=NO, title='Save Changes?')
        else:
            result = YES
        if result == YES:
            notebook.Freeze()
            if replace:
                self.new()
            active.close()
            notebook.Thaw()

    #### convenience functions
    
    def confirm(self, message, title=None, cancel=False, default=NO, no_label="", yes_label=""):
        """ Convenience method to show a confirmation dialog. """

        from pyface.confirmation_dialog import ConfirmationDialog

        if title is None:
            title = "Confirmation"

        dialog = ConfirmationDialog(parent=self.window.control, message=message, cancel=cancel, default=default, title=title, no_label=no_label, yes_label=yes_label)

        return dialog.open()

    def information(self, message, title='Information'):
        """ Convenience method to show an information message dialog. """

        from pyface.message_dialog import information

        return information(self.window.control, message, title)

    def warning(self, message, title='Warning'):
        """ Convenience method to show a warning message dialog. """

        from pyface.message_dialog import warning

        return warning(self.window.control, message, title)

    def error(self, message, title='Error'):
        """ Convenience method to show an error message dialog. """

        from pyface.message_dialog import error

        return error(self.window.control, message, title)
コード例 #20
0
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

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

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

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

    editor_area = Instance(IEditorAreaPane)

    tool_bars = [
        SToolBar(
            TaskAction(
                method="new",
                tooltip="New file",
                image=ImageResource("document_new"),
            ),
            image_size=(32, 32),
        )
    ]

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

    def _menu_bar_default(self):
        return SMenuBar(
            SMenu(
                TaskAction(name="New", method="new", accelerator="Ctrl+N"),
                id="File",
                name="&File",
            ),
            SMenu(
                DockPaneToggleGroup(),
                TaskToggleGroup(),
                id="View",
                name="&View",
            ),
        )

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

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

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

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

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
コード例 #21
0
 def test_create_editor(self):
     """ Does creating an editor work?
     """
     area = EditorAreaPane()
     area.register_factory(Editor, lambda obj: isinstance(obj, int))
     self.assertTrue(isinstance(area.create_editor(0), Editor))
コード例 #22
0
 def create_central_pane(self):
     """ Create the central pane: the script editor.
     """
     self.editor_area = EditorAreaPane()
     return self.editor_area
コード例 #23
0
ファイル: task.py プロジェクト: jomason/omnivore
class FrameworkTask(Task):
    """ A simple task for opening a blank editor.
    """

    # Class properties (not traits!) because they must be available in a TaskFactory

    new_file_text = ''

    about_application = "about://omnivore"  # URL to load if no document specified on the command line

    editor_id = 'omnivore.framework.framework_task'

    pane_layout_version = ''

    doc_hint = ''  # directives for document formatter

    about_filesystem = {  # extra documents to place in the about:// filesystem
    }

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

    id = editor_id + "." + pane_layout_version if pane_layout_version else editor_id
    name = 'Framework'

    icon = Instance(ImageResource)

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

    editor_area = Instance(IEditorAreaPane)

    #### FrameworkTask interface ##############################################

    preferences_helper = Instance(FrameworkPreferences)

    status_bar_debug_width = Int(150)

    start_new_editor_in_new_window = Bool(False)

    print_data = Any

    document_changed = Event

    # event that causes the menubar/toolbar to be updated according to
    # the ui state variables
    menu_update_event = Event

    keyboard_shortcuts = Any

    # class attribute

    activated_task_ids = set()

    #### 'IAbout' interface ###################################################

    about_title = Unicode('Omnivore XL')

    about_version = Unicode

    about_description = Unicode(
        'Byte into the meat of 8-bit Software!\n\nSend feedback to: [email protected]'
    )

    about_website = Str('http://playermissile.com/omnivore')

    about_image = Instance(ImageResource, ImageResource('omnivore256'))

    #### 'IErrorReporter' interface ###########################################

    error_email_from = Str

    error_email_passwd = Str

    error_email_to = Str

    # Regular ol' class attributes here

    # description of menus
    ui_layout_description = {
        "menu": {
            "order": ["File", "Edit", "View", "Documents", "Window", "Help"],
            "File": ["NewGroup", "OpenGroup", "ImportGroup", "SaveGroup", "RevertGroup", "PrintGroup", "ExportGroup", "ExitGroup"],
            "Edit": ["UndoGroup", "CopyPasteGroup", "SelectGroup", "FindGroup", "PrefGroup"],
            "View": ["PredefinedGroup", "ZoomGroup", "ChangeGroup", "ConfigGroup", "ToggleGroup", "TaskGroup", "DebugGroup"],
            "Documents": ["DocumentGroup"],
            "Window": ["NewTaskGroup", "WindowGroup"],
            "Help": ["AboutGroup", "DocGroup", "BugReportGroup", "DebugTaskGroup", "DebugFrameworkGroup"],
        },
        "MenuBar": {  # documentation for menus and submenus that don't have actions
            "Documents": "This menu contains a list of all documents open in the current session, across all windows and tabs. Selecting an item in this list will switch the view to that document, using the editor that was being used the last time it was edited.",
            "Window": {
                "New View In...": "This menu will contain a list of all editors that can modify this file. Selecting an item in this list will add a new view into this file using the selected editor.  For instance, you can have a map editor and a hex editor on the same file; they point to the same data and modifying data in one window will show up in the other window.",
            },
        },

        "toolbar": {
            "order": ["File", "Edit", "View"],
            "File": ["NewGroup", "OpenGroup", "SaveGroup"],
            "Edit": ["UndoGroup", "CopyPasteGroup", "SelectGroup", "FindGroup"],
            "View": ["ZoomGroup", "ChangeGroup", "ConfigGroup"],
        },
    }

    # subclasses can make changes by putting entries into this structure.
    # Entries here will replace items in the ui_layout_description dict
    ui_layout_overrides = {}

    # IAbout interface

    def _about_version_default(self):
        from omnivore import __version__
        return __version__

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

    def _icon_default(self):
        return ImageResource('omnivore')

    def get_layout_description(self, category, title):
        try:
            log.debug("%s: %s/%s found in overrides" %
                      (self.name, category, title))
            return self.ui_layout_overrides[category][title]
        except KeyError:
            return self.ui_layout_description[category][title]
        log.error("Ui for %s, %s not found s" % (category, title))

    def get_submenu_docs(self, menu_list):
        """Find any submenu docs from the MenuBar or Tool Bar keys in
        the ui_layout_* dicts.

        The hierarchy of pyface actions is very complicated and I can't figure
        out how to attach documentation to a submenu. So we're left with this
        mess. At least it's all in one spot.
        """
        category = menu_list.pop(0)
        desc = ""
        for ui in [self.ui_layout_overrides, self.ui_layout_description]:
            try:
                desc = ui[category]
                print category, desc
                for m in menu_list:
                    desc = desc[m]
                    print m, desc
            except KeyError:
                desc = ""
                continue
            else:
                break
        print "SUBMENU_DOCS", menu_list, desc
        if not isinstance(desc, basestring):
            desc = ""
        return desc

    def _menu_bar_default(self):
        menus = []
        for menu_title in self.get_layout_description("menu", "order"):
            menu_desc = self.get_layout_description("menu", menu_title)
            self.add_menu(menus, "Menu", menu_title, *menu_desc)
        return SMenuBar(*menus)

    def _tool_bars_default(self):
        bars = []
        desc = self.ui_layout_description["toolbar"]
        for menu_title in desc["order"]:
            menu_desc = desc[menu_title]
            bars.append(self.get_groups("Tool", menu_title, *menu_desc))
        return [
            SToolBar(*bars, show_tool_names=False, id="%s:ToolBar" % self.id)
        ]

    def _status_bar_default(self):
        return FrameworkStatusBarManager(
            message="Hi!", debug_width=self.status_bar_debug_width)

    def _default_layout_default(self):
        return TaskLayout()

    def _keyboard_shortcuts_default(self):
        actions = []

        # Give each keyboard action a wx ID so that it can be identified in the
        # menu callback
        for action in self.get_keyboard_actions():
            id = wx.NewId()
            action.keyboard_shortcut_id = id
            actions.append(action)
        return actions

    ##### Task setup/cleanup

    def initialized(self):
        self.window.application.remember_perspectives(self.window)
        c = self.editor_area.control
        c.Bind(aui.EVT_AUINOTEBOOK_TAB_RIGHT_DOWN, self.on_tab_context_menu)
        c.Bind(aui.EVT_AUINOTEBOOK_BG_RIGHT_DOWN,
               self.on_tab_background_context_menu)
        c.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_tab_pane_close)

    def activated(self):
        log.debug("  status bar: %s" % self.status_bar)
        active = self.active_editor
        if active:
            self.status_bar.message = active.name
        else:
            self.status_bar.message = self.name
        self.window.icon = self.icon
        self.set_keyboard_shortcuts()
        self._active_editor_tab_change(None)
        visible = self.pane_layout_initial_visibility()
        for pane in self.iter_panes():
            if pane.id in visible:
                pane.visible = visible[pane.id]

        if self.id not in self.activated_task_ids:
            self.activated_task_ids.add(self.id)
            self.first_time_activated()

    def first_time_activated(self):
        """ Called the first time a task is activated in the application.
        """
        pass

    def pane_layout_initial_visibility(self):
        return {}

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

    def create_dock_panes(self):
        """ Create any dock panes and connect to its double click event.
        """
        return []

    def iter_panes(self):
        for pane in self.window.dock_panes:
            yield pane

    def prepare_destroy(self):
        self.window.application.remember_perspectives(self.window)
        self.destroy_minibuffer()

    ###########################################################################
    # 'FrameworkTask' interface.
    ###########################################################################

    def new(self, source=None, **kwargs):
        """ Opens a new tab
        
        :param source: optional :class:`FileGuess` or :class:`Editor` instance
        that will load a new file or create a new view of the existing editor,
        respectively.
        """
        try:
            editor = self.get_editor(**kwargs)
        except e:
            self.error("Failed creating editor: %s" % str(e))
            return
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        log.debug("new: source=%s editor=%s" % (source, editor))
        if hasattr(source, 'get_metadata') or source is None:
            editor.load(source, **kwargs)
            if source is not None:
                self.window.application.successfully_loaded_event = source.metadata.uri
        elif hasattr(source, 'document_id'):
            source.load_permute(editor)
            editor.load_document(source)
            self.window.application.successfully_loaded_event = source.metadata.uri
        else:
            editor.view_document(source.document, source)
        self.activated()

    def find_tab_or_open(self, document):
        for editor in self.editor_area.editors:
            if editor.document == document:
                self.editor_area.activate_editor(editor)
                return
        self.new(document)

    def new_window(self, task=None, view=None):
        """ Opens a new window
        
        With no arguments, opens an empty window with the default task.
        
        :keyword task: optional task to set the task of the new window
        
        :keyword view: optional :class:`Editor` instance that will set the
        task of the new window and will create a new view of the editor in the
        first tab
        """
        log.debug("Opening new window!!!")
        window = self.window.application.create_window()
        log.debug("  window=%s" % str(window))
        log.debug("  self=%s" % str(self.window))
        log.debug("  task type: %s" % str(task))
        log.debug("  view of: %s" % str(view))
        task_id = None
        if view is not None:
            task_cls = view.editor_area.task.__class__
            log.debug("  task_cls: %s" % str(task_cls))
        elif task is not None:
            if isinstance(task, FrameworkTask):
                task_cls = task.__class__
            else:
                task_cls = task
        else:
            task_id = self.window.application.startup_task
        if task_id is None:
            task = task_cls()
            task_id = task.id
        log.debug("  task id: %s" % task_id)
        log.debug("  returned factory: %s" %
                  self.window.application._get_task_factory(task_id))
        for factory in self.window.application.task_factories:
            log.debug("    factory: %s, %s" % (factory.id, factory))

        task = self.window.application.create_task(task_id)
        log.debug("  created task: %s" % task)
        window.add_task(task)
        window.activate_task(task)
        if view is not None:
            task.new(view)
        window.open()
        log.debug("All windows: %s" % self.window.application.windows)

    def prompt_local_file_dialog(self,
                                 title="",
                                 most_recent=True,
                                 save=False,
                                 default_filename="",
                                 wildcard="*"):
        """Display an "open file" dialog to load from the local filesystem,
        defaulting to the most recently used directory.

        If there is no previously used directory, default to the directory of
        the current file.

        Returns the directory path on the filesystem, or None if not found.
        """
        dirpath = ""
        action = "save as" if save else "open"
        if not title:
            title = "Save File" if save else "Open File"
        if self.active_editor:
            # will try path of current file
            dirpath = self.active_editor.best_file_save_dir

        dialog = FileDialog(parent=self.window.control,
                            title=title,
                            default_directory=dirpath,
                            action=action,
                            default_filename=default_filename,
                            wildcard=wildcard)
        if dialog.open() == OK:
            return dialog.path
        return None

    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.
            path = prompt_local_file_dialog(save=True)
            if path:
                editor.save(path)
            else:
                return False
        return True

    def allow_different_task(self, guess, other_task):
        """Hook to allow tasks to abort loading different task window.
        
        This method allows a hook to confirm that the user wants to load a file
        that can't be handled by the current task.  For example, this can be
        used to prompt with a dialog box.
        
        :rtype: Boolean; True means continue with the file load in a separate
        task window
        """
        return True

    def _print_data_default(self):
        data = wx.PrintData()
        data.SetPaperId(wx.PAPER_LETTER)
        data.SetOrientation(wx.PORTRAIT)
        return data

    def page_setup(self):
        data = wx.PageSetupDialogData(self.print_data)
        data.SetDefaultMinMargins(True)

        dlg = wx.PageSetupDialog(self.window.control, data)

        if dlg.ShowModal() == wx.ID_OK:
            data = dlg.GetPageSetupData().GetPrintData()
            self.print_data = wx.PrintData(data)  # Force a copy

        dlg.Destroy()

    def debug(self):
        """Debug stuff!
        """
        action_schemas = list(self.menu_bar.items)
        action_schemas.extend(self.tool_bars)
        for action in self._iter_schema_items(action_schemas):
            if hasattr(action, 'name'):
                action.name = action.name + "!"

    def ask_attempt_loading_as_octet_stream(self, guess, other_task):
        return self.confirm(
            "%s\n\nwas identified with a MIME type of %s\nand can also be edited in a %s window.\n\nOpen here in the %s window instead?"
            % (guess.metadata.uri, guess.metadata.mime,
               other_task.new_file_text, self.name), "Edit in %s?" % self.name)

    ###########################################################################
    # 'FrameworkTask' convenience functions.
    ###########################################################################

    @property
    def preferences(self):
        return self.window.application.get_preferences(self.preferences_helper)

    def create_menu(self, location, menu_name, *group_names):
        items = []
        for group_name in group_names:
            self.add_actions_and_groups(items, location, menu_name, group_name)
        return SMenu(*items, id=menu_name, name=menu_name)

    def add_menu(self, menu, location, menu_name, *group_names):
        entry = self.create_menu(location, menu_name, *group_names)
        menu.append(entry)

    def add_actions_and_groups(self, menu_items, location, menu_name,
                               group_name):
        actions = self.get_actions_wrapper(location, menu_name, group_name)

        groups = []
        group_suffix = ""
        group_index = 0
        current = []

        for item in actions:
            if isinstance(item, Group) or isinstance(item, SMenu):
                if current:
                    group = Group(*current,
                                  id="%s%s" % (group_name, group_suffix))
                    group_index += 1
                    group_suffix = str(group_index)
                    groups.append(group)
                    current = []
                groups.append(item)
            else:
                current.append(item)
        if current:
            group = Group(*current, id="%s%s" % (group_name, group_suffix))
            groups.append(group)

        menu_items.append(Separator(id="%sStart" % group_name,
                                    separator=False))
        for group in groups:
            menu_items.append(group)
        menu_items.append(Separator(id="%sEnd" % group_name, separator=False))

    def get_group(self, location, menu_name, group_name):
        actions = self.get_actions_wrapper(location, menu_name, group_name)
        return Group(*actions, id=group_name)

    def get_groups(self, location, menu_name, *group_names):
        actions = []
        for group_name in group_names:
            actions.extend(
                self.get_actions_wrapper(location, menu_name, group_name))
        return Group(*actions, id=menu_name)

    def get_actions_wrapper(self, location, menu_name, group_name):
        actions = self.get_actions(location, menu_name, group_name)
        if actions is None:
            # fall back to this class if it's not found in subclass
            actions = FrameworkTask.get_actions(self, location, menu_name,
                                                group_name)
        return actions

    def get_actions(self, location, menu_name, group_name):
        # allow spaces in menu names by removing them for function lookup
        menu_lookup = menu_name.replace(" ", "")
        method_name = "get_actions_%s_%s_%s" % (location, menu_lookup,
                                                group_name)
        try:
            method = getattr(self, method_name)
        except AttributeError, e:
            log.debug("%s actions not found for %s/%s in %s" %
                      (location, menu_name, group_name, self.id))
            actions = []
        else: