ruber 0.0.8 → 0.0.9

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 (81) hide show
  1. data/CHANGES +21 -0
  2. data/data/share/apps/ruber/ruberui.rc +3 -1
  3. data/lib/ruber/application/application.rb +22 -23
  4. data/lib/ruber/application/plugin.yaml +7 -2
  5. data/lib/ruber/{projects → application}/project_files_list.rb +0 -0
  6. data/lib/ruber/{projects → application}/project_files_widget.rb +0 -0
  7. data/lib/ruber/application/ui/project_files_rule_chooser_widget.rb +74 -0
  8. data/lib/ruber/{projects → application}/ui/project_files_rule_chooser_widget.ui +0 -0
  9. data/lib/ruber/application/ui/project_files_widget.rb +117 -0
  10. data/lib/ruber/{projects → application}/ui/project_files_widget.ui +0 -0
  11. data/lib/ruber/component_manager.rb +14 -9
  12. data/lib/ruber/editor/document.rb +35 -5
  13. data/lib/ruber/kde_sugar.rb +16 -0
  14. data/lib/ruber/main_window/choose_plugins_dlg.rb +7 -4
  15. data/lib/ruber/main_window/main_window.rb +131 -193
  16. data/lib/ruber/main_window/main_window_actions.rb +157 -58
  17. data/lib/ruber/main_window/main_window_internal.rb +145 -54
  18. data/lib/ruber/main_window/open_file_in_project_dlg.rb +4 -4
  19. data/lib/ruber/main_window/plugin.yaml +3 -6
  20. data/lib/ruber/main_window/ui/workspace_settings_widget.rb +2 -2
  21. data/lib/ruber/main_window/workspace.rb +62 -32
  22. data/lib/ruber/output_widget.rb +20 -16
  23. data/lib/ruber/pane.rb +11 -5
  24. data/lib/ruber/project.rb +27 -12
  25. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +2 -2
  26. data/lib/ruber/projects/ui/project_files_widget.rb +2 -2
  27. data/lib/ruber/utils.rb +37 -4
  28. data/lib/ruber/version.rb +1 -1
  29. data/lib/ruber/world/document_factory.rb +121 -0
  30. data/lib/ruber/world/document_list.rb +396 -0
  31. data/lib/ruber/world/environment.rb +470 -0
  32. data/lib/ruber/{main_window → world}/hint_solver.rb +1 -1
  33. data/lib/ruber/world/plugin.yaml +11 -0
  34. data/lib/ruber/world/project_factory.rb +131 -0
  35. data/lib/ruber/world/project_list.rb +265 -0
  36. data/lib/ruber/world/ui/workspace_settings_widget.rb +51 -0
  37. data/lib/ruber/{main_window → world}/ui/workspace_settings_widget.ui +0 -0
  38. data/lib/ruber/world/world.rb +307 -0
  39. data/plugins/auto_end/auto_end.rb +135 -9
  40. data/plugins/autosave/autosave.rb +4 -4
  41. data/plugins/find_in_files/find_in_files.rb +5 -5
  42. data/plugins/find_in_files/find_in_files_widgets.rb +1 -1
  43. data/plugins/project_browser/project_browser.rb +4 -4
  44. data/plugins/rake/rake.rb +4 -4
  45. data/plugins/rake/rake_extension.rb +1 -1
  46. data/plugins/rspec/rspec.rb +4 -4
  47. data/plugins/rspec/ruber_rspec_formatter.rb +2 -2
  48. data/plugins/ruby_development/ruby_development.rb +3 -3
  49. data/plugins/ruby_runner/ruby_runner.rb +2 -2
  50. data/plugins/state/plugin.yaml +6 -8
  51. data/plugins/state/state.rb +201 -391
  52. data/plugins/state/ui/config_widget.rb +5 -5
  53. data/plugins/state/ui/config_widget.ui +3 -3
  54. data/plugins/syntax_checker/syntax_checker.rb +4 -0
  55. data/spec/annotation_model_spec.rb +1 -1
  56. data/spec/auto_end_spec.rb +98 -47
  57. data/spec/component_manager_spec.rb +80 -21
  58. data/spec/document_factory_spec.rb +115 -0
  59. data/spec/document_list_spec.rb +560 -450
  60. data/spec/document_spec.rb +143 -55
  61. data/spec/editor_view_spec.rb +2 -2
  62. data/spec/environment_spec.rb +1900 -0
  63. data/spec/hint_solver_spec.rb +5 -5
  64. data/spec/kde_sugar_spec.rb +16 -0
  65. data/spec/output_widget_spec.rb +177 -51
  66. data/spec/pane_spec.rb +29 -5
  67. data/spec/plugin_spec.rb +1 -1
  68. data/spec/project_factory_spec.rb +104 -0
  69. data/spec/project_list_spec.rb +352 -447
  70. data/spec/project_spec.rb +34 -33
  71. data/spec/qt_sugar_spec.rb +2 -2
  72. data/spec/state_spec.rb +508 -811
  73. data/spec/utils_spec.rb +149 -98
  74. data/spec/workspace_spec.rb +120 -9
  75. data/spec/world_spec.rb +1219 -0
  76. metadata +23 -14
  77. data/lib/ruber/documents/document_list.rb +0 -412
  78. data/lib/ruber/documents/plugin.yaml +0 -4
  79. data/lib/ruber/main_window/view_manager.rb +0 -431
  80. data/lib/ruber/projects/plugin.yaml +0 -11
  81. data/lib/ruber/projects/project_list.rb +0 -314
@@ -1,4 +0,0 @@
1
- name: documents
2
- require: document_list
3
- class: Ruber::DocumentList
4
- features: :docs
@@ -1,431 +0,0 @@
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
- # tab(view).split view, editor, dir
117
- view.parent.split view, editor, dir
118
- else
119
- if hints[:close_starting_document]
120
- if @tabs.count == 1 and @tabs.widget(0).single_view?
121
- doc_to_close = @tabs.widget(0).view.document
122
- end
123
- end
124
- add_tab editor, doc.icon, doc.document_name
125
- doc_to_close.close if doc_to_close
126
- end
127
- editor.parent.label = label_for_editor editor
128
- end
129
- end
130
- editor
131
- end
132
-
133
- =begin rdoc
134
- Makes the given editor active
135
-
136
- Besides merging the editor's GUI with the main window's, this method also deactivates
137
- the previously active editor, updates the activation order, activates the document
138
- associated with the new active editor, updates the tab where the new editor is
139
- and emits the {#active_editor_changed} signal.
140
-
141
- Nothing is done if the given editor was already active
142
- @param [EditorView] editor the editor to activate
143
- @return [EditorView] the new active editor
144
- =end
145
- def make_editor_active editor
146
- return if editor and @active_editor == editor
147
- deactivate_editor @active_editor
148
- @active_editor = editor
149
- if editor
150
- parent.gui_factory.add_client editor.send(:internal)
151
- @activation_order.delete editor
152
- @activation_order.insert 0, editor
153
- editor_tab = tab(editor)
154
- tab_idx = @tabs.index_of editor_tab
155
- @focus_editors[tab_idx] = editor
156
- update_tab editor_tab
157
- editor.document.activate
158
- end
159
- emit active_editor_changed @active_editor
160
- @active_editor
161
- end
162
-
163
- =begin rdoc
164
- Deactivates the given editor
165
-
166
- To deactivate the editor, its GUI is removed from the main window's and the corresponding
167
- document is deactivated.
168
-
169
- If the given editor wasn't the active one, nothing is done
170
- @param [EditorView] view the editor to deactivate
171
- @return [nil]
172
- =end
173
- def deactivate_editor view
174
- return unless @active_editor and view == @active_editor
175
- @active_editor.document.deactivate
176
- parent.gui_factory.remove_client view.send(:internal)
177
- @active_editor = nil
178
- nil
179
- end
180
-
181
- =begin rdoc
182
- Executes a block without automatically activating editors
183
-
184
- Usually, whenever a tab becomes active, one of the editors it contains becomes
185
- active. Sometimes, you don't want this to happen (for example, when opening multiple
186
- documents in sequence). To do so, do what you need from a block passed to this method.
187
-
188
- After the block has been executed, the last activated method in the current tab
189
- becomes active.
190
-
191
- @yield the block to call without automatically activating editors
192
- @return [Object] the value returned by the block
193
- =end
194
- def without_activating
195
- begin
196
- @auto_activate_editors = false
197
- yield
198
- ensure
199
- @auto_activate_editors = true
200
- if @tabs.current_index < 0 then make_editor_active nil
201
- else make_editor_active @focus_editors[@tabs.current_index]
202
- end
203
- end
204
- end
205
-
206
- =begin rdoc
207
- The toplevel pane corresponding to the given index or widget
208
-
209
- @overload tab idx
210
- @param [Integer] idx the index of the tab
211
- @return [Pane] the toplevel pane in the tab number _idx_
212
- @overload tab editor
213
- @param [EditorView] editor the editor to retrieve the pane for
214
- @return [Pane,nil] the toplevel pane containing the given editor or *nil* if the
215
- view isn't contained in a pane
216
- @overload tab pane
217
- @param [Pane] pane the pane to retrieve the toplevel pane for
218
- @return [Pane, nil] the toplevel pane containing the given pane or *nil* if the
219
- pane isn't contained in another pane
220
- =end
221
- def tab arg
222
- if arg.is_a? Integer then @tabs.widget arg
223
- else
224
- pane = arg.is_a?(Pane) ? arg : arg.parent
225
- return unless pane
226
- pane = pane.parent_pane while pane.parent_pane
227
- pane
228
- end
229
- end
230
-
231
- =begin rdoc
232
- Whether the given view is a focus editor
233
-
234
- @overload focus_editor? editor
235
- Whether the given view is the focus editor for any tab
236
- @param [EditorView] editor the view to test
237
- @return [Boolean] *true* if there's a tab which has _editor_ as focus editor and
238
- *false* otherwise
239
- @overload focus_editor? editor, tab
240
- Whether the given view is the focus editor for the given tab
241
- @param [EditorView] editor the view to test
242
- @param [Pane,Integer] tab the tab the view must be focus editor for. If a {Pane}
243
- it must be the toplevel pane of the tab; if an @Integer@, it must be the index
244
- of the pane to test
245
- @note this method doesn't test whether _tab_ actually is a toplevel pane
246
- @return [Boolean] *true* if _editor_ is the focus widget for _tab_ and
247
- *false* otherwise
248
- =end
249
- def focus_editor? editor, tab = nil
250
- if tab
251
- tab = @tabs.index_of(tab) unless tab.is_a? Integer
252
- @focus_editors[tab] == editor
253
- else @focus_editors.any?{|k, v| v == editor}
254
- end
255
- end
256
-
257
- =begin rdoc
258
- The label to use for an editor
259
-
260
- @param [EditorView] ed the editor to return the label for
261
- @return [String] the text to show below the given editor
262
- =end
263
- def label_for_editor ed
264
- url = ed.document.url
265
- if url.valid? then url.local_file? ? url.path : url.pretty_url
266
- else ed.document.document_name
267
- end
268
- end
269
-
270
- private
271
-
272
- =begin rdoc
273
- Creates an editor for a document
274
-
275
- @param [Document] doc the document to create the editor for
276
- @return [EditorView] the new editor for the document
277
- =end
278
- def create_editor doc
279
- editor = doc.create_view
280
- connect editor, SIGNAL('focus_in(QWidget*)'), self, SLOT('focus_in_view(QWidget*)')
281
- connect editor, SIGNAL('closing(QWidget*)'), self, SLOT('view_closing(QWidget*)')
282
- editor
283
- end
284
-
285
- =begin rdoc
286
- Adds a new tab to the tab widget
287
-
288
- The tab is created with a view inserted in it and is assigned an icon an a label
289
- @param [EditorView] view the view to insert in the new pane
290
- @param [Qt::Icon] icon the icon to associate with the new tab
291
- @param [String] label the label to use for the new tab
292
- @return [Pane] the pane corresponding to the new tab
293
- =end
294
- def add_tab view, icon, label
295
- new_tab = Pane.new(view)
296
- idx = @tabs.add_tab new_tab, icon, label
297
- @focus_editors[idx] = view
298
- connect new_tab, SIGNAL('closing_last_view(QWidget*)'), self, SLOT('remove_tab(QWidget*)')
299
- connect new_tab, SIGNAL('pane_split(QWidget*, QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
300
- connect new_tab, SIGNAL('removing_view(QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
301
- connect new_tab, SIGNAL('view_replaced(QWidget*, QWidget*, QWidget*)'), self, SLOT('update_tab(QWidget*)')
302
- new_tab
303
- end
304
-
305
- =begin rdoc
306
- Removes the tab corresponding to the given toplevel pane
307
-
308
- @param [Pane] pane the toplevel pane whose tab should be removed
309
- @return [nil]
310
- =end
311
- def remove_tab pane
312
- idx = @tabs.index_of pane
313
- if idx
314
- @focus_editors.delete_at idx
315
- @tabs.remove_tab idx
316
- end
317
- nil
318
- end
319
- slots 'remove_tab(QWidget*)'
320
-
321
- =begin rdoc
322
- Slot called whenever a view receives focus
323
-
324
- The views is activated, unless it was already active
325
- @param [EditorView] view the view which received focus
326
- @return [nil]
327
- =end
328
- def focus_in_view view
329
- if view != @active_editor
330
- make_editor_active view
331
- end
332
- nil
333
- end
334
- slots 'focus_in_view(QWidget*)'
335
-
336
- =begin rdoc
337
- Slot called whenever a view is closed
338
-
339
- It deactivates the view (if it was active), performs some cleanup and gives focus
340
- to the editor which had focus before (if any).
341
- @param [EditorView] view the view which is being closed
342
- @return [nil]
343
- =end
344
- def view_closing view
345
- view_tab = self.tab(view)
346
- has_focus = view_tab.is_active_window if view_tab
347
- if has_focus
348
- views = view_tab.to_a
349
- idx = views.index(view)
350
- new_view = views[idx-1] || views[idx+1]
351
- end
352
- @activation_order.delete view
353
- disconnect view, SIGNAL('focus_in(QWidget*)'), self, SLOT('focus_in_view(QWidget*)')
354
- deactivate_editor view
355
- if new_view
356
- make_editor_active new_view
357
- new_view.set_focus
358
- end
359
- nil
360
- end
361
- slots 'view_closing(QWidget*)'
362
-
363
- =begin rdoc
364
- Slot called whenever the current tab changes
365
-
366
- Unless called from within a {#without_activating} block, it activates and gives focus
367
- to the view in the new current tab which last got focus.
368
-
369
- If called from within a {#without_activating} block, or if there's no current tab,
370
- all editors are deactivated
371
- @param [Integer] idx the index of the current tab
372
- @return [nil]
373
- =end
374
- def current_tab_changed idx
375
- if idx > -1
376
- @focus_editors[idx] ||= @tabs.widget(idx).to_a[0]
377
- ed = @focus_editors[idx]
378
- if @auto_activate_editors then ed.set_focus
379
- else make_editor_active nil
380
- end
381
- else
382
- make_editor_active nil
383
- end
384
- nil
385
- end
386
- slots 'current_tab_changed(int)'
387
-
388
- =begin rdoc
389
- Updates the tab containing the given toplevel pane
390
-
391
- Updating the tab means changing its icon, its label, its tooltip and the label
392
- associated with each of the editors it contains
393
- @param [Pane] pane the toplevel pane contained in the pane to update
394
- @return [nil]
395
- =end
396
- def update_tab pane
397
- idx = @tabs.index_of tab(pane)
398
- return if idx < 0
399
- doc = @focus_editors[idx].document
400
- @tabs.set_tab_text idx, doc.document_name
401
- @tabs.set_tab_icon idx, doc.icon
402
- pane.each_pane{|pn| pn.label = label_for_editor(pn.view) if pn.single_view?}
403
- update_tool_tip idx
404
- nil
405
- end
406
- slots 'update_tab(QWidget*)'
407
-
408
- =begin rdoc
409
- Updates the tooltip for the given tab
410
-
411
- A pane's tooltip contains the list of the documents associated with the views in
412
- the tab, separated by newlines.
413
-
414
- @param [Integer] idx the index of the tab whose tooltip should be updated
415
- @param [Array<EditorView>] ignore a list of views which shouldn't be considered
416
- when creating the tool tip. This is necessary because, when a view is closed,
417
- this method is called _before_ the view is removed from the pane, so the document
418
- associated with it would be included in the tooltip if it weren't specified here
419
- @return [nil]
420
- =end
421
- def update_tool_tip idx, *ignore
422
- docs = @tabs.widget(idx).reject{|v| ignore.include? v}.map{|v| v.document.document_name}.uniq
423
- @tabs.set_tab_tool_tip idx, docs.join("\n")
424
- nil
425
- end
426
-
427
- end
428
-
429
- end
430
-
431
- end
@@ -1,11 +0,0 @@
1
- name: projects
2
- require: [project_list, project_files_widget, project_files_list]
3
- class: Ruber::ProjectList
4
- project_options:
5
- general:
6
- project_files: {default: {:include: [], :exclude: [], :extensions: ["*.rb"]}}
7
- open_documents: {default: [], type: session, scope: [global, document]}
8
- project_widgets:
9
- - {class: Ruber::ProjectFilesWidget, caption: 'General', pixmap: configure}
10
- extensions:
11
- project_files: {class: ProjectFilesList}
@@ -1,314 +0,0 @@
1
- =begin
2
- Copyright (C) 2010 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/project'
22
- require 'ruber/plugin_like'
23
-
24
- module Ruber
25
-
26
- =begin rdoc
27
- The current project
28
-
29
- @return [Ruber::Project,nil] the current project or *nil* if no project is open
30
- =end
31
- def self.current_project
32
- self[:projects].current_project
33
- end
34
-
35
- =begin rdoc
36
- List of all open global projects
37
-
38
- It allows to obtain a list of the open projects, to know when a project is
39
- closed and keeps trace of which is the current project. The most common usage
40
- is the following:
41
- * use the {#project} method to retrieve an open project basing on the name of
42
- its file, or to open it if it isn't already open, or to create a new project.
43
- This will also cause the project to be added to the list of open projects,
44
- if needed
45
- * use {#current_project=} to set the current project
46
- * use one of the methods to iterate or work with one of the projects
47
- * close one of the projects with the project's {Project#close close} method, or use the
48
- {#close_current_project} method to close the current project.
49
- =end
50
- class ProjectList < Qt::Object
51
-
52
- include PluginLike
53
-
54
- include Enumerable
55
-
56
- =begin rdoc
57
- Signal emitted when the current project changes
58
-
59
- @param [Ruber::Project,nil] prj the new current project, or *nil* if there's no open
60
- project
61
- =end
62
- signals 'current_project_changed(QObject*)'
63
-
64
- =begin rdoc
65
- Signal emitted just before a project is closed
66
-
67
- @param [Ruber::Project] prj the project which is being closed
68
- =end
69
- signals 'closing_project(QObject*)'
70
-
71
- =begin rdoc
72
- Signal emitted whenever a project is added
73
-
74
- @param [Ruber::Project] prj the newly added project
75
- =end
76
- signals 'project_added(QObject*)'
77
-
78
- slots 'add_project(QObject*)', 'close_project(QObject*)', 'load_settings()'
79
-
80
- =begin rdoc
81
- @return [Ruber::Project,nil] the current project or *nil* if there's no open project
82
- =end
83
- attr_reader :current_project
84
- alias_method :current, :current_project
85
-
86
- =begin rdoc
87
- @param [Ruber::ComponentManager] _manager (unused)
88
- @param [Ruber::PluginSpecification] psf the plugin specification object describing
89
- the component
90
- =end
91
- def initialize _manager, psf
92
- super Ruber[:app]
93
- initialize_plugin psf
94
- @current_project = nil
95
- @projects = {}
96
- end
97
-
98
- =begin rdoc
99
- Iterates on all the projects
100
-
101
- In both versions of the method, the order in which the projects are passed to the block is arbitrary
102
-
103
- @overload each_project
104
- Passes each open project to the block in turn
105
-
106
- @yield [prj] one of the projects
107
- @return [Ruber::ProjectList] *self*
108
- @overload each_project
109
- @return [Enumerator] an enumerator whose @each@ method yields all the projects
110
- in turn
111
- =end
112
- def each_project &blk #:yields: project
113
- res = @projects.each_value &blk
114
- res.same?(@projects) ? self : res
115
- end
116
- alias each each_project
117
-
118
- =begin rdoc
119
- The existing projects
120
-
121
- @return [Array<Ruber::Project>] the existing projects. Modifying the array
122
- wont affect the @ProjectList@
123
- =end
124
- def projects
125
- @projects.values
126
- end
127
-
128
- =begin rdoc
129
- Returns the project associated with a project file, opening it if necessary
130
-
131
- This is one of the core methods of this class. It searchs the list of open projects
132
- and return the one corresponding to the given project file. If a project for that
133
- file isn't open, it will be opened and added to the list of open projects.
134
-
135
- If, for any reason, you create a project using @Project.new@ instead of
136
- using this method, you'll need to add it to the project list yourself using
137
- {#add_project}.
138
-
139
- @param [String] file the absolute path of the project file
140
- @return [Ruber::Project] the project corresponding to the project file _file_
141
- @raise an error deriving from @SystemCallError@ if the project file doesn't exist
142
- or can't be opened
143
- @raise {Ruber::AbstractProject::InvalidProjectFile} if _file_ isn't a valid project file
144
- =end
145
- def project file
146
- @projects[file] || add_project(Project.new(file))
147
- end
148
-
149
- =begin rdoc
150
- Returns the project corresponding to a given file or with a given name
151
-
152
- @overload [] name
153
- Returns the project with the given name
154
- @param [String] name the name of the project. It *must not* start with a slash (@/@)
155
- @return [Ruber::Project,nil] the project with name _name_ or *nil* if no open
156
- project with that name exists. If more than one project with that name exist,
157
- which will be returned is arbitrary
158
- @overload [] file
159
- Returns the project corresponding to the given project file
160
- @param [String] file the absolute path of the project file
161
- @return [Ruber::Project,nil] the project corresponding to the project file _file_
162
- or *nil* if no open projects correspond to that file. Note that, unlike {#project},
163
- this method doesn't attempt to open the project corresponding to _file_ if it
164
- isn't already open
165
- =end
166
- def [] arg
167
- if arg[0,1] == '/' then @projects[arg]
168
- else
169
- find{|prj| prj.project_name == arg}
170
- end
171
- end
172
-
173
- =begin rdoc
174
- Creates a new empty project
175
-
176
- After being created, the new project is added to the list. You almost always should
177
- use this method, rather than calling {AbstractProject.new} to create a new empty
178
- project.
179
-
180
- @param [String] file the absolue path of the project file to associate with the
181
- new project
182
- @param [String] name the name of the new project
183
- @return [Ruber::Project] the new project
184
- @raise @RuntimeError@ if a file corresponding to the path _file_ already exists
185
- =end
186
- def new_project file, name
187
- add_project Project.new( file, name )
188
- end
189
-
190
- =begin rdoc
191
- Makes a project active
192
-
193
- The previously active project is deactivated, while the new one (unless *nil*)
194
- will be activated (calling respectively the the projects' @deactivate@ and @activate@
195
- methods)
196
-
197
- @param [Ruber::Project,nil] prj the project to make current. If *nil*, the current
198
- project will be deactivated, but no other project will become current
199
- @raise @ArgumentError@ if _prj_ is not included in the project list
200
- =end
201
- def current_project= prj
202
- if prj and !@projects[prj.project_file]
203
- raise ArgumentError, "Tried to set an unknown project as current project"
204
- end
205
- @current_project.deactivate if @current_project
206
- @current_project = prj
207
- emit current_project_changed prj
208
- @current_project.activate if @current_project
209
- end
210
-
211
- =begin rdoc
212
- Adds a project to the list
213
-
214
- The {#project_added} signal is emitted after adding the project.
215
-
216
- Since this method is automatically called by both {#project} and {#new_project},
217
- you usually don't need to call it, unless you need to create the project using
218
- @Project.new@ rather than using one of the above methods.
219
-
220
- @param [Ruber::Project] prj the project to add
221
- @return [Ruber::Project] the project itself
222
- @raise @RuntimeError@ if a project corresponding to the same file as _prj_ is
223
- already in the list
224
- =end
225
- def add_project prj
226
- if @projects[prj.project_file]
227
- raise "A project with project file #{prj.project_file} is already open"
228
- end
229
- @projects[prj.project_file] = prj
230
- connect prj, SIGNAL('closing(QObject*)'), self, SLOT('close_project(QObject*)')
231
- emit project_added(prj)
232
- prj
233
- end
234
-
235
- =begin rdoc
236
- Closes the current project
237
-
238
- If there's not a current project, nothing is done. Otherwise, it simply calls the
239
- {#close_project} method passing the current project as argument.
240
-
241
- @return [nil]
242
- =end
243
- def close_current_project
244
- @current_project.close if @current_project
245
- nil
246
- end
247
-
248
- =begin rdoc
249
-
250
- Closes a project
251
-
252
- If the project is current, sets the current project to *nil* before closing it.
253
- In all cases, emits the {#closing_project} signal before closing the project.
254
-
255
- @param [Ruber::Project] the project to close
256
- @return [nil]
257
- =end
258
- def close_project prj
259
- self.current_project = nil if @current_project == prj
260
- emit closing_project(prj)
261
- @projects.delete prj.project_file
262
- nil
263
- end
264
-
265
-
266
- =begin rdoc
267
- Saves each open project
268
-
269
- @return [nil]
270
- =end
271
- def save_settings
272
- @projects.values.each{|pr| pr.save}
273
- nil
274
- end
275
-
276
- =begin rdoc
277
- Tells whether it's all right for the projects to close the application
278
-
279
- It calls the @query_close@ method for each project, returning *false* if any of
280
- them returns *false* and *true* if all return *true*
281
-
282
- @return [Boolean] *true* if it's all right for the projects to close the application
283
- and *false* if at least one of them say the application can't be closed
284
- =end
285
- def query_close
286
- @projects.values.each{|pr| return false unless pr.query_close}
287
- true
288
- end
289
-
290
- =begin rdoc
291
- Returns the project associated with a given project file
292
-
293
- @param [String] file the path of the project file
294
- @param [Symbol] which if @:active_only@, the project corresponding to _file_ will
295
- be returned only if it's active. If it is @:all@ then it will be returned even if
296
- it's inactive. Any other value will cause this method to always return *nil*
297
- @return [Ruber::Project,nil] the project associated with the file _file_ or *nil*
298
- if the list doesn't contain any such file or if it doesn't respect the value of
299
- _which_.
300
- =end
301
- def project_for_file file, which = :active_only
302
- current_prj = current
303
- return nil unless current_prj
304
- if current_prj.project_files.file_in_project?(file) then current_prj
305
- elsif which == :all
306
- find{|prj| prj.project_files.file_in_project?(file)}
307
- else nil
308
- end
309
- end
310
-
311
-
312
- end
313
-
314
- end