ruber 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. data/CHANGES +25 -0
  2. data/bin/ruber +0 -0
  3. data/data/share/apps/ruber/ruberui.rc +15 -1
  4. data/data/share/icons/{ruber.png → ruber-old.pgn} +0 -0
  5. data/lib/ruber/application/application.rb +216 -73
  6. data/lib/ruber/application/plugin.yaml +2 -2
  7. data/lib/ruber/document_project.rb +25 -5
  8. data/lib/ruber/documents/document_list.rb +11 -15
  9. data/lib/ruber/editor/document.rb +106 -50
  10. data/lib/ruber/editor/editor_view.rb +4 -2
  11. data/lib/ruber/external_program_plugin.rb +8 -0
  12. data/lib/ruber/kde_config_option_backend.rb +12 -4
  13. data/lib/ruber/kde_sugar.rb +35 -1
  14. data/lib/ruber/main_window/choose_plugins_dlg.rb +10 -10
  15. data/lib/ruber/main_window/hint_solver.rb +263 -0
  16. data/lib/ruber/main_window/main_window.rb +462 -206
  17. data/lib/ruber/main_window/main_window_actions.rb +228 -62
  18. data/lib/ruber/main_window/main_window_internal.rb +169 -115
  19. data/lib/ruber/main_window/plugin.yaml +13 -3
  20. data/lib/ruber/main_window/save_modified_files_dlg.rb +1 -1
  21. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +1 -1
  22. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +1 -1
  23. data/lib/ruber/main_window/ui/new_project_widget.rb +1 -1
  24. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +1 -1
  25. data/lib/ruber/main_window/ui/output_color_widget.rb +1 -1
  26. data/lib/ruber/main_window/ui/workspace_settings_widget.rb +51 -0
  27. data/lib/ruber/main_window/ui/workspace_settings_widget.ui +28 -0
  28. data/lib/ruber/main_window/view_manager.rb +418 -0
  29. data/lib/ruber/main_window/workspace.png +0 -0
  30. data/lib/ruber/output_widget.rb +43 -37
  31. data/lib/ruber/pane.rb +621 -0
  32. data/lib/ruber/plugin_specification_reader.rb +8 -1
  33. data/lib/ruber/projects/project_files_list.rb +6 -0
  34. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +1 -1
  35. data/lib/ruber/projects/ui/project_files_widget.rb +1 -1
  36. data/lib/ruber/qt_sugar.rb +94 -4
  37. data/lib/ruber/utils.rb +16 -7
  38. data/lib/ruber/version.rb +2 -2
  39. data/plugins/autosave/autosave.rb +62 -1
  40. data/plugins/autosave/plugin.yaml +1 -0
  41. data/plugins/autosave/ui/autosave_config_widget.rb +37 -14
  42. data/plugins/autosave/ui/autosave_config_widget.ui +62 -12
  43. data/plugins/find_in_files/find_in_files_widgets.rb +1 -3
  44. data/plugins/find_in_files/ui/config_widget.rb +1 -1
  45. data/plugins/find_in_files/ui/find_in_files_widget.rb +1 -1
  46. data/plugins/rake/plugin.yaml +1 -1
  47. data/plugins/rake/ui/add_quick_task_widget.rb +1 -1
  48. data/plugins/rake/ui/choose_task_widget.rb +1 -1
  49. data/plugins/rake/ui/config_widget.rb +1 -1
  50. data/plugins/rake/ui/project_widget.rb +1 -1
  51. data/plugins/rspec/rspec.rb +14 -22
  52. data/plugins/rspec/ruber_rspec_formatter.rb +4 -1
  53. data/plugins/rspec/ui/rspec_project_widget.rb +1 -1
  54. data/plugins/ruby_development/plugin.yaml +7 -2
  55. data/plugins/ruby_development/ruby_development.rb +134 -13
  56. data/plugins/ruby_development/ui/config_widget.rb +66 -0
  57. data/plugins/ruby_development/ui/config_widget.ui +58 -0
  58. data/plugins/ruby_development/ui/project_widget.rb +1 -1
  59. data/plugins/ruby_runner/plugin.yaml +2 -2
  60. data/plugins/ruby_runner/ruby_runner.rb +15 -3
  61. data/plugins/ruby_runner/ui/config_widget.rb +1 -1
  62. data/plugins/ruby_runner/ui/project_widget.rb +1 -1
  63. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +1 -1
  64. data/plugins/state/plugin.yaml +6 -2
  65. data/plugins/state/state.rb +305 -81
  66. data/plugins/state/ui/config_widget.rb +1 -1
  67. data/spec/common.rb +11 -3
  68. data/spec/document_list_spec.rb +8 -8
  69. data/spec/document_project_spec.rb +98 -25
  70. data/spec/document_spec.rb +178 -152
  71. data/spec/editor_view_spec.rb +26 -5
  72. data/spec/framework.rb +5 -0
  73. data/spec/hint_solver_spec.rb +450 -0
  74. data/spec/kde_sugar_spec.rb +73 -6
  75. data/spec/output_widget_spec.rb +172 -156
  76. data/spec/pane_spec.rb +1165 -0
  77. data/spec/plugin_specification_reader_spec.rb +37 -1
  78. data/spec/project_files_list_spec.rb +30 -20
  79. data/spec/qt_sugar_spec.rb +269 -0
  80. data/spec/state_spec.rb +566 -353
  81. data/spec/utils_spec.rb +1 -1
  82. data/spec/view_manager_spec.rb +71 -0
  83. metadata +16 -4
@@ -28,17 +28,20 @@ config_options:
28
28
  v_splitter: {key: Vertical splitter, type: string list, default: "['80', '20']"}
29
29
  workspace:
30
30
  tools_sizes: {default: {}}
31
+ close_buttons: {default: 'true', type: bool}
31
32
  config_widgets:
32
33
  - {caption: General, pixmap: configure, class: Ruber::MainWindowSettingsWidget}
33
34
  - {caption: Colors, pixmap: fill-color, class: Ruber::OutputColorWidget}
35
+ - {caption: Workspace, pixmap: workspace.png, class: Ruber::MainWindow::WorkspaceSettingsWidget}
34
36
  actions:
35
37
  file_new: {standard_action: open_new, slot: new_file()}
36
38
  file_open: {standard_action: open, slot: open_file()}
37
39
  file_open_recent: {standard_action: open_recent, signal: urlSelected(KUrl), slot: open_recent_file(KUrl)}
38
40
  file-save_all: {text: Save &All, icon: document-save-all, slot: save_all()}
39
41
  file_close: {standard_action: close, slot: close_current_editor()}
40
- file-close_all: {text: Clos&e All, slot: close_all_views()}
41
- file-close_other: {text: Close All O&ther, slot: close_other_views()}
42
+ file-close_tab: {text: Close Current &Tab, slot: close_tab(), state: current_document}
43
+ file-close_all: {text: Clos&e All, slot: close_all_views(), state: current_document}
44
+ file-close_other: {text: Close All O&ther, slot: close_other_views(), state: current_document}
42
45
  file_quit: {standard_action: quit, receiver: 'Ruber[:app]', slot: closeAllWindows()}
43
46
  go_back: {standard_action: back, slot: previous_document(), shortcut: Alt+Left}
44
47
  go_forward: {standard_action: forward, slot: next_document(), shortcut: Alt+Right}
@@ -55,4 +58,11 @@ actions:
55
58
  options-choose_plugins: {text: C&hoose Plugins..., icon: preferences-plugin, slot: choose_plugins()}
56
59
  options_configure: {standard_action: preferences, slot: preferences()}
57
60
  configure_document: {text: Configure &Document, icon: configure, slot: configure_document(), state: current_document}
58
- help_user_manual: {text: Ruber User &Manual, icon: help-contents, slot: show_user_manual()}
61
+ help_user_manual: {text: Ruber User &Manual, icon: help-contents, slot: show_user_manual()}
62
+ window-split_horizontally: {text: Split Horizontally, slot: split_horizontally(), shortcut: Ctrl+Shift+T, state: current_document}
63
+ window-split_vertically: {text: Split Vertically, slot: split_vertically(), shortcut: Ctrl+Shift+L, state: current_document}
64
+ window-switch_to_new_document: {text: Switch to New File, slot: switch_to_new_document(), state: current_document}
65
+ window-switch_to_file: {text: Switch to Open File, slot: switch_to_file(), state: current_document}
66
+ window-switch_to_recent_file: {signal: urlSelected(KUrl), slot: switch_to_recent_file(KUrl), class: KDE::RecentFilesAction, text: Switch to Recent File, state: current_document}
67
+ extensions:
68
+ ruber_default_document: {class: Ruber::Application::DefaultDocumentExtension, scope: document, place: all}
@@ -71,7 +71,7 @@ module Ruber
71
71
  end
72
72
 
73
73
  cancel = KDE::StandardGuiItem.cancel
74
- cancel.text = KDE::i18n "&Abort saving"
74
+ cancel.text = KDE::i18n "&Abort"
75
75
  set_button_gui_item Cancel, cancel
76
76
  end
77
77
 
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'choose_plugins_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'main_window_settings_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'new_project_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:48 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'open_file_in_project_dlg.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'output_color_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -0,0 +1,51 @@
1
+ =begin
2
+ ** Form generated from reading ui file 'workspace_settings_widget.ui'
3
+ **
4
+ ** Created: mar gen 11 14:57:22 2011
5
+ ** by: Qt User Interface Compiler version 4.7.1
6
+ **
7
+ ** WARNING! All changes made in this file will be lost when recompiling ui file!
8
+ =end
9
+
10
+ class Ui_WorkspaceSettingsWidgetBase
11
+ attr_reader :verticalLayout
12
+ attr_reader :_workspace__close_buttons
13
+
14
+ def setupUi(workspaceSettingsWidgetBase)
15
+ if workspaceSettingsWidgetBase.objectName.nil?
16
+ workspaceSettingsWidgetBase.objectName = "workspaceSettingsWidgetBase"
17
+ end
18
+ workspaceSettingsWidgetBase.resize(400, 35)
19
+ @verticalLayout = Qt::VBoxLayout.new(workspaceSettingsWidgetBase)
20
+ @verticalLayout.objectName = "verticalLayout"
21
+ @_workspace__close_buttons = Qt::CheckBox.new(workspaceSettingsWidgetBase)
22
+ @_workspace__close_buttons.objectName = "_workspace__close_buttons"
23
+
24
+ @verticalLayout.addWidget(@_workspace__close_buttons)
25
+
26
+
27
+ retranslateUi(workspaceSettingsWidgetBase)
28
+
29
+ Qt::MetaObject.connectSlotsByName(workspaceSettingsWidgetBase)
30
+ end # setupUi
31
+
32
+ def setup_ui(workspaceSettingsWidgetBase)
33
+ setupUi(workspaceSettingsWidgetBase)
34
+ end
35
+
36
+ def retranslateUi(workspaceSettingsWidgetBase)
37
+ workspaceSettingsWidgetBase.windowTitle = Qt::Application.translate("WorkspaceSettingsWidgetBase", "Form", nil, Qt::Application::UnicodeUTF8)
38
+ @_workspace__close_buttons.text = Qt::Application.translate("WorkspaceSettingsWidgetBase", "&Display close buttons on tabs", nil, Qt::Application::UnicodeUTF8)
39
+ end # retranslateUi
40
+
41
+ def retranslate_ui(workspaceSettingsWidgetBase)
42
+ retranslateUi(workspaceSettingsWidgetBase)
43
+ end
44
+
45
+ end
46
+
47
+ module Ui
48
+ class WorkspaceSettingsWidgetBase < Ui_WorkspaceSettingsWidgetBase
49
+ end
50
+ end # module Ui
51
+
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>WorkspaceSettingsWidgetBase</class>
4
+ <widget class="QWidget" name="WorkspaceSettingsWidgetBase">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>400</width>
10
+ <height>35</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QVBoxLayout" name="verticalLayout">
17
+ <item>
18
+ <widget class="QCheckBox" name="_workspace__close_buttons">
19
+ <property name="text">
20
+ <string>&amp;Display close buttons on tabs</string>
21
+ </property>
22
+ </widget>
23
+ </item>
24
+ </layout>
25
+ </widget>
26
+ <resources/>
27
+ <connections/>
28
+ </ui>
@@ -0,0 +1,418 @@
1
+ =begin
2
+ Copyright (C) 2010,2011 by Stefano Crocco
3
+ stefano.crocco@alice.it
4
+
5
+ This program is free software; you can redistribute it andor modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the
17
+ Free Software Foundation, Inc.,
18
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+ =end
20
+
21
+ require 'ruber/main_window/hint_solver'
22
+ require 'ruber/pane'
23
+
24
+ module Ruber
25
+
26
+ class MainWindow
27
+
28
+ =begin rdoc
29
+ Class which manages the views in the tab widget
30
+
31
+ It takes care of activating a view when it gets focus, removing a tab when the
32
+ last view in it is closed, and so on.
33
+
34
+ @note this class is only for internal use by {MainWindow}. Its API is likely to
35
+ change and the whole class may disappear in the future. So, *do not* use it outside
36
+ of {MainWindow}
37
+ =end
38
+ class ViewManager < Qt::Object
39
+
40
+ =begin rdoc
41
+ @return [KDE::PartManager] the part manager which manages the document parts
42
+ =end
43
+ attr_reader :part_manager
44
+
45
+ =begin rdoc
46
+ @return [EditorView,nil] the active editor (that is, the editor whose GUI is merged
47
+ with the main window GUI) or *nil* if no main window exists
48
+ =end
49
+ attr_reader :active_editor
50
+
51
+ =begin rdoc
52
+ @return [Array<EditorView>] a list of all the editors in all tabs, in activation
53
+ order, from more recently activated to less recently activated
54
+ =end
55
+ attr_reader :activation_order
56
+
57
+ =begin rdoc
58
+ @return [Boolean] whether to automatically activate an editor when it is created
59
+ =end
60
+ attr_accessor :auto_activate_editors
61
+
62
+ =begin rdoc
63
+ Signal emitted whenever an editor is created
64
+ @param [EditorView] editor the newly created editor
65
+ =end
66
+ signals 'view_created(QWidget*)'
67
+
68
+ =begin rdoc
69
+ Signal emitted whenever the active editor changes
70
+
71
+ This signal is emitted _after_ the editor has become active
72
+ @param [EditorView,nil] editor the editor which become active or *nil* if no editor
73
+ become active
74
+ =end
75
+ signals 'active_editor_changed(QWidget*)'
76
+
77
+ =begin rdoc
78
+ @param [KDE::TabWidget] tabs the tab widget used by the main window
79
+ @param [Ruber::MainWindow] parent the main window
80
+ =end
81
+ def initialize tabs, parent
82
+ super parent
83
+ @tabs = tabs
84
+ @focus_editors = []
85
+ @part_manager = KParts::PartManager.new parent, self
86
+ @activation_order = []
87
+ @active_editor = nil
88
+ @solver = MainWindow::HintSolver.new @tabs, @part_manager, @activation_order
89
+ @auto_activate_editors = true
90
+ connect @tabs, SIGNAL('currentChanged(int)'), self, SLOT('current_tab_changed(int)')
91
+ end
92
+
93
+ =begin rdoc
94
+ Returns an editor associated with the given document, creating it if needed
95
+
96
+ It works as {MainWindow#editor_for!}.
97
+
98
+ _hints_ may contain the same values as in {MainWindow#editor_for!}. It may also
99
+ contain another value, @:close_starting_document@
100
+ @param [Document] doc the document to retrieve an editor for
101
+ @param hints (see MainWindow#editor_for!)
102
+ @option hints [Boolean] :close_starting_document (false) if given, specifies that
103
+ the default document created by ruber at startup exists and it's in the first
104
+ tab. If a new view is created in a new tab, this document is closed
105
+ @return [EditorView] the view to use for the document
106
+ =end
107
+ def editor_for doc, hints
108
+ editor = @solver.find_editor doc, hints
109
+ if !editor and hints[:create_if_needed]
110
+ editor = create_editor doc
111
+ if hints[:show]
112
+ @activation_order << editor
113
+ view = @solver.place_editor hints
114
+ if view
115
+ dir = Qt.const_get hints[:split].to_s.capitalize
116
+ view.parent.split view, editor, dir
117
+ else
118
+ if hints[:close_starting_document]
119
+ if @tabs.count == 1 and @tabs.widget(0).single_view?
120
+ doc_to_close = @tabs.widget(0).view.document
121
+ end
122
+ end
123
+ add_tab editor, doc.icon, doc.document_name
124
+ doc_to_close.close if doc_to_close
125
+ end
126
+ editor.parent.label = label_for_editor editor
127
+ end
128
+ end
129
+ editor
130
+ end
131
+
132
+ =begin rdoc
133
+ Makes the given editor active
134
+
135
+ Besides merging the editor's GUI with the main window's, this method also deactivates
136
+ the previously active editor, updates the activation order, activates the document
137
+ associated with the new active editor, updates the tab where the new editor is
138
+ and emits the {#active_editor_changed} signal.
139
+
140
+ Nothing is done if the given editor was already active
141
+ @param [EditorView] editor the editor to activate
142
+ @return [EditorView] the new active editor
143
+ =end
144
+ def make_editor_active editor
145
+ return if editor and @active_editor == editor
146
+ deactivate_editor @active_editor
147
+ @active_editor = editor
148
+ if editor
149
+ parent.gui_factory.add_client editor.send(:internal)
150
+ @activation_order.delete editor
151
+ @activation_order.insert 0, editor
152
+ editor_tab = tab(editor)
153
+ tab_idx = @tabs.index_of editor_tab
154
+ @focus_editors[tab_idx] = editor
155
+ update_tab editor_tab
156
+ editor.document.activate
157
+ end
158
+ emit active_editor_changed @active_editor
159
+ @active_editor
160
+ end
161
+
162
+ =begin rdoc
163
+ Deactivates the given editor
164
+
165
+ To deactivate the editor, its GUI is removed from the main window's and the corresponding
166
+ document is deactivated.
167
+
168
+ If the given editor wasn't the active one, nothing is done
169
+ @param [EditorView] view the editor to deactivate
170
+ @return [nil]
171
+ =end
172
+ def deactivate_editor view
173
+ return unless @active_editor and view == @active_editor
174
+ @active_editor.document.deactivate
175
+ parent.gui_factory.remove_client view.send(:internal)
176
+ @active_editor = nil
177
+ nil
178
+ end
179
+
180
+ =begin rdoc
181
+ Executes a block without automatically activating editors
182
+
183
+ Usually, whenever a tab becomes active, one of the editors it contains becomes
184
+ active. Sometimes, you don't want this to happen (for example, when opening multiple
185
+ documents in sequence). To do so, do what you need from a block passed to this method.
186
+
187
+ After the block has been executed, the last activated method in the current tab
188
+ becomes active.
189
+
190
+ @yield the block to call without automatically activating editors
191
+ @return [Object] the value returned by the block
192
+ =end
193
+ def without_activating
194
+ begin
195
+ @auto_activate_editors = false
196
+ yield
197
+ ensure
198
+ @auto_activate_editors = true
199
+ if @tabs.current_index < 0 then make_editor_active nil
200
+ else make_editor_active @focus_editors[@tabs.current_index]
201
+ end
202
+ end
203
+ end
204
+
205
+ =begin rdoc
206
+ The toplevel pane corresponding to the given index or widget
207
+
208
+ @overload tab idx
209
+ @param [Integer] idx the index of the tab
210
+ @return [Pane] the toplevel pane in the tab number _idx_
211
+ @overload tab editor
212
+ @param [EditorView] editor the editor to retrieve the pane for
213
+ @return [Pane,nil] the toplevel pane containing the given editor or *nil* if the
214
+ view isn't contained in a pane
215
+ @overload tab pane
216
+ @param [Pane] pane the pane to retrieve the toplevel pane for
217
+ @return [Pane, nil] the toplevel pane containing the given pane or *nil* if the
218
+ pane isn't contained in another pane
219
+ =end
220
+ def tab arg
221
+ if arg.is_a? Integer then @tabs.widget arg
222
+ else
223
+ pane = arg.is_a?(Pane) ? arg : arg.parent
224
+ return unless pane
225
+ pane = pane.parent_pane while pane.parent_pane
226
+ pane
227
+ end
228
+ end
229
+
230
+ =begin rdoc
231
+ Whether the given view is a focus editor
232
+
233
+ @overload focus_editor? editor
234
+ Whether the given view is the focus editor for any tab
235
+ @param [EditorView] editor the view to test
236
+ @return [Boolean] *true* if there's a tab which has _editor_ as focus editor and
237
+ *false* otherwise
238
+ @overload focus_editor? editor, tab
239
+ Whether the given view is the focus editor for the given tab
240
+ @param [EditorView] editor the view to test
241
+ @param [Pane,Integer] tab the tab the view must be focus editor for. If a {Pane}
242
+ it must be the toplevel pane of the tab; if an @Integer@, it must be the index
243
+ of the pane to test
244
+ @note this method doesn't test whether _tab_ actually is a toplevel pane
245
+ @return [Boolean] *true* if _editor_ is the focus widget for _tab_ and
246
+ *false* otherwise
247
+ =end
248
+ def focus_editor? editor, tab = nil
249
+ if tab
250
+ tab = @tabs.index_of(tab) unless tab.is_a? Integer
251
+ @focus_editors[tab] == editor
252
+ else @focus_editors.any?{|k, v| v == editor}
253
+ end
254
+ end
255
+
256
+ =begin rdoc
257
+ The label to use for an editor
258
+
259
+ @param [EditorView] ed the editor to return the label for
260
+ @return [String] the text to show below the given editor
261
+ =end
262
+ def label_for_editor ed
263
+ url = ed.document.url
264
+ if url.valid? then url.local_file? ? url.path : url.pretty_url
265
+ else ed.document.document_name
266
+ end
267
+ end
268
+
269
+ private
270
+
271
+ =begin rdoc
272
+ Creates an editor for a document
273
+
274
+ @param [Document] doc the document to create the editor for
275
+ @return [EditorView] the new editor for the document
276
+ =end
277
+ def create_editor doc
278
+ editor = doc.create_view
279
+ connect editor, SIGNAL('focus_in(QWidget*)'), self, SLOT('focus_in_view(QWidget*)')
280
+ connect editor, SIGNAL('closing(QWidget*)'), self, SLOT('view_closing(QWidget*)')
281
+ editor
282
+ end
283
+
284
+ =begin rdoc
285
+ Adds a new tab to the tab widget
286
+
287
+ The tab is created with a view inserted in it and is assigned an icon an a label
288
+ @param [EditorView] view the view to insert in the new pane
289
+ @param [Qt::Icon] icon the icon to associate with the new tab
290
+ @param [String] label the label to use for the new tab
291
+ @return [Pane] the pane corresponding to the new tab
292
+ =end
293
+ def add_tab view, icon, label
294
+ new_tab = Pane.new(view)
295
+ idx = @tabs.add_tab new_tab, icon, label
296
+ @focus_editors[idx] = view
297
+ connect new_tab, SIGNAL('closing_last_view(QWidget*)'), self, SLOT('remove_tab(QWidget*)')
298
+ connect new_tab, SIGNAL('pane_split(QWidget*, QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
299
+ connect new_tab, SIGNAL('removing_view(QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
300
+ connect new_tab, SIGNAL('view_replaced(QWidget*, QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
301
+ new_tab
302
+ end
303
+
304
+ =begin rdoc
305
+ Removes the tab corresponding to the given toplevel pane
306
+
307
+ @param [Pane] pane the toplevel pane whose tab should be removed
308
+ @return [nil]
309
+ =end
310
+ def remove_tab pane
311
+ idx = @tabs.index_of pane
312
+ if idx
313
+ @focus_editors.delete_at idx
314
+ @tabs.remove_tab idx
315
+ end
316
+ nil
317
+ end
318
+ slots 'remove_tab(QWidget*)'
319
+
320
+ =begin rdoc
321
+ Slot called whenever a view receives focus
322
+
323
+ The views is activated, unless it was already active
324
+ @param [EditorView] view the view which received focus
325
+ @return [nil]
326
+ =end
327
+ def focus_in_view view
328
+ if view != @active_editor
329
+ make_editor_active view
330
+ end
331
+ nil
332
+ end
333
+ slots 'focus_in_view(QWidget*)'
334
+
335
+ =begin rdoc
336
+ Slot called whenever a view is closed
337
+
338
+ It deactivates the view (if it was active) and preforms some cleanup.
339
+ @param [EditorView] view the view which is being closed
340
+ @return [nil]
341
+ =end
342
+ def view_closing view
343
+ @activation_order.delete view
344
+ disconnect view, SIGNAL('focus_in(QWidget*)'), self, SLOT('focus_in_view(QWidget*)')
345
+ deactivate_editor view
346
+ nil
347
+ end
348
+ slots 'view_closing(QWidget*)'
349
+
350
+ =begin rdoc
351
+ Slot called whenever the current tab changes
352
+
353
+ Unless called from within a {#without_activating} block, it activates and gives focus
354
+ to the view in the new current tab which last got focus.
355
+
356
+ If called from within a {#without_activating} block, or if there's no current tab,
357
+ all editors are deactivated
358
+ @param [Integer] idx the index of the current tab
359
+ @return [nil]
360
+ =end
361
+ def current_tab_changed idx
362
+ if idx > -1
363
+ @focus_editors[idx] ||= @tabs.widget(idx).to_a[0]
364
+ ed = @focus_editors[idx]
365
+ if @auto_activate_editors then ed.set_focus
366
+ else make_editor_active nil
367
+ end
368
+ else
369
+ make_editor_active nil
370
+ end
371
+ nil
372
+ end
373
+ slots 'current_tab_changed(int)'
374
+
375
+ =begin rdoc
376
+ Updates the tab containing the given toplevel pane
377
+
378
+ Updating the tab means changing its icon, its label, its tooltip and the label
379
+ associated with each of the editors it contains
380
+ @param [Pane] pane the toplevel pane contained in the pane to update
381
+ @return [nil]
382
+ =end
383
+ def update_tab pane
384
+ idx = @tabs.index_of tab(pane)
385
+ return if idx < 0
386
+ doc = @focus_editors[idx].document
387
+ @tabs.set_tab_text idx, doc.document_name
388
+ @tabs.set_tab_icon idx, doc.icon
389
+ pane.each_pane{|pn| pn.label = label_for_editor(pn.view) if pn.single_view?}
390
+ update_tool_tip idx
391
+ nil
392
+ end
393
+ slots 'update_tab(QWidget*)'
394
+
395
+ =begin rdoc
396
+ Updates the tooltip for the given tab
397
+
398
+ A pane's tooltip contains the list of the documents associated with the views in
399
+ the tab, separated by newlines.
400
+
401
+ @param [Integer] idx the index of the tab whose tooltip should be updated
402
+ @param [Array<EditorView>] ignore a list of views which shouldn't be considered
403
+ when creating the tool tip. This is necessary because, when a view is closed,
404
+ this method is called _before_ the view is removed from the pane, so the document
405
+ associated with it would be included in the tooltip if it weren't specified here
406
+ @return [nil]
407
+ =end
408
+ def update_tool_tip idx, *ignore
409
+ docs = @tabs.widget(idx).reject{|v| ignore.include? v}.map{|v| v.document.document_name}.uniq
410
+ @tabs.set_tab_tool_tip idx, docs.join("\n")
411
+ nil
412
+ end
413
+
414
+ end
415
+
416
+ end
417
+
418
+ end