Exemplo n.º 1
0
 def OnViewAllTags(self, event):
     if self._view_all_tags_dialog is None:
         self._view_all_tags_dialog = ViewAllTagsDialog(self._controller, self)
     self._view_all_tags_dialog.show_dialog()
Exemplo n.º 2
0
class RideFrame(wx.Frame, RideEventHandler):

    def __init__(self, application, controller):
        wx.Frame.__init__(self, parent=None, title='RIDE',
                          pos=application.settings['mainframe position'],
                          size=application.settings['mainframe size'])
        self.ensure_on_screen()
        if application.settings['mainframe maximized']:
            self.Maximize()
        self._application = application
        self._controller = controller
        self._init_ui()
        self._plugin_manager = PluginManager(self.notebook)
        self._review_dialog = None
        self._view_all_tags_dialog = None
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
        self._subscribe_messages()
        self.Show()
        wx.CallLater(100, self.actions.register_tools)

    def _subscribe_messages(self):
        for listener, topic in [
            (lambda msg: self.SetStatusText('Saved %s' % msg.path), RideSaved),
            (lambda msg: self.SetStatusText('Saved all files'), RideSaveAll),
            (self._set_label, RideTreeSelection),
            (self._show_validation_error, RideInputValidationError),
            (self._show_modification_prevented_error, RideModificationPrevented)
        ]:
            PUBLISHER.subscribe(listener, topic)

    def _set_label(self, message):
        self.SetTitle(self._create_title(message))

    def _create_title(self, message):
        title = 'RIDE'
        if message:
            item = message.item
            title += ' - ' + item.datafile.name
            if not item.is_modifiable():
                title += ' (READ ONLY)'
        return title

    def _show_validation_error(self, message):
        wx.MessageBox(message.message, 'Validation Error', style=wx.ICON_ERROR)

    def _show_modification_prevented_error(self, message):
        wx.MessageBox('"%s" is read only' % message.controller.datafile_controller.filename,
                      'Modification prevented',
                      style=wx.ICON_ERROR)

    def _init_ui(self):
        splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        self.notebook = NoteBook(splitter, self._application)
        mb = MenuBar(self)
        self.toolbar = ToolBar(self)
        self.actions = ActionRegisterer(mb, self.toolbar,
                                        ShortcutRegistry(self))
        self.tree = Tree(splitter, self.actions, self._application.settings)
        self.actions.register_actions(
            ActionInfoCollection(_menudata, self, self.tree))
        mb.take_menu_bar_into_use()
        splitter.SetMinimumPaneSize(100)
        splitter.SplitVertically(self.tree, self.notebook, 300)
        self.CreateStatusBar()
        self.SetIcons(ImageProvider().PROGICONS)

    def get_selected_datafile(self):
        return self.tree.get_selected_datafile()

    def get_selected_datafile_controller(self):
        return self.tree.get_selected_datafile_controller()

    def OnClose(self, event):
        if self._allowed_to_exit():
            PUBLISHER.unsubscribe(self._set_label, RideTreeSelection)
            RideClosing().publish()
            self.Destroy()
        else:
            wx.CloseEvent.Veto(event)

    def OnSize(self, event):
        if not self.IsMaximized():
            self._application.settings['mainframe maximized'] = False
            self._application.settings['mainframe size'] = self.GetSizeTuple()
        event.Skip()

    def OnMove(self, event):
        # When the window is Iconized, a move event is also raised, but we
        # don't want to update the position in the settings file
        if not self.IsIconized() and not self.IsMaximized():
            self._application.settings['mainframe position'] = self.GetPositionTuple()
        event.Skip()

    def OnMaximize(self, event):
        self._application.settings['mainframe maximized'] = True
        event.Skip()

    def OnReleasenotes(self, event):
        pass

    def _allowed_to_exit(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox('There are unsaved modifications.\n'
                                'Do you want to save your changes before exiting?',
                                'Warning', wx.ICON_WARNING|wx.CANCEL|wx.YES_NO)
            if ret == wx.CANCEL:
                return False
            if ret == wx.YES:
                self.save()
        return True

    def has_unsaved_changes(self):
        return self._controller.is_dirty()

    def OnNewProject(self, event):
        if not self.check_unsaved_modifications():
            return
        NewProjectDialog(self._controller).execute()
        self._populate_tree()

    def _populate_tree(self):
        self.tree.populate(self._controller)

    def OnOpenTestSuite(self, event):
        if not self.check_unsaved_modifications():
            return
        path = RobotFilePathDialog(
            self, self._controller, self._application.settings).execute()
        if path:
            self.open_suite(path)

    def check_unsaved_modifications(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox('There are unsaved modifications.\n'
                                'Do you want to proceed without saving?',
                                'Warning', wx.ICON_WARNING|wx.YES_NO)
            return ret == wx.YES
        return True

    def open_suite(self, path):
        self._controller.update_default_dir(path)
        self._controller.load_datafile(path, LoadProgressObserver(self))
        self._populate_tree()

    def refresh_datafile(self, item, event):
        self.tree.refresh_datafile(item, event)

    def OnOpenDirectory(self, event):
        if self.check_unsaved_modifications():
            path = wx.DirSelector(message='Choose a directory containing Robot files',
                                    defaultPath=self._controller.default_dir)
            if path:
                self.open_suite(path)

    def OnReload(self, event):
        # path = wx.DirSelector(message='Choose a directory containing Robot files',
        # defaultPath=self._controller.default_dir)
        python_home = get_python_lib()
        script_and_parameter ='python ' + python_home + '\PublicLibrary\RF_tool_box.py ' + self._controller.default_dir
        os.system(script_and_parameter)
        self.open_suite(self._controller.default_dir)

    def OnSave(self, event):
        self.save()

    def OnSaveAll(self, event):
        self.save_all()

    def save_all(self):
        self._show_dialog_for_files_without_format()
        self._controller.execute(SaveAll())

    def save(self, controller=None):
        if controller is None :
            controller = self.get_selected_datafile_controller()
        if controller is not None:
            if not controller.has_format():
                self._show_dialog_for_files_without_format(controller)
            else:
                controller.execute(SaveFile())

    def _show_dialog_for_files_without_format(self, controller=None):
        files_without_format = self._controller.get_files_without_format(controller)
        for f in files_without_format:
            self._show_format_dialog_for(f)

    def _show_format_dialog_for(self, file_controller_without_format):
        InitFileFormatDialog(file_controller_without_format).execute()

    def OnExit(self, event):
        self.Close()

    def OnManagePlugins(self, event):
        self._plugin_manager.show(self._application.get_plugins())

    def OnViewAllTags(self, event):
        if self._view_all_tags_dialog is None:
            self._view_all_tags_dialog = ViewAllTagsDialog(self._controller, self)
        self._view_all_tags_dialog.show_dialog()

    def OnSearchUnusedKeywords(self, event):
        if self._review_dialog is None:
            self._review_dialog = ReviewDialog(self._controller, self)
        self._review_dialog.show_dialog()

    def OnPreferences(self, event):
        dlg = PreferenceEditor(self, "RIDE - Preferences",
                               self._application.preferences, style='tree')
        # I would prefer that this not be modal, but making it non-
        # modal opens up a can of worms. We don't want to have to deal
        # with settings getting changed out from under us while the
        # dialog is open.
        dlg.ShowModal()
        dlg.Destroy()

    def OnAbout(self, event):
        dlg = AboutDialog()
        dlg.ShowModal()
        dlg.Destroy()

    def OnShortcutkeys(self, event):
        dialog = ShortcutKeysDialog()
        dialog.Show()

    def OnReportaProblem(self, event):
        wx.LaunchDefaultBrowser('http://github.com/robotframework/RIDE/issues')

    def OnUserGuide(self, event):
        wx.LaunchDefaultBrowser('http://robotframework.org/robotframework/#user-guide')

    def _has_data(self):
        return self._controller.data is not None

    def _refresh(self):
        self._controller.update_namespace()

# This code is copied from http://wiki.wxpython.org/EnsureFrameIsOnScreen,
# and adapted to fit our code style.
    def ensure_on_screen(self):
        try:
            display_id = wx.Display.GetFromWindow(self)
        except NotImplementedError:
            display_id = 0
        if display_id == -1:
            display_id = 0
        geometry = wx.Display(display_id).GetGeometry()
        position = self.GetPosition()
        if position.x < geometry.x:
            position.x = geometry.x
        if position.y < geometry.y:
            position.y = geometry.y
        size = self.GetSize()
        if size.width > geometry.width:
            size.width = geometry.width
            position.x = geometry.x
        elif position.x + size.width > geometry.x + geometry.width:
            position.x = geometry.x + geometry.width - size.width
        if size.height > geometry.height:
            size.height = geometry.height
            position.y = geometry.y
        elif position.y + size.height > geometry.y + geometry.height:
            position.y = geometry.y + geometry.height - size.height
        self.SetPosition(position)
        self.SetSize(size)
Exemplo n.º 3
0
class RideFrame(wx.Frame, RideEventHandler):

    def __init__(self, application, controller):
        wx.Frame.__init__(self, parent=None, title='RIDE',
                          pos=application.settings['mainframe position'],
                          size=application.settings['mainframe size'])
        self.ensure_on_screen()
        if application.settings['mainframe maximized']:
            self.Maximize()
        self._application = application
        self._controller = controller
        self._init_ui()
        self._plugin_manager = PluginManager(self.notebook)
        self._review_dialog = None
        self._view_all_tags_dialog = None
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
        self._subscribe_messages()
        self.Show()
        wx.CallLater(100, self.actions.register_tools)

    def _subscribe_messages(self):
        for listener, topic in [
            (lambda msg: self.SetStatusText('Saved %s' % msg.path), RideSaved),
            (lambda msg: self.SetStatusText('Saved all files'), RideSaveAll),
            (self._set_label, RideTreeSelection),
            (self._show_validation_error, RideInputValidationError),
            (self._show_modification_prevented_error, RideModificationPrevented)
        ]:
            PUBLISHER.subscribe(listener, topic)

    def _set_label(self, message):
        self.SetTitle(self._create_title(message))

    def _create_title(self, message):
        title = 'RIDE'
        if message:
            item = message.item
            title += ' - ' + item.datafile.name
            if not item.is_modifiable():
                title += ' (READ ONLY)'
        return title

    def _show_validation_error(self, message):
        wx.MessageBox(message.message, 'Validation Error', style=wx.ICON_ERROR)

    def _show_modification_prevented_error(self, message):
        wx.MessageBox('"%s" is read only' % message.controller.datafile_controller.filename,
                      'Modification prevented',
                      style=wx.ICON_ERROR)

    def _init_ui(self):
        splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        self.notebook = NoteBook(splitter, self._application)
        mb = MenuBar(self)
        self.toolbar = ToolBar(self)
        self.actions = ActionRegisterer(mb, self.toolbar,
                                        ShortcutRegistry(self))
        self.tree = Tree(splitter, self.actions, self._application.settings)
        self.actions.register_actions(
            ActionInfoCollection(_menudata, self, self.tree))
        mb.take_menu_bar_into_use()
        splitter.SetMinimumPaneSize(100)
        splitter.SplitVertically(self.tree, self.notebook, 300)
        self.CreateStatusBar()
        self.SetIcons(ImageProvider().PROGICONS)

    def get_selected_datafile(self):
        return self.tree.get_selected_datafile()

    def get_selected_datafile_controller(self):
        return self.tree.get_selected_datafile_controller()

    def OnClose(self, event):
        if self._allowed_to_exit():
            PUBLISHER.unsubscribe(self._set_label, RideTreeSelection)
            RideClosing().publish()
            self.Destroy()
        else:
            wx.CloseEvent.Veto(event)

    def OnSize(self, event):
        if not self.IsMaximized():
            self._application.settings['mainframe maximized'] = False
            self._application.settings['mainframe size'] = self.GetSizeTuple()
        event.Skip()

    def OnMove(self, event):
        # When the window is Iconized, a move event is also raised, but we
        # don't want to update the position in the settings file
        if not self.IsIconized() and not self.IsMaximized():
            self._application.settings['mainframe position'] = self.GetPositionTuple()
        event.Skip()

    def OnMaximize(self, event):
        self._application.settings['mainframe maximized'] = True
        event.Skip()

    def OnReleasenotes(self, event):
        pass

    def _allowed_to_exit(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox('There are unsaved modifications.\n'
                                'Do you want to save your changes before exiting?',
                                'Warning', wx.ICON_WARNING|wx.CANCEL|wx.YES_NO)
            if ret == wx.CANCEL:
                return False
            if ret == wx.YES:
                self.save()
        return True

    def has_unsaved_changes(self):
        return self._controller.is_dirty()

    def OnNewProject(self, event):
        if not self.check_unsaved_modifications():
            return
        NewProjectDialog(self._controller).execute()
        self._populate_tree()

    def _populate_tree(self):
        self.tree.populate(self._controller)

    def OnOpenTestSuite(self, event):
        if not self.check_unsaved_modifications():
            return
        path = self._get_path()
        if path:
            self.open_suite(path)

    def check_unsaved_modifications(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox('There are unsaved modifications.\n'
                                'Do you want to proceed without saving?',
                                'Warning', wx.ICON_WARNING|wx.YES_NO)
            return ret == wx.YES
        return True

    def _get_path(self):
        wildcard = 'Robot data (*robot)|*.robot|Robot data (*txt)|*.txt|All files|*.*'
        dlg = wx.FileDialog(
            self, message='Open', wildcard=wildcard,
            defaultDir=self._controller.default_dir, style=wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self._controller.update_default_dir(path)
        else:
            path = None
        dlg.Destroy()
        return path

    def open_suite(self, path):
        self._controller.update_default_dir(path)
        self._controller.load_datafile(path, LoadProgressObserver(self))
        self._populate_tree()

    def refresh_datafile(self, item, event):
        self.tree.refresh_datafile(item, event)

    def OnOpenDirectory(self, event):
        if self.check_unsaved_modifications():
            path = wx.DirSelector(message='Choose a directory containing Robot files',
                                  defaultPath=self._controller.default_dir)
            if path:
                self.open_suite(path)

    def OnSave(self, event):
        self.save()

    def OnSaveAll(self, event):
        self.save_all()

    def save_all(self):
        self._show_dialog_for_files_without_format()
        self._controller.execute(SaveAll())

    def save(self, controller=None):
        if controller is None :
            controller = self.get_selected_datafile_controller()
        if controller is not None:
            if not controller.has_format():
                self._show_dialog_for_files_without_format(controller)
            else:
                controller.execute(SaveFile())

    def _show_dialog_for_files_without_format(self, controller=None):
        files_without_format = self._controller.get_files_without_format(controller)
        for f in files_without_format:
            self._show_format_dialog_for(f)

    def _show_format_dialog_for(self, file_controller_without_format):
        InitFileFormatDialog(file_controller_without_format).execute()

    def OnExit(self, event):
        self.Close()

    def OnManagePlugins(self, event):
        self._plugin_manager.show(self._application.get_plugins())

    def OnViewAllTags(self, event):
        if self._view_all_tags_dialog is None:
            self._view_all_tags_dialog = ViewAllTagsDialog(self._controller, self)
        self._view_all_tags_dialog.show_dialog()

    def OnSearchUnusedKeywords(self, event):
        if self._review_dialog is None:
            self._review_dialog = ReviewDialog(self._controller, self)
        self._review_dialog.show_dialog()

    def OnPreferences(self, event):
        dlg = PreferenceEditor(self, "RIDE - Preferences",
                               self._application.preferences, style='tree')
        # I would prefer that this not be modal, but making it non-
        # modal opens up a can of worms. We don't want to have to deal
        # with settings getting changed out from under us while the
        # dialog is open.
        dlg.ShowModal()
        dlg.Destroy()

    def OnAbout(self, event):
        dlg = AboutDialog()
        dlg.ShowModal()
        dlg.Destroy()

    def OnShortcutkeys(self, event):
        dialog = ShortcutKeysDialog()
        dialog.Show()

    def OnReportaProblem(self, event):
        wx.LaunchDefaultBrowser('http://github.com/robotframework/RIDE/issues')

    def OnUserGuide(self, event):
        wx.LaunchDefaultBrowser('http://robotframework.org/robotframework/#user-guide')

    def _has_data(self):
        return self._controller.data is not None

    def _refresh(self):
        self._controller.update_namespace()

# This code is copied from http://wiki.wxpython.org/EnsureFrameIsOnScreen,
# and adapted to fit our code style.
    def ensure_on_screen(self):
        try:
            display_id = wx.Display.GetFromWindow(self)
        except NotImplementedError:
            display_id = 0
        if display_id == -1:
            display_id = 0
        geometry = wx.Display(display_id).GetGeometry()
        position = self.GetPosition()
        if position.x < geometry.x:
            position.x = geometry.x
        if position.y < geometry.y:
            position.y = geometry.y
        size = self.GetSize()
        if size.width > geometry.width:
            size.width = geometry.width
            position.x = geometry.x
        elif position.x + size.width > geometry.x + geometry.width:
            position.x = geometry.x + geometry.width - size.width
        if size.height > geometry.height:
            size.height = geometry.height
            position.y = geometry.y
        elif position.y + size.height > geometry.y + geometry.height:
            position.y = geometry.y + geometry.height - size.height
        self.SetPosition(position)
        self.SetSize(size)
Exemplo n.º 4
0
 def OnViewAllTags(self, event):
     if self._view_all_tags_dialog is None:
         self._view_all_tags_dialog = ViewAllTagsDialog(self._controller, self)
     self._view_all_tags_dialog.show_dialog()
Exemplo n.º 5
0
class RideFrame(wx.Frame):
    def __init__(self, application, controller):
        size = application.settings.get('mainframe size', (1100, 700))
        wx.Frame.__init__(self,
                          parent=None,
                          id=wx.ID_ANY,
                          title='RIDE',
                          pos=application.settings.get('mainframe position',
                                                       (50, 30)),
                          size=size,
                          style=wx.DEFAULT_FRAME_STYLE | wx.SUNKEN_BORDER)

        # set Left to Right direction (while we don't have localization)
        self.SetLayoutDirection(wx.Layout_LeftToRight)
        # self.SetLayoutDirection(wx.Layout_RightToLeft)

        self._mgr = aui.AuiManager()

        # tell AuiManager to manage this frame
        self._mgr.SetManagedWindow(self)

        # set frame icon
        # self.SetIcon(Icon('widgets/robot.ico')) # Maybe is not needed
        # self.SetMinSize(size)
        self.SetMinSize(wx.Size(400, 300))

        self.ensure_on_screen()
        if application.settings.get('mainframe maximized', False):
            self.Maximize()
        self._application = application
        self._controller = controller
        self.favicon = Icon(
            os.path.join(os.path.dirname(__file__), "..", "widgets",
                         "robot.ico"), wx.BITMAP_TYPE_ICO, 256, 256)
        self.SetIcon(self.favicon)  #TODO use SetIcons for all sizes
        self._init_ui()
        self._plugin_manager = PluginManager(self.notebook)
        self._review_dialog = None
        self._view_all_tags_dialog = None
        #, self, self.actions,
        # self._application.settings)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
        self.Bind(wx.EVT_DIRCTRL_FILEACTIVATED, self.OnOpenFile)
        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnMenuOpenFile)
        self._subscribe_messages()
        wx.CallAfter(self.actions.register_tools)  # DEBUG

    def _subscribe_messages(self):
        for listener, topic in [
            (lambda msg: self.SetStatusText('Saved %s' % msg.path), RideSaved),
            (lambda msg: self.SetStatusText('Saved all files'), RideSaveAll),
            (self._set_label, RideTreeSelection),
            (self._show_validation_error, RideInputValidationError),
            (self._show_modification_prevented_error,
             RideModificationPrevented)
        ]:
            PUBLISHER.subscribe(listener, topic)

    def _set_label(self, message):
        self.SetTitle(self._create_title(message))

    def _create_title(self, message):
        title = 'RIDE'
        if message:
            item = message.item
            title += ' - ' + item.datafile.name
            if not item.is_modifiable():
                title += ' (READ ONLY)'
        return title

    def _show_validation_error(self, message):
        wx.MessageBox(message.message, 'Validation Error', style=wx.ICON_ERROR)

    def _show_modification_prevented_error(self, message):
        wx.MessageBox("\"%s\" is read only" %
                      message.controller.datafile_controller.filename,
                      "Modification prevented",
                      style=wx.ICON_ERROR)

    def _init_ui(self):
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        ##### self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        # set up default notebook style
        self._notebook_style = aui.AUI_NB_DEFAULT_STYLE | \
                               aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
        # TODO self._notebook_theme = 0 (allow to select themes for notebooks)
        # self.notebook = NoteBook(self.splitter, self._application,
        #                         self._notebook_style)
        self.notebook = NoteBook(self, self._application, self._notebook_style)
        self._mgr.AddPane(
            self.notebook,
            aui.AuiPaneInfo().Name("notebook_editors").CenterPane().PaneBorder(
                False))
        ################ Test
        # self._mgr.AddPane(self.CreateTextCtrl(),
        #                   aui.AuiPaneInfo().Name("text_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateHTMLCtrl(),
        #                   aui.AuiPaneInfo().Name("html_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateNotebook(),
        #                   aui.AuiPaneInfo().Name("notebook_content").
        #                   CenterPane().PaneBorder(False))
        ####################
        # self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo().
        #                   Name("test1").Caption(
        #     "Pane Caption").Top().MinimizeButton(True))

        mb = MenuBar(self)
        self.toolbar = ToolBar(self)
        self.toolbar.SetMinSize(wx.Size(100, 60))
        # self.SetToolBar(self.toolbar.GetToolBar())
        self._mgr.AddPane(
            self.toolbar,
            aui.AuiPaneInfo().Name("maintoolbar").ToolbarPane().Top())
        self.actions = ActionRegisterer(self._mgr, mb, self.toolbar,
                                        ShortcutRegistry(self))
        """
        ##### Test
        tb3 = self.testToolbar()

        self._mgr.AddPane(tb3,
                          aui.AuiPaneInfo().Name("tb3").Caption("Toolbar 3").
                          ToolbarPane().Top().Row(1).Position(1))
        
        ##### End Test
        """
        # Tree is always created here
        self.tree = Tree(self, self.actions, self._application.settings)
        self.tree.SetMinSize(wx.Size(120, 200))
        # TreePlugin will manage showing the Tree
        self.actions.register_actions(
            ActionInfoCollection(_menudata, self, self.tree))
        ###### File explorer panel is always created here
        self.filemgr = FileExplorer(self, self._controller)
        self.filemgr.SetMinSize(wx.Size(120, 200))

        mb.take_menu_bar_into_use()
        self.CreateStatusBar()
        self.SetIcons(ImageProvider().PROGICONS)
        # tell the manager to "commit" all the changes just made
        self._mgr.Update()

    def testToolbar(self):

        #### More testing
        prepend_items, append_items = [], []
        item = aui.AuiToolBarItem()

        item.SetKind(wx.ITEM_SEPARATOR)
        append_items.append(item)

        item = aui.AuiToolBarItem()
        item.SetKind(wx.ITEM_NORMAL)
        item.SetId(ID_CustomizeToolbar)
        item.SetLabel("Customize...")
        append_items.append(item)

        tb3 = aui.AuiToolBar(self,
                             -1,
                             wx.DefaultPosition,
                             wx.DefaultSize,
                             agwStyle=aui.AUI_TB_DEFAULT_STYLE
                             | aui.AUI_TB_OVERFLOW)
        tb3.SetToolBitmapSize(wx.Size(16, 16))
        tb3_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER,
                                            wx.Size(16, 16))
        tb3.AddSimpleTool(ID_SampleItem + 16, "Check 1", tb3_bmp1, "Check 1",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 17, "Check 2", tb3_bmp1, "Check 2",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 18, "Check 3", tb3_bmp1, "Check 3",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 19, "Check 4", tb3_bmp1, "Check 4",
                          aui.ITEM_CHECK)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 20, "Radio 1", tb3_bmp1, "Radio 1",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 21, "Radio 2", tb3_bmp1, "Radio 2",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 22, "Radio 3", tb3_bmp1, "Radio 3",
                          aui.ITEM_RADIO)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 23, "Radio 1 (Group 2)", tb3_bmp1,
                          "Radio 1 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 24, "Radio 2 (Group 2)", tb3_bmp1,
                          "Radio 2 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 25, "Radio 3 (Group 2)", tb3_bmp1,
                          "Radio 3 (Group 2)", aui.ITEM_RADIO)

        tb3.SetCustomOverflowItems(prepend_items, append_items)
        tb3.Realize()
        return tb3

    def get_selected_datafile(self):
        return self.tree.get_selected_datafile()

    def get_selected_datafile_controller(self):
        return self.tree.get_selected_datafile_controller()

    def OnClose(self, event):
        if self._allowed_to_exit():
            perspective = self._mgr.SavePerspective()
            self._application.settings.set('AUI Perspective', perspective)
            PUBLISHER.unsubscribe(self._set_label, RideTreeSelection)
            RideClosing().publish()
            # deinitialize the frame manager
            self._mgr.UnInit()
            self.Destroy()
        else:
            wx.CloseEvent.Veto(event)

    def OnSize(self, event):
        if not self.IsMaximized():
            self._application.settings['mainframe maximized'] = False
            self._application.settings['mainframe size'] = self.DoGetSize()
        event.Skip()

    def OnMove(self, event):
        # When the window is Iconized, a move event is also raised, but we
        # don't want to update the position in the settings file
        if not self.IsIconized() and not self.IsMaximized():
            self._application.settings['mainframe position'] =\
                self.DoGetPosition()
        event.Skip()

    def OnMaximize(self, event):
        self._application.settings['mainframe maximized'] = True
        event.Skip()

    def OnReleasenotes(self, event):
        pass

    def _allowed_to_exit(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox(
                "There are unsaved modifications.\n"
                "Do you want to save your changes before "
                "exiting?", "Warning", wx.ICON_WARNING | wx.CANCEL | wx.YES_NO)
            if ret == wx.CANCEL:
                return False
            if ret == wx.YES:
                self.save()
        return True

    def has_unsaved_changes(self):
        return self._controller.is_dirty()

    def OnNewProject(self, event):
        if not self.check_unsaved_modifications():
            return
        NewProjectDialog(self._controller).execute()
        self._populate_tree()

    def _populate_tree(self):
        self.tree.populate(self._controller)
        self.filemgr.update_tree()

    def OnOpenFile(self, event):
        if not self.filemgr:
            return
        # EVT_DIRCTRL_FILEACTIVATED
        from os.path import splitext
        robottypes = self._application.settings.get(
            'robot types', ['robot', 'resource'
                            'txt', 'tsv', 'html'])
        path = self.filemgr.GetFilePath()
        ext = ''
        if len(path) > 0:
            ext = splitext(path)
            ext = ext[1].replace('.', '')
            # print("DEBUG: path %s ext %s" % (path, ext))
        if len(ext) > 0 and ext in robottypes:
            if not self.check_unsaved_modifications():
                return
            if self.open_suite(path):
                return
        from robotide.editor import customsourceeditor
        customsourceeditor.main(path)

    def OnMenuOpenFile(self, event):
        if not self.filemgr:
            return
        # TODO: Use widgets/popupmenu tools
        path = self.filemgr.GetFilePath()
        if len(path) > 0:
            self.OnOpenFile(event)
        else:
            path = self.filemgr.GetPath()
            if not self.check_unsaved_modifications():
                return
            self.open_suite(path)  # It is a directory, do not edit
        event.Skip()

    def OnOpenTestSuite(self, event):
        if not self.check_unsaved_modifications():
            return
        path = RobotFilePathDialog(self, self._controller,
                                   self._application.settings).execute()
        if path:
            if self.open_suite(path):
                return
            from robotide.editor import customsourceeditor
            customsourceeditor.main(path)

    def check_unsaved_modifications(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox(
                "There are unsaved modifications.\n"
                "Do you want to proceed without saving?", "Warning",
                wx.ICON_WARNING | wx.YES_NO)
            return ret == wx.YES
        return True

    def open_suite(self, path):
        self._controller.update_default_dir(path)
        # self._controller.default_dir will only save dir path
        # need to save path to self._application.workspace_path too
        self._application.workspace_path = path
        try:
            err = self._controller.load_datafile(path,
                                                 LoadProgressObserver(self))
        finally:
            if isinstance(err, UserWarning):
                # raise err  # Just leave message in Parser Log
                return False
        self._populate_tree()
        return True

    def refresh_datafile(self, item, event):
        self.tree.refresh_datafile(item, event)
        if self.filemgr:
            self.filemgr.ReCreateTree()

    def OnOpenDirectory(self, event):
        if self.check_unsaved_modifications():
            path = wx.DirSelector(message="Choose a directory containing Robot"
                                  " files",
                                  default_path=self._controller.default_dir)
            if path:
                self.open_suite(path)

    def OnSave(self, event):
        RideBeforeSaving().publish()
        self.save()

    def OnSaveAll(self, event):
        RideBeforeSaving().publish()
        self.save_all()

    def save_all(self):
        self._show_dialog_for_files_without_format()
        self._controller.execute(SaveAll())

    def save(self, controller=None):
        if controller is None:
            controller = self.get_selected_datafile_controller()
        if controller is not None:
            if not controller.has_format():
                self._show_dialog_for_files_without_format(controller)
            else:
                controller.execute(SaveFile())

    def _show_dialog_for_files_without_format(self, controller=None):
        files_without_format = self._controller.get_files_without_format(
            controller)
        for f in files_without_format:
            self._show_format_dialog_for(f)

    def _show_format_dialog_for(self, file_controller_without_format):
        InitFileFormatDialog(file_controller_without_format).execute()

    def OnExit(self, event):
        self.Close()

    def OnManagePlugins(self, event):
        self._plugin_manager.show(self._application.get_plugins())

    def OnViewAllTags(self, event):
        if self._view_all_tags_dialog is None:
            self._view_all_tags_dialog = ViewAllTagsDialog(
                self._controller, self)
        self._view_all_tags_dialog.show_dialog()

    def OnSearchUnusedKeywords(self, event):
        if self._review_dialog is None:
            self._review_dialog = ReviewDialog(self._controller, self)
        self._review_dialog.show_dialog()

    def OnPreferences(self, event):
        dlg = PreferenceEditor(self,
                               "RIDE - Preferences",
                               self._application.preferences,
                               style='tree')
        # I would prefer that this not be modal, but making it non-
        # modal opens up a can of worms. We don't want to have to deal
        # with settings getting changed out from under us while the
        # dialog is open.
        dlg.ShowModal()
        dlg.Destroy()

    def OnAbout(self, event):
        dlg = AboutDialog()
        dlg.ShowModal()
        dlg.Destroy()

    def OnShortcutkeys(self, event):
        dialog = ShortcutKeysDialog()
        dialog.Show()

    def OnReportaProblem(self, event):
        wx.LaunchDefaultBrowser("https://github.com/robotframework/RIDE/issues"
                                "?utf8=%E2%9C%93&q=is%3Aissue+%22search"
                                "%20your%20problem%22")

    def OnUserGuide(self, event):
        wx.LaunchDefaultBrowser("http://robotframework.org/robotframework/"
                                "#user-guide")

    def OnWiki(self, event):
        wx.LaunchDefaultBrowser("https://github.com/robotframework/RIDE/wiki")

    def _has_data(self):
        return self._controller.data is not None

    def _refresh(self):
        self._controller.update_namespace()

    # This code is copied from http://wiki.wxpython.org/EnsureFrameIsOnScreen,
    # and adapted to fit our code style.
    def ensure_on_screen(self):
        try:
            display_id = wx.Display.GetFromWindow(self)
        except NotImplementedError:
            display_id = 0
        if display_id == -1:
            display_id = 0
        geometry = wx.Display(display_id).GetGeometry()
        position = self.GetPosition()
        if position.x < geometry.x:
            position.x = geometry.x
        if position.y < geometry.y:
            position.y = geometry.y
        size = self.GetSize()
        if size.width > geometry.width:
            size.width = geometry.width
            position.x = geometry.x
        elif position.x + size.width > geometry.x + geometry.width:
            position.x = geometry.x + geometry.width - size.width
        if size.height > geometry.height:
            size.height = geometry.height
            position.y = geometry.y
        elif position.y + size.height > geometry.y + geometry.height:
            position.y = geometry.y + geometry.height - size.height
        self.SetPosition(position)
        self.SetSize(size)

    # DEBUG just some testing
    def CreateSizeReportCtrl(self, width=80, height=80):

        ctrl = SizeReportCtrl(self, -1, wx.DefaultPosition,
                              wx.Size(width, height), self._mgr)
        return ctrl

    def show_confirm_reload_dlg(self, event):
        msg = [
            'Workspace modifications detected on the file system.',
            'Do you want to reload the workspace?',
            'Answering <No> will overwrite the changes on disk.'
        ]
        if self._controller.is_dirty():
            msg.insert(2, 'Answering <Yes> will discard unsaved changes.')
        ret = wx.MessageBox('\n'.join(msg),
                            'Files Changed On Disk',
                            style=wx.YES_NO | wx.ICON_WARNING)
        confirmed = ret == wx.YES
        if confirmed:
            # workspace_path should update after open directory/suite
            # There're two scenarios:
            # 1. path is a directory
            # 2. path is a suite file
            new_path = RideFSWatcherHandler.get_workspace_new_path()
            if new_path and os.path.exists(new_path):
                wx.CallAfter(self.open_suite, new_path)
            else:
                # in case workspace is totally removed
                # ask user to open new directory
                # TODO add some notification msg to users
                wx.CallAfter(self.OnOpenDirectory, event)
        else:
            for _ in self._controller.datafiles:
                if _.has_been_modified_on_disk(
                ) or _.has_been_removed_from_disk():
                    if not os.path.exists(_.directory):
                        # sub folder is removed, create new one before saving
                        os.makedirs(_.directory)
                    _.mark_dirty()
            self.save_all()
Exemplo n.º 6
0
class RideFrame(with_metaclass(classmaker(), wx.Frame, RideEventHandler)):
    def __init__(self, application, controller):
        size = application.settings.get('mainframe size', (1100, 700))
        wx.Frame.__init__(self,
                          parent=None,
                          id=wx.ID_ANY,
                          title='RIDE',
                          pos=application.settings.get('mainframe position',
                                                       (50, 30)),
                          size=size,
                          style=wx.DEFAULT_FRAME_STYLE | wx.SUNKEN_BORDER)

        self._mgr = aui.AuiManager()

        # tell AuiManager to manage this frame
        self._mgr.SetManagedWindow(self)

        # set frame icon
        # self.SetIcon(Icon('widgets/robot.ico')) # Maybe is not needed
        # self.SetMinSize(size)
        self.SetMinSize(wx.Size(400, 300))

        self.ensure_on_screen()
        if application.settings.get('mainframe maximized', False):
            self.Maximize()
        self._application = application
        self._controller = controller
        self._init_ui()
        self._plugin_manager = PluginManager(self.notebook)
        self._review_dialog = None
        self._view_all_tags_dialog = None
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
        self.Bind(wx.EVT_DIRCTRL_FILEACTIVATED, self.OnOpenFile)
        self._subscribe_messages()
        #print("DEBUG: Call register_tools, actions: %s" % self.actions.__repr__())
        if PY2:
            wx.CallLater(100, self.actions.register_tools)  # DEBUG
        else:
            wx.CallAfter(self.actions.register_tools)  # DEBUG

    def _subscribe_messages(self):
        for listener, topic in [
            (lambda msg: self.SetStatusText('Saved %s' % msg.path), RideSaved),
            (lambda msg: self.SetStatusText('Saved all files'), RideSaveAll),
            (self._set_label, RideTreeSelection),
            (self._show_validation_error, RideInputValidationError),
            (self._show_modification_prevented_error,
             RideModificationPrevented)
        ]:
            PUBLISHER.subscribe(listener, topic)

    def _set_label(self, message):
        self.SetTitle(self._create_title(message))

    def _create_title(self, message):
        title = 'RIDE'
        if message:
            item = message.item
            title += ' - ' + item.datafile.name
            if not item.is_modifiable():
                title += ' (READ ONLY)'
        return title

    def _show_validation_error(self, message):
        wx.MessageBox(message.message, 'Validation Error', style=wx.ICON_ERROR)

    def _show_modification_prevented_error(self, message):
        wx.MessageBox("\"%s\" is read only" %
                      message.controller.datafile_controller.filename,
                      "Modification prevented",
                      style=wx.ICON_ERROR)

    def _init_ui(self):
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        ##### self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        # set up default notebook style
        self._notebook_style = aui.AUI_NB_DEFAULT_STYLE |\
                               aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
        # TODO self._notebook_theme = 0 (allow to select themes for notebooks)
        # self.notebook = NoteBook(self.splitter, self._application,
        #                         self._notebook_style)
        self.notebook = NoteBook(self, self._application, self._notebook_style)
        self._mgr.AddPane(
            self.notebook,
            aui.AuiPaneInfo().Name("notebook_editors").CenterPane().PaneBorder(
                False))
        ################ Test
        # self._mgr.AddPane(self.CreateTextCtrl(),
        #                   aui.AuiPaneInfo().Name("text_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateHTMLCtrl(),
        #                   aui.AuiPaneInfo().Name("html_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateNotebook(),
        #                   aui.AuiPaneInfo().Name("notebook_content").
        #                   CenterPane().PaneBorder(False))
        ####################
        # self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo().
        #                   Name("test1").Caption(
        #     "Pane Caption").Top().MinimizeButton(True))

        mb = MenuBar(self)
        self.toolbar = ToolBar(self)
        self.toolbar.SetMinSize(wx.Size(100, 60))
        # self.SetToolBar(self.toolbar.GetToolBar())
        self._mgr.AddPane(
            self.toolbar,
            aui.AuiPaneInfo().Name("maintoolbar").ToolbarPane().Top())
        self.actions = ActionRegisterer(self._mgr, mb, self.toolbar,
                                        ShortcutRegistry(self))
        """
        ##### Test
        tb3 = self.testToolbar()

        self._mgr.AddPane(tb3,
                          aui.AuiPaneInfo().Name("tb3").Caption("Toolbar 3").
                          ToolbarPane().Top().Row(1).Position(1))
        
        ##### End Test
        """
        # self._mgr.AddPane(self.CreateTreeControl(),
        #                  aui.AuiPaneInfo().Name("tree_content").
        #                  CenterPane().Hide().MinimizeButton(True))
        ###### self.tree = Tree(self.splitter, self.actions, self._application.settings)
        self.tree = Tree(self, self.actions, self._application.settings)
        #self.tree.SetMinSize(wx.Size(100, 200))
        self.tree.SetMinSize(wx.Size(120, 200))
        self._mgr.AddPane(
            self.tree,
            aui.AuiPaneInfo().Name("tree_content").Caption(
                "Test Suites").LeftDockable(True).CloseButton(False))
        # MaximizeButton(True).MinimizeButton(True))
        self.actions.register_actions(
            ActionInfoCollection(_menudata, self, self.tree))
        ###### File explorer pane
        self.filemgr = wx.GenericDirCtrl(self,
                                         -1,
                                         size=(200, 225),
                                         style=wx.DIRCTRL_3D_INTERNAL)
        self.filemgr.SetMinSize(wx.Size(120, 200))
        self._mgr.AddPane(
            self.filemgr,
            aui.AuiPaneInfo().Name("file_manager").Caption(
                "Files").LeftDockable(True).CloseButton(True))

        mb.take_menu_bar_into_use()
        #### self.splitter.SetMinimumPaneSize(100)
        #### self.splitter.SplitVertically(self.tree, self.notebook, 300)
        self.CreateStatusBar()
        self.SetIcons(ImageProvider().PROGICONS)
        # tell the manager to "commit" all the changes just made
        self._mgr.Update()

    def testToolbar(self):

        #### More testing
        prepend_items, append_items = [], []
        item = aui.AuiToolBarItem()

        item.SetKind(wx.ITEM_SEPARATOR)
        append_items.append(item)

        item = aui.AuiToolBarItem()
        item.SetKind(wx.ITEM_NORMAL)
        item.SetId(ID_CustomizeToolbar)
        item.SetLabel("Customize...")
        append_items.append(item)

        tb3 = aui.AuiToolBar(self,
                             -1,
                             wx.DefaultPosition,
                             wx.DefaultSize,
                             agwStyle=aui.AUI_TB_DEFAULT_STYLE
                             | aui.AUI_TB_OVERFLOW)
        tb3.SetToolBitmapSize(wx.Size(16, 16))
        tb3_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER,
                                            wx.Size(16, 16))
        tb3.AddSimpleTool(ID_SampleItem + 16, "Check 1", tb3_bmp1, "Check 1",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 17, "Check 2", tb3_bmp1, "Check 2",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 18, "Check 3", tb3_bmp1, "Check 3",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 19, "Check 4", tb3_bmp1, "Check 4",
                          aui.ITEM_CHECK)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 20, "Radio 1", tb3_bmp1, "Radio 1",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 21, "Radio 2", tb3_bmp1, "Radio 2",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 22, "Radio 3", tb3_bmp1, "Radio 3",
                          aui.ITEM_RADIO)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 23, "Radio 1 (Group 2)", tb3_bmp1,
                          "Radio 1 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 24, "Radio 2 (Group 2)", tb3_bmp1,
                          "Radio 2 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 25, "Radio 3 (Group 2)", tb3_bmp1,
                          "Radio 3 (Group 2)", aui.ITEM_RADIO)

        tb3.SetCustomOverflowItems(prepend_items, append_items)
        tb3.Realize()
        return tb3

    def get_selected_datafile(self):
        return self.tree.get_selected_datafile()

    def get_selected_datafile_controller(self):
        return self.tree.get_selected_datafile_controller()

    def OnClose(self, event):
        if self._allowed_to_exit():
            PUBLISHER.unsubscribe(self._set_label, RideTreeSelection)
            RideClosing().publish()
            # deinitialize the frame manager
            self._mgr.UnInit()
            self.Destroy()
        else:
            wx.CloseEvent.Veto(event)

    def OnSize(self, event):
        if not self.IsMaximized():
            self._application.settings['mainframe maximized'] = False
            self._application.settings['mainframe size'] = self.MyGetSize()
            # DEBUG wxPhoenix .GetSizeTuple()
        event.Skip()

    def OnMove(self, event):
        # When the window is Iconized, a move event is also raised, but we
        # don't want to update the position in the settings file
        if not self.IsIconized() and not self.IsMaximized():
            # DEBUG wxPhoenix writes wx.Point(50, 30) instead of just (50, 30)
            self._application.settings['mainframe position'] = \
                self.MyGetPosition()
            # DEBUG wxPhoenix self.GetPositionTuple()
        event.Skip()

    def OnMaximize(self, event):
        self._application.settings['mainframe maximized'] = True
        event.Skip()

    def OnReleasenotes(self, event):
        pass

    def MyGetSize(self):
        if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
            return self.DoGetSize()
        else:
            return self.GetSizeTuple()

    def MyGetPosition(self):
        if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
            return self.DoGetPosition()
        else:
            return self.GetPositionTuple()

    def _allowed_to_exit(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox(
                "There are unsaved modifications.\n"
                "Do you want to save your changes before "
                "exiting?", "Warning", wx.ICON_WARNING | wx.CANCEL | wx.YES_NO)
            if ret == wx.CANCEL:
                return False
            if ret == wx.YES:
                self.save()
        return True

    def has_unsaved_changes(self):
        return self._controller.is_dirty()

    def OnNewProject(self, event):
        if not self.check_unsaved_modifications():
            return
        NewProjectDialog(self._controller).execute()
        self._populate_tree()

    def _populate_tree(self):
        self.tree.populate(self._controller)
        if len(self._controller.data.directory) > 1:
            self.filemgr.SelectPath(self._controller.data.source)
            try:
                self.filemgr.ExpandPath(self._controller.data.source)
            except Exception:
                pass
            self.filemgr.Update()

    def OnOpenFile(self, event):
        # EVT_DIRCTRL_FILEACTIVATED
        from os.path import splitext
        robottypes = self._application.settings.get(
            'robot types', ['robot', 'resource'
                            'txt', 'tsv', 'html'])
        path = self.filemgr.GetFilePath()
        ext = splitext(path)
        ext = ext[1].replace('.', '')
        # print("DEBUG: path %s ext %s" % (path, ext))
        if ext in robottypes:
            if not self.check_unsaved_modifications():
                return
            try:
                self.open_suite(path)
                return
            except UserWarning as e:
                pass
        from robotide.editor import customsourceeditor
        customsourceeditor.main(path)

    def OnOpenTestSuite(self, event):
        if not self.check_unsaved_modifications():
            return
        path = RobotFilePathDialog(self, self._controller,
                                   self._application.settings).execute()
        if path:
            try:
                self.open_suite(path)
                return
            except UserWarning as e:
                pass
            from robotide.editor import customsourceeditor
            customsourceeditor.main(path)

    def check_unsaved_modifications(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox(
                "There are unsaved modifications.\n"
                "Do you want to proceed without saving?", "Warning",
                wx.ICON_WARNING | wx.YES_NO)
            return ret == wx.YES
        return True

    def open_suite(self, path):
        self._controller.update_default_dir(path)
        err = self._controller.load_datafile(path, LoadProgressObserver(self))
        if isinstance(err, UserWarning):
            raise err
        self._populate_tree()

    def refresh_datafile(self, item, event):
        self.tree.refresh_datafile(item, event)

    def OnOpenDirectory(self, event):
        if self.check_unsaved_modifications():
            if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
                path = wx.DirSelector(
                    message="Choose a directory containing "
                    "Robot files",
                    default_path=self._controller.default_dir)
            else:
                path = wx.DirSelector(message="Choose a directory containing "
                                      "Robot files",
                                      defaultPath=self._controller.default_dir)
            if path:
                self.open_suite(path)

    def OnSave(self, event):
        self.save()

    def OnSaveAll(self, event):
        self.save_all()

    def save_all(self):
        self._show_dialog_for_files_without_format()
        self._controller.execute(SaveAll())

    def save(self, controller=None):
        if controller is None:
            controller = self.get_selected_datafile_controller()
        if controller is not None:
            if not controller.has_format():
                self._show_dialog_for_files_without_format(controller)
            else:
                controller.execute(SaveFile())

    def _show_dialog_for_files_without_format(self, controller=None):
        files_without_format = self._controller.get_files_without_format(
            controller)
        for f in files_without_format:
            self._show_format_dialog_for(f)

    def _show_format_dialog_for(self, file_controller_without_format):
        InitFileFormatDialog(file_controller_without_format).execute()

    def OnExit(self, event):
        self.Close()

    def OnManagePlugins(self, event):
        self._plugin_manager.show(self._application.get_plugins())

    def OnViewAllTags(self, event):
        if self._view_all_tags_dialog is None:
            self._view_all_tags_dialog = ViewAllTagsDialog(
                self._controller, self)
        self._view_all_tags_dialog.show_dialog()

    def OnSearchUnusedKeywords(self, event):
        if self._review_dialog is None:
            self._review_dialog = ReviewDialog(self._controller, self)
        self._review_dialog.show_dialog()

    def OnPreferences(self, event):
        dlg = PreferenceEditor(self,
                               "RIDE - Preferences",
                               self._application.preferences,
                               style='tree')
        # I would prefer that this not be modal, but making it non-
        # modal opens up a can of worms. We don't want to have to deal
        # with settings getting changed out from under us while the
        # dialog is open.
        dlg.ShowModal()
        dlg.Destroy()

    def OnAbout(self, event):
        dlg = AboutDialog()
        dlg.ShowModal()
        dlg.Destroy()

    def OnShortcutkeys(self, event):
        dialog = ShortcutKeysDialog()
        dialog.Show()

    def OnReportaProblem(self, event):
        wx.LaunchDefaultBrowser(
            "https://github.com/robotframework/RIDE/issues")

    def OnUserGuide(self, event):
        wx.LaunchDefaultBrowser("http://robotframework.org/robotframework/"
                                "#user-guide")

    def _has_data(self):
        return self._controller.data is not None

    def _refresh(self):
        self._controller.update_namespace()

# This code is copied from http://wiki.wxpython.org/EnsureFrameIsOnScreen,
# and adapted to fit our code style.

    def ensure_on_screen(self):
        try:
            display_id = wx.Display.GetFromWindow(self)
        except NotImplementedError:
            display_id = 0
        if display_id == -1:
            display_id = 0
        geometry = wx.Display(display_id).GetGeometry()
        position = self.GetPosition()
        if position.x < geometry.x:
            position.x = geometry.x
        if position.y < geometry.y:
            position.y = geometry.y
        size = self.GetSize()
        if size.width > geometry.width:
            size.width = geometry.width
            position.x = geometry.x
        elif position.x + size.width > geometry.x + geometry.width:
            position.x = geometry.x + geometry.width - size.width
        if size.height > geometry.height:
            size.height = geometry.height
            position.y = geometry.y
        elif position.y + size.height > geometry.y + geometry.height:
            position.y = geometry.y + geometry.height - size.height
        self.SetPosition(position)
        self.SetSize(size)

    # DEBUG just some testing
    def CreateSizeReportCtrl(self, width=80, height=80):

        ctrl = SizeReportCtrl(self, -1, wx.DefaultPosition,
                              wx.Size(width, height), self._mgr)
        return ctrl
Exemplo n.º 7
0
class RideFrame(wx.Frame, RideEventHandler):
    __metaclass__ = classmaker()

    def __init__(self, application, controller):
        size = application.settings.get('mainframe size', (1100, 700))
        wx.Frame.__init__(self, parent=None, id = wx.ID_ANY, title='RIDE',
                          pos=application.settings.get('mainframe position', (50, 30)),
                          size=size,
                          style=wx.DEFAULT_FRAME_STYLE | wx.SUNKEN_BORDER)

        self._mgr = aui.AuiManager()

        # tell AuiManager to manage this frame
        self._mgr.SetManagedWindow(self)

        # set frame icon
        # self.SetIcon(Icon('widgets/robot.ico')) # Maybe is not needed
        # self.SetMinSize(size)
        self.SetMinSize(wx.Size(400, 300))

        self.ensure_on_screen()
        if application.settings.get('mainframe maximized', False):
            self.Maximize()
        self._application = application
        self._controller = controller
        self._init_ui()
        self._plugin_manager = PluginManager(self.notebook)
        self._review_dialog = None
        self._view_all_tags_dialog = None
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
        self.Bind(wx.EVT_DIRCTRL_FILEACTIVATED, self.OnOpenFile)
        self._subscribe_messages()
        #print("DEBUG: Call register_tools, actions: %s" % self.actions.__repr__())
        if PY2:
            wx.CallLater(100, self.actions.register_tools)  # DEBUG
        else:
            wx.CallAfter(self.actions.register_tools)  # DEBUG

    def _subscribe_messages(self):
        for listener, topic in [
            (lambda msg: self.SetStatusText('Saved %s' % msg.path), RideSaved),
            (lambda msg: self.SetStatusText('Saved all files'), RideSaveAll),
            (self._set_label, RideTreeSelection),
            (self._show_validation_error, RideInputValidationError),
            (self._show_modification_prevented_error,
             RideModificationPrevented)
        ]:
            PUBLISHER.subscribe(listener, topic)

    def _set_label(self, message):
        self.SetTitle(self._create_title(message))

    def _create_title(self, message):
        title = 'RIDE'
        if message:
            item = message.item
            title += ' - ' + item.datafile.name
            if not item.is_modifiable():
                title += ' (READ ONLY)'
        return title

    def _show_validation_error(self, message):
        wx.MessageBox(message.message, 'Validation Error', style=wx.ICON_ERROR)

    def _show_modification_prevented_error(self, message):
        wx.MessageBox("\"%s\" is read only" %
                      message.controller.datafile_controller.filename,
                      "Modification prevented",
                      style=wx.ICON_ERROR)

    def _init_ui(self):
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        ##### self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        # self._mgr.AddPane(wx.Panel(self), aui.AuiPaneInfo().CenterPane())
        # set up default notebook style
        self._notebook_style = aui.AUI_NB_DEFAULT_STYLE |\
                               aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
        # TODO self._notebook_theme = 0 (allow to select themes for notebooks)
        # self.notebook = NoteBook(self.splitter, self._application,
        #                         self._notebook_style)
        self.notebook = NoteBook(self, self._application,
                                 self._notebook_style)
        self._mgr.AddPane(self.notebook,
                          aui.AuiPaneInfo().Name("notebook_editors").
                          CenterPane().PaneBorder(False))
        ################ Test
        # self._mgr.AddPane(self.CreateTextCtrl(),
        #                   aui.AuiPaneInfo().Name("text_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateHTMLCtrl(),
        #                   aui.AuiPaneInfo().Name("html_content").
        #                   CenterPane().Hide().MinimizeButton(True))
        #
        # self._mgr.AddPane(self.CreateNotebook(),
        #                   aui.AuiPaneInfo().Name("notebook_content").
        #                   CenterPane().PaneBorder(False))
        ####################
        # self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo().
        #                   Name("test1").Caption(
        #     "Pane Caption").Top().MinimizeButton(True))

        mb = MenuBar(self)
        self.toolbar = ToolBar(self)
        self.toolbar.SetMinSize(wx.Size(100, 60))
        # self.SetToolBar(self.toolbar.GetToolBar())
        self._mgr.AddPane(self.toolbar, aui.AuiPaneInfo().Name("maintoolbar").
                          ToolbarPane().Top())
        self.actions = ActionRegisterer(self._mgr, mb, self.toolbar,
                                        ShortcutRegistry(self))
        """
        ##### Test
        tb3 = self.testToolbar()

        self._mgr.AddPane(tb3,
                          aui.AuiPaneInfo().Name("tb3").Caption("Toolbar 3").
                          ToolbarPane().Top().Row(1).Position(1))
        
        ##### End Test
        """
        # self._mgr.AddPane(self.CreateTreeControl(),
        #                  aui.AuiPaneInfo().Name("tree_content").
        #                  CenterPane().Hide().MinimizeButton(True))
        ###### self.tree = Tree(self.splitter, self.actions, self._application.settings)
        self.tree = Tree(self, self.actions,
                         self._application.settings)
        #self.tree.SetMinSize(wx.Size(100, 200))
        self.tree.SetMinSize(wx.Size(120, 200))
        self._mgr.AddPane(self.tree,
                          aui.AuiPaneInfo().Name("tree_content").
                          Caption("Test Suites").LeftDockable(True).
                          CloseButton(False))
        # MaximizeButton(True).MinimizeButton(True))
        self.actions.register_actions(
            ActionInfoCollection(_menudata, self, self.tree))
        ###### File explorer pane
        self.filemgr = wx.GenericDirCtrl(self, -1, size=(200, 225),
                                         style=wx.DIRCTRL_3D_INTERNAL)
        self.filemgr.SetMinSize(wx.Size(120, 200))
        self._mgr.AddPane(self.filemgr,
                          aui.AuiPaneInfo().Name("file_manager").
                          Caption("Files").LeftDockable(True).
                          CloseButton(True))

        mb.take_menu_bar_into_use()
        #### self.splitter.SetMinimumPaneSize(100)
        #### self.splitter.SplitVertically(self.tree, self.notebook, 300)
        self.CreateStatusBar()
        self.SetIcons(ImageProvider().PROGICONS)
        # tell the manager to "commit" all the changes just made
        self._mgr.Update()

    def testToolbar(self):

        #### More testing
        prepend_items, append_items = [], []
        item = aui.AuiToolBarItem()

        item.SetKind(wx.ITEM_SEPARATOR)
        append_items.append(item)

        item = aui.AuiToolBarItem()
        item.SetKind(wx.ITEM_NORMAL)
        item.SetId(ID_CustomizeToolbar)
        item.SetLabel("Customize...")
        append_items.append(item)

        tb3 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
                             agwStyle=aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_OVERFLOW)
        tb3.SetToolBitmapSize(wx.Size(16, 16))
        tb3_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER,
                                            wx.Size(16, 16))
        tb3.AddSimpleTool(ID_SampleItem + 16, "Check 1", tb3_bmp1, "Check 1",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 17, "Check 2", tb3_bmp1, "Check 2",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 18, "Check 3", tb3_bmp1, "Check 3",
                          aui.ITEM_CHECK)
        tb3.AddSimpleTool(ID_SampleItem + 19, "Check 4", tb3_bmp1, "Check 4",
                          aui.ITEM_CHECK)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 20, "Radio 1", tb3_bmp1, "Radio 1",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 21, "Radio 2", tb3_bmp1, "Radio 2",
                          aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 22, "Radio 3", tb3_bmp1, "Radio 3",
                          aui.ITEM_RADIO)
        tb3.AddSeparator()
        tb3.AddSimpleTool(ID_SampleItem + 23, "Radio 1 (Group 2)", tb3_bmp1,
                          "Radio 1 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 24, "Radio 2 (Group 2)", tb3_bmp1,
                          "Radio 2 (Group 2)", aui.ITEM_RADIO)
        tb3.AddSimpleTool(ID_SampleItem + 25, "Radio 3 (Group 2)", tb3_bmp1,
                          "Radio 3 (Group 2)", aui.ITEM_RADIO)

        tb3.SetCustomOverflowItems(prepend_items, append_items)
        tb3.Realize()
        return tb3

    def get_selected_datafile(self):
        return self.tree.get_selected_datafile()

    def get_selected_datafile_controller(self):
        return self.tree.get_selected_datafile_controller()

    def OnClose(self, event):
        if self._allowed_to_exit():
            PUBLISHER.unsubscribe(self._set_label, RideTreeSelection)
            RideClosing().publish()
            # deinitialize the frame manager
            self._mgr.UnInit()
            self.Destroy()
        else:
            wx.CloseEvent.Veto(event)

    def OnSize(self, event):
        if not self.IsMaximized():
            self._application.settings['mainframe maximized'] = False
            self._application.settings['mainframe size'] = self.MyGetSize()
            # DEBUG wxPhoenix .GetSizeTuple()
        event.Skip()

    def OnMove(self, event):
        # When the window is Iconized, a move event is also raised, but we
        # don't want to update the position in the settings file
        if not self.IsIconized() and not self.IsMaximized():
            # DEBUG wxPhoenix writes wx.Point(50, 30) instead of just (50, 30)
            self._application.settings['mainframe position'] = \
                self.MyGetPosition()
            # DEBUG wxPhoenix self.GetPositionTuple()
        event.Skip()

    def OnMaximize(self, event):
        self._application.settings['mainframe maximized'] = True
        event.Skip()

    def OnReleasenotes(self, event):
        pass

    def MyGetSize(self):
        if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
            return self.DoGetSize()
        else:
            return self.GetSizeTuple()

    def MyGetPosition(self):
        if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
            return self.DoGetPosition()
        else:
            return self.GetPositionTuple()

    def _allowed_to_exit(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox("There are unsaved modifications.\n"
                                "Do you want to save your changes before "
                                "exiting?", "Warning",
                                wx.ICON_WARNING | wx.CANCEL | wx.YES_NO)
            if ret == wx.CANCEL:
                return False
            if ret == wx.YES:
                self.save()
        return True

    def has_unsaved_changes(self):
        return self._controller.is_dirty()

    def OnNewProject(self, event):
        if not self.check_unsaved_modifications():
            return
        NewProjectDialog(self._controller).execute()
        self._populate_tree()

    def _populate_tree(self):
        self.tree.populate(self._controller)
        if len(self._controller.data.directory) > 1:
            self.filemgr.SelectPath(self._controller.data.source)
            try:
                self.filemgr.ExpandPath(self._controller.data.source)
            except Exception:
                pass
            self.filemgr.Update()

    def OnOpenFile(self, event):
        # EVT_DIRCTRL_FILEACTIVATED
        from os.path import splitext
        robottypes = self._application.settings.get('robot types', ['robot',
                                                                    'txt',
                                                                    'tsv',
                                                                    'html'])
        path = self.filemgr.GetFilePath()
        ext = splitext(path)
        ext = ext[1].replace('.', '')
        # print("DEBUG: path %s ext %s" % (path, ext))
        if ext in robottypes:
            if not self.check_unsaved_modifications():
                return
            try:
                self.open_suite(path)
                return
            except UserWarning as e:
                pass
        from robotide.editor import customsourceeditor
        customsourceeditor.main(path)

    def OnOpenTestSuite(self, event):
        if not self.check_unsaved_modifications():
            return
        path = RobotFilePathDialog(
            self, self._controller, self._application.settings).execute()
        if path:
            try:
                self.open_suite(path)
                return
            except UserWarning as e:
                pass
            from robotide.editor import customsourceeditor
            customsourceeditor.main(path)

    def check_unsaved_modifications(self):
        if self.has_unsaved_changes():
            ret = wx.MessageBox("There are unsaved modifications.\n"
                                "Do you want to proceed without saving?",
                                "Warning", wx.ICON_WARNING | wx.YES_NO)
            return ret == wx.YES
        return True

    def open_suite(self, path):
        self._controller.update_default_dir(path)
        err = self._controller.load_datafile(path, LoadProgressObserver(self))
        if isinstance(err, UserWarning):
            raise err
        self._populate_tree()

    def refresh_datafile(self, item, event):
        self.tree.refresh_datafile(item, event)

    def OnOpenDirectory(self, event):
        if self.check_unsaved_modifications():
            if wx.VERSION >= (3, 0, 3, ''):  # DEBUG wxPhoenix
                path = wx.DirSelector(message="Choose a directory containing "
                                              "Robot files",
                                      default_path=self._controller.default_dir
                                      )
            else:
                path = wx.DirSelector(message="Choose a directory containing "
                                              "Robot files",
                                      defaultPath=self._controller.default_dir)
            if path:
                self.open_suite(path)

    def OnSave(self, event):
        self.save()

    def OnSaveAll(self, event):
        self.save_all()

    def save_all(self):
        self._show_dialog_for_files_without_format()
        self._controller.execute(SaveAll())

    def save(self, controller=None):
        if controller is None:
            controller = self.get_selected_datafile_controller()
        if controller is not None:
            if not controller.has_format():
                self._show_dialog_for_files_without_format(controller)
            else:
                controller.execute(SaveFile())

    def _show_dialog_for_files_without_format(self, controller=None):
        files_without_format = self._controller.get_files_without_format(
            controller)
        for f in files_without_format:
            self._show_format_dialog_for(f)

    def _show_format_dialog_for(self, file_controller_without_format):
        InitFileFormatDialog(file_controller_without_format).execute()

    def OnExit(self, event):
        self.Close()

    def OnManagePlugins(self, event):
        self._plugin_manager.show(self._application.get_plugins())

    def OnViewAllTags(self, event):
        if self._view_all_tags_dialog is None:
            self._view_all_tags_dialog = ViewAllTagsDialog(self._controller,
                                                           self)
        self._view_all_tags_dialog.show_dialog()

    def OnSearchUnusedKeywords(self, event):
        if self._review_dialog is None:
            self._review_dialog = ReviewDialog(self._controller, self)
        self._review_dialog.show_dialog()

    def OnPreferences(self, event):
        dlg = PreferenceEditor(self, "RIDE - Preferences",
                               self._application.preferences, style='tree')
        # I would prefer that this not be modal, but making it non-
        # modal opens up a can of worms. We don't want to have to deal
        # with settings getting changed out from under us while the
        # dialog is open.
        dlg.ShowModal()
        dlg.Destroy()

    def OnAbout(self, event):
        dlg = AboutDialog()
        dlg.ShowModal()
        dlg.Destroy()

    def OnShortcutkeys(self, event):
        dialog = ShortcutKeysDialog()
        dialog.Show()

    def OnReportaProblem(self, event):
        wx.LaunchDefaultBrowser("https://github.com/robotframework/RIDE/issues"
                                )

    def OnUserGuide(self, event):
        wx.LaunchDefaultBrowser("http://robotframework.org/robotframework/"
                                "#user-guide")

    def _has_data(self):
        return self._controller.data is not None

    def _refresh(self):
        self._controller.update_namespace()

# This code is copied from http://wiki.wxpython.org/EnsureFrameIsOnScreen,
# and adapted to fit our code style.
    def ensure_on_screen(self):
        try:
            display_id = wx.Display.GetFromWindow(self)
        except NotImplementedError:
            display_id = 0
        if display_id == -1:
            display_id = 0
        geometry = wx.Display(display_id).GetGeometry()
        position = self.GetPosition()
        if position.x < geometry.x:
            position.x = geometry.x
        if position.y < geometry.y:
            position.y = geometry.y
        size = self.GetSize()
        if size.width > geometry.width:
            size.width = geometry.width
            position.x = geometry.x
        elif position.x + size.width > geometry.x + geometry.width:
            position.x = geometry.x + geometry.width - size.width
        if size.height > geometry.height:
            size.height = geometry.height
            position.y = geometry.y
        elif position.y + size.height > geometry.y + geometry.height:
            position.y = geometry.y + geometry.height - size.height
        self.SetPosition(position)
        self.SetSize(size)

    # DEBUG just some testing
    def CreateSizeReportCtrl(self, width=80, height=80):

        ctrl = SizeReportCtrl(self, -1, wx.DefaultPosition, wx.Size(width, height), self._mgr)
        return ctrl