ruber 0.0.8 → 0.0.9

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