ruber 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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