Class: Ruber::MainWindow
- Extended by:
- Forwardable
- Includes:
- GuiStatesHandler, PluginLike
- Defined in:
- lib/ruber/main_window/main_window.rb,
lib/ruber/main_window/hint_solver.rb,
lib/ruber/main_window/view_manager.rb,
lib/ruber/main_window/main_window_actions.rb,
lib/ruber/main_window/main_window_internal.rb
Overview
The application’s main window. It is made of a menu bar, a tool bar, a workspace and a status bar. The workspace (see Workspace) is the main window’s central widget and where most of the user interaction happens. It contains the editors and the tool widgets.
Defined Under Namespace
Classes: HintSolver, ViewManager, WorkspaceSettingsWidget
Constant Summary collapse
- DEFAULT_HINTS =
The default hints used by methods like #editor_for and #editor_for!
{ :exisiting => :always, :strategy => [:current, :current_tab, :first], :new => :new_tab, :split => :horizontal, :show => true, :create_if_needed => true }.freeze
- OPEN_DLG_FILTERS =
A list of strings to be used to create the filter for open file dialogs
[ '*.rb|Ruby source file (*.rb)', '*.yaml *.yml|YAML files (*.yaml, *.yml)', '*|All files' ]
Instance Attribute Summary collapse
-
#last_session_data ⇒ Object
readonly
A hash with the data stored in the session manager by plugins.
-
#workspace ⇒ Workspace
readonly
The widget which contains the tool widgets.
Attributes included from PluginLike
Instance Method Summary collapse
-
#activate_editor(editor) ⇒ Object
Activates an editor.
-
#active_editor ⇒ EditorView?
(also: #current_editor)
The active editor The active editor is the editor which has its GUI merged with the main window’s.
-
#close_editor(editor, ask = true) ⇒ Boolean
Closes an editor view.
-
#current_document ⇒ Document?
(also: #active_document)
The document associated with the active editor.
-
#display_doc(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
(also: #display_document)
Displays an editor for the given document.
-
#editor_for(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
Returns an editor associated with the given document.
-
#editor_for!(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
Returns an editor associated with the given document, creating it if needed.
-
#execute_action(name, *args) ⇒ Object
Executes a given action.
-
#focus_on_editor(ed = nil, hints = DEFAULT_HINTS) ⇒ EditorView?
Gives focus to an editor view.
-
#initialize(_manager, pdf) ⇒ MainWindow
constructor
Creates a new MainWindow.
-
#load_settings ⇒ nil
Override of PluginLike#load_settings.
-
#projects_directory ⇒ String
The default directory where to look for, and create, projects.
-
#query_close ⇒ TrueClass
Override of PluginLike#query_close.
-
#replace_editor(old, editor_or_doc) ⇒ EditorView?
Replaces an editor with another.
-
#safe_open_project(file, allow_reuse = false) ⇒ Project?
Opens a project, displaying amessage boxe in case of errors.
-
#save_documents(docs = nil) ⇒ Boolean
Asks the user to save multiple documents.
-
#save_settings ⇒ nil
Override of PluginLike#save_settings.
-
#tab(arg) ⇒ Object
The toplevel pane corresponding to the given index or editor.
-
#tabs ⇒ Array<Pane>
The open tabs.
-
#views(doc = nil) ⇒ Array<EditorView>
The views contained in the main window.
-
#without_activating { ... } ⇒ Object
Executes the given block without automatically activating an editor whenever the current tab changes.
Methods included from GuiStatesHandler
#change_state, included, #register_action_handler, #remove_action_handler_for, #state
Methods included from PluginLike
#add_extensions_to_project, #add_options_to_project, #add_widgets_to_project, #plugin_name, #register_with_project, #remove_extensions_from_project, #remove_from_project, #remove_options_from_project, #remove_widgets_from_project, #restore_session, #session_data, #shutdown, #unload, #update_project
Constructor Details
#initialize(_manager, pdf) ⇒ MainWindow
Creates a new MainWindow. _manager is the component manager, while pdf is the plugin description for this object.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/ruber/main_window/main_window.rb', line 97 def initialize _manager, pdf super nil, 0 initialize_plugin pdf initialize_states_handler self. = Workspace.new self # We need the instance variable to use it with Forwardable @workspace = @tabs = .instance_variable_get :@views @tabs.tabs_closable = Ruber[:config][:workspace, :close_buttons] @view_manager = ViewManager.new @tabs, self @auto_activate_editors = true @ui_states = {} @actions_state_handlers = Hash.new{|h, k| h[k] = []} @about_plugin_actions = [] @switch_to_actions = [] @last_session_data = nil self. = StatusBar.new self self.connect(SIGNAL('current_document_changed(QObject*)')) do |doc| change_state 'current_document', !doc.nil? end connect Ruber[:components], SIGNAL('component_loaded(QObject*)'), self, SLOT('add_about_plugin_action(QObject*)') connect Ruber[:components], SIGNAL('unloading_component(QObject*)'), self, SLOT('remove_about_plugin_action(QObject*)') connect Ruber[:components], SIGNAL('unloading_component(QObject*)'), self, SLOT('remove_plugin_ui_actions(QObject*)') connect @view_manager, SIGNAL('active_editor_changed(QWidget*)'), self, SLOT('slot_active_editor_changed(QWidget*)') connect Ruber[:documents], SIGNAL('document_created(QObject*)'), self, SLOT('document_created(QObject*)') connect Ruber[:documents], SIGNAL('closing_document(QObject*)'), self, SLOT(:update_switch_to_list) setup_actions action_collection Ruber[:projects].connect( SIGNAL('current_project_changed(QObject*)') ) do |prj| change_state "active_project_exists", !prj.nil? change_title end connect @tabs, SIGNAL('tabCloseRequested(int)'), self, SLOT('close_tab(int)') connect Ruber[:projects], SIGNAL('closing_project(QObject*)'), self, SLOT('close_project_files(QObject*)') setup_GUI create_shell_GUI true config_obj = Ruber[:config].kconfig apply_main_window_settings KDE::ConfigGroup.new( config_obj, 'MainWindow') recent_files = KDE::ConfigGroup.new config_obj, 'Recent files' open_recent_action =action_collection.action("file_open_recent") open_recent_action.load_entries recent_files switch_to_recent_action = action_collection.action("window-switch_to_recent_file") switch_to_recent_action.load_entries recent_files # Synchronize the two menus, so that when the user clears one of them the also # is also cleared connect open_recent_action, SIGNAL(:recentListCleared), switch_to_recent_action, SLOT(:clear) connect switch_to_recent_action, SIGNAL(:recentListCleared), open_recent_action, SLOT(:clear) recent_projects = KDE::ConfigGroup.new config_obj, 'Recent projects' action_collection.action("project-open_recent").load_entries recent_projects .show setup_initial_states end |
Instance Attribute Details
#last_session_data ⇒ Object (readonly)
A hash with the data stored in the session manager by plugins. The hash is only availlable after the restore
method has been called (which means that it will always be unavaillable if ruber wasn’t started by the session manager). If the hash isn’t availlable, nil is returned
NOTE: only for use by Application when restoring the session
91 92 93 |
# File 'lib/ruber/main_window/main_window.rb', line 91 def last_session_data @last_session_data end |
#workspace ⇒ Workspace (readonly)
The widget which contains the tool widgets.
The primary use of this method is to connect to the signals emitted from the workspace when a tool widget is raised, shown or hidden. All of its other methods are also provided by the MainWindow, so you shouldn’t need to access the workspace to use them.
81 82 83 |
# File 'lib/ruber/main_window/main_window.rb', line 81 def workspace @workspace end |
Instance Method Details
#activate_editor(editor) ⇒ Object
Activates an editor
If the editor is not in the current tab, the tab it belongs to becomes active.
Activating an editor means merging its GUI with the main window’s GUI, changing the title of the main window accordingly and telling the status bar to refer to that view.
After activating the editor, the #current_document_changed and #active_editor_changed signals are emitted.
393 394 395 396 397 398 399 400 |
# File 'lib/ruber/main_window/main_window.rb', line 393 def activate_editor editor tab = @view_manager.tab editor return unless tab @tabs. = tab return if active_editor == editor @view_manager.make_editor_active editor editor end |
#active_editor ⇒ EditorView? Also known as: current_editor
The active editor
The active editor is the editor which has its GUI merged with the main window’s. This means it is the editor which last received focus and the one which would receive focus when the tab widget does. If the focus already is in the tab widget, then the active editor is the one whose @is_active_window@ method returns true.
374 375 376 |
# File 'lib/ruber/main_window/main_window.rb', line 374 def active_editor @view_manager.active_editor end |
#close_editor(editor, ask = true) ⇒ Boolean
Always use this method to close an editor, rather than calling its close method directly, unless you want to leave the corresponding document without a view
Closes an editor view
If the editor to be closed is the last editor associated with the document the document will be closed. If ask is true and the document is modified, the user will be asked whether to save or discard the changes and will have the possibility of aborting closing the editor (and the document). If ask is false, the document will be closed without user interaction.
If there are other editors associated with the document besides the one to close, the latter will be closed without affecting the document.
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/ruber/main_window/main_window.rb', line 548 def close_editor editor, ask = true # editor_tab = self.tab(editor) # has_focus = editor_tab.is_active_window if editor_tab # if has_focus # views = editor_tab.to_a # idx = views.index(editor) # new_view = views[idx-1] || views[idx+1] # end doc = editor.document if doc.views.size > 1 editor.close true else doc.close ask end # focus_on_editor new_view if new_view end |
#current_document ⇒ Document? Also known as: active_document
The document associated with the active editor
This is a convenience method for @active_editor.document@ which takes care of the case when there’s no active editor.
466 467 468 |
# File 'lib/ruber/main_window/main_window.rb', line 466 def current_document (ed = active_editor) ? ed.document : nil end |
#display_doc(doc, hints = DEFAULT_HINTS) ⇒ EditorView? Also known as: display_document
Displays an editor for the given document
This method is similar to #editor_for! but, after retrieving the editor (creating it and/or the document as needed), it activates and gives focus to it and moves the cursor to the given position.
Besides the keys listed in #editor_for!, hints can also contain the two entries @:line@ and @:column@.
490 491 492 493 494 495 496 497 498 |
# File 'lib/ruber/main_window/main_window.rb', line 490 def display_doc doc, hints = DEFAULT_HINTS ed = editor_for! doc, hints return unless ed activate_editor ed line = hints[:line] ed.go_to line, hints[:column] || 0 if line ed.set_focus ed end |
#editor_for(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
Returns an editor associated with the given document
It works mostly like #editor_for!, but it doesn’t attempt to create the document if it doesn’t exist an always sets the @create_if_needed@ hint to false. See #editor_for! for the values it can contain.
editor associated with the given document exists or no document corresponds to doc file doesn’t exist
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
# File 'lib/ruber/main_window/main_window.rb', line 346 def editor_for doc, hints = DEFAULT_HINTS hints = DEFAULT_HINTS.merge hints hints[:create_if_needed] = false unless doc.is_a? Document url = doc if url.is_a? String url = KDE::Url.new url if url.relative? path = File. url.path url.path = path end end doc = Ruber[:documents].document_for_url url end return unless doc @view_manager.editor_for doc, hints end |
#editor_for!(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
Returns an editor associated with the given document, creating it if needed
If doc is not a document and no document for the file representing by the string or URL doc is open, it will be created.
Since there can be more than one editor associated with the document, the optional hints argument can be used to specify which one should be returned. If no editor exists for the document, or none of the exisiting ones statisfy the @existing@ hint, a new one will be created, unless the @create_if_needed@ hint is false.
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/ruber/main_window/main_window.rb', line 299 def editor_for! doc, hints = DEFAULT_HINTS hints = DEFAULT_HINTS.merge hints if hints[:new] == :replace if active_editor hints[:existing] = :never hints[:show] = false else hints[:new] = :new_tab end end docs = Ruber[:documents].documents unless doc.is_a? Document unless hints.has_key? :close_starting_document hints[:close_starting_document] = docs.size == 1 && docs[0].extension(:ruber_default_document).default_document && docs[0].pristine? end url = doc if url.is_a? String url = KDE::Url.new url if url.relative? path = File. url.path url.path = path end end doc = Ruber[:documents].document url end return unless doc ed = @view_manager.without_activating{@view_manager.editor_for doc, hints} if hints[:new] == :replace replace_editor active_editor, ed else ed end end |
#execute_action(name, *args) ⇒ Object
Executes a given action
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
# File 'lib/ruber/main_window/main_window.rb', line 764 def execute_action name, *args data = plugin_description.actions[name.to_s] if data slot = data.slot.sub(/\(.*/, '') instance_eval(data.receiver).send slot, *args true elsif (action = action_collection.action(name)) if action.class == KDE::ToggleAction then KDE::ToggleAction action.instance_eval{emit toggled(*args)} elsif action.class == KDE::Action action.instance_eval{emit triggered()} else action.instance_eval{emit triggered(*args)} end true else false end end |
#focus_on_editor ⇒ EditorView? #focus_on_editor(editor) ⇒ EditorView? #focus_on_editor(doc, hints = DEFAULT_HINTS) ⇒ EditorView?
Gives focus to an editor view
Giving focus to the editor implies:
-
bringing the tab containing it to the foreground
-
activating the editor
-
giving focus to the editor
737 738 739 740 741 742 743 744 745 |
# File 'lib/ruber/main_window/main_window.rb', line 737 def focus_on_editor ed = nil, hints = DEFAULT_HINTS if ed ed = editor_for! ed, hints unless ed.is_a? EditorView activate_editor ed ed.set_focus else active_editor.set_focus if active_editor end active_editor end |
#load_settings ⇒ nil
Override of PluginLike#load_settings
705 706 707 708 709 710 711 |
# File 'lib/ruber/main_window/main_window.rb', line 705 def load_settings c = Ruber[:config][:general] @default_script_dir = KDE::Url.from_path c.default_script_directory @default_project_dir = KDE::Url.from_path c.default_project_directory @tabs.tabs_closable = Ruber[:config][:workspace, :close_buttons] if @tabs nil end |
#projects_directory ⇒ String
Returns the default directory where to look for, and create, projects.
750 751 752 |
# File 'lib/ruber/main_window/main_window.rb', line 750 def projects_directory @default_project_dir end |
#query_close ⇒ TrueClass
Override of PluginLike#query_close
It stores the session data retrieved by the component manager in case of session saving and does nothing otherwise.
621 622 623 624 625 626 |
# File 'lib/ruber/main_window/main_window.rb', line 621 def query_close if Ruber[:app].session_saving @session_data = Ruber[:components].session_data end true end |
#replace_editor(old, new_ed) ⇒ EditorView? #replace_editor(old, doc) ⇒ EditorView?
Replaces an editor with another
If the editor to be replaced is the only one associated witha given document and the document is modified, the user is asked whether he wants to save it or not. If he chooses to abort, the editor is not replaced, otherwise the document is closed.
The new editor is put in the same pane which contained the old one (without splitting it).
430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/ruber/main_window/main_window.rb', line 430 def replace_editor old, editor_or_doc if old.document.views.size == 1 return unless old.document.query_close close_doc = true end if editor_or_doc.is_a?(EditorView) then ed = editor_or_doc else ed = editor_for! editor_or_doc, :existing => :never, :show => false end old.parent.replace_view old, ed close_editor old, false ed end |
#safe_open_project(file, allow_reuse = false) ⇒ Project?
Opens a project, displaying amessage boxe in case of errors
This method provides a standard interface for creating a project from a project file named, automatically handling the possible exceptions.
In particular, a message box will be displayed if the project file doesn’t exist or if it exists but it’s not a valid project file.
If the project corresponding to the given file is already open, the behaviour depends on the value of allow_reuse. If false, the user is warned with a message box that the project is already open and nothing is done. If allow_reuse is true, the existing project is returned.
The new project will be made active and the existing one (if any) will be closed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
# File 'lib/ruber/main_window/main_window.rb', line 650 def safe_open_project file, allow_reuse = false prj = Ruber[:projects][file] if !allow_reuse and prj text = "A project corresponding to the file #{file} is already open. Please, close it before attempting to open it again" KDE::MessageBox.sorry self, KDE.i18n(text) return nil elsif prj then return prj end = nil begin prj = Ruber[:projects].project file rescue Project::InvalidProjectFile => ex text = "%s isn't a valid project file. The error reported was:\n%s" = KDE.i18n(text) % [file, ex.] rescue LoadError then = KDE.i18n(ex.) end if prj # The following two lines should be removed when we'll allow more than one project # open at the same time Ruber[:projects].current_project.close if Ruber[:projects].current_project Ruber[:projects].current_project = prj prj else KDE::MessageBox.sorry self, nil end end |
#save_documents(docs = nil) ⇒ Boolean
Asks the user to save multiple documents
This method is meant to be called in situation where the user may want to save a number of documents, for example when the application is quitting, as it avoids displaying a dialog box for each modified document.
It displays a dialog where the user can choose, among the documents passed as first argument, which ones he wants to save. The user has three choiches:
-
save some (or all) the files, then proceed with the operation which has caused
the dialog to be shown (for example, quitting the application)
-
don’t save any file and go on with the operation
-
abort the operation.
In the first case, this method attempts to perform save the selected files. If any of them can’t be saved, the dialog to choose the files to save will be displayed again, with only those files which couldn’t be saved (after informing the user of the failure). The user can again chose which of those files this method should attempt to save again, or whether to abort the operation or skip saving. This will be repeated until all files have been saved or the user gives up
In the second and third cases, the method simply returns respectively true or false.
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/ruber/main_window/main_window.rb', line 594 def save_documents docs = nil docs ||= Ruber[:docs] to_save = docs.select{|d| d.modified?} until to_save.empty? dlg = SaveModifiedFilesDlg.new to_save, self case dlg.exec when KDE::Dialog::Yes to_save = Ruber[:docs].save_documents dlg.to_save unless to_save.empty? msg = "The following documents couldn't be saved: #{to_save.join "\n"}\nPlease, choose how to proceed" KDE::MessageBox.sorry nil, KDE.i18n(msg) end when KDE::Dialog::No then to_save.clear when Qt::Dialog::Rejected then return false end end true end |
#save_settings ⇒ nil
Override of PluginLike#save_settings
It saves recent files and projects, the position of the splitters and the size of the window.
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
# File 'lib/ruber/main_window/main_window.rb', line 685 def save_settings @workspace.store_sizes # TODO see if the following line works. Otherwise, remove it and uncomment the one # following it config = Ruber[:config].kconfig # config = KDE::Global.config recent_files = KDE::ConfigGroup.new config, 'Recent files' action_collection.action("file_open_recent").save_entries recent_files recent_projects = KDE::ConfigGroup.new config, 'Recent projects' action_collection.action("project-open_recent").save_entries recent_projects config.sync c = Ruber[:config][:main_window] c.window_size = rect.size nil end |
#tab(idx) ⇒ Pane #tab(editor) ⇒ Pane
The toplevel pane corresponding to the given index or editor
453 454 455 |
# File 'lib/ruber/main_window/main_window.rb', line 453 def tab arg @view_manager.tab arg end |
#tabs ⇒ Array<Pane>
The open tabs
158 159 160 |
# File 'lib/ruber/main_window/main_window.rb', line 158 def tabs @tabs.to_a end |
#views(doc = nil) ⇒ Array<EditorView>
The views contained in the main window
If a document is given as argument, returns all views associated with the document; if no document is given, all views are returned.
The order of the views in the returned list is the activation order: the view which was activated more recently is at position 0 in the array, the one activated before that is at position 1 and so on. Views which have never been activated are at the end of the array, in an arbitrary order
179 180 181 182 183 |
# File 'lib/ruber/main_window/main_window.rb', line 179 def views doc = nil if doc then @view_manager.activation_order.select{|v| v.document == doc} else @view_manager.activation_order.dup end end |
#without_activating { ... } ⇒ Object
automatical editor activation will be restored at the end of this method (even if exceptions occur).
Executes the given block without automatically activating an editor whenever the current tab changes
This method should be used, for example, when more than one editor should be opened at once. Without this, every new editor would become (for a little time) the active one, with its gui merged with the main window and so on. This slows things down and should be avoided. To do so, you use this method:
bc. Ruber.without_activating do
ed = nil
files.each do |f|
ed = Ruber[:main_window].editor_for! f
end
Ruber[:main_window].activate_editor ed
end
After calling this method, the focus widget of the current tab gets focus
525 526 527 |
# File 'lib/ruber/main_window/main_window.rb', line 525 def without_activating &blk @view_manager.without_activating &blk end |