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
@@ -0,0 +1,1900 @@
1
+ require 'spec/framework'
2
+ require 'spec/common'
3
+
4
+ require 'ruber/world/environment'
5
+
6
+ require 'tmpdir'
7
+
8
+ describe Ruber::World::Environment do
9
+
10
+ before(:all) do
11
+ #the following line is only needed until world is added to the list of
12
+ #components loaded by the application
13
+ Ruber[:components].load_component 'world' unless Ruber[:world]
14
+ end
15
+
16
+ before do
17
+ Ruber[:world].close_all(:documents, :discard)
18
+ @env = Ruber::World::Environment.new nil
19
+ #without this, the tab widgets become visible, slowing down tests noticeably
20
+ flexmock(@env.tab_widget).should_receive(:show).by_default
21
+ @env.activate
22
+ end
23
+
24
+ after do
25
+ @env.dispose
26
+ end
27
+
28
+ it 'inherits from Qt::Object' do
29
+ Ruber::World::Environment.ancestors.should include(Qt::Object)
30
+ end
31
+
32
+ it 'includes the Activable module' do
33
+ Ruber::World::Environment.ancestors.should include(Ruber::Activable)
34
+ end
35
+
36
+ it 'has a plugin instance method' do
37
+ Ruber::World::Environment.instance_methods.should include(:plugin)
38
+ end
39
+
40
+ it 'has a save_settings method' do
41
+ Ruber::World::Environment.instance_methods.should include(:save_settings)
42
+ end
43
+
44
+ it 'has a shutdown method' do
45
+ Ruber::World::Environment.instance_methods.should include(:shutdown)
46
+ end
47
+
48
+ shared_examples_for 'when adding a view' do
49
+
50
+ before do
51
+ @doc = Ruber[:world].new_document
52
+ @view = @doc.create_view
53
+ end
54
+
55
+ it 'inserts the view in the list of views contained in the environment' do
56
+ @add_view_proc.call @view
57
+ @env.views.should include(@view)
58
+ end
59
+
60
+ it 'adds the document to the list of documents associated with the environment' do
61
+ @add_view_proc.call @view
62
+ @env.documents.should include(@view.document)
63
+ end
64
+
65
+ it 'doesn\'t add the document to the list if the list already includes it' do
66
+ @env.editor_for! @doc
67
+ @add_view_proc.call @view
68
+ @env.documents.select{|doc| doc == @doc}.count.should == 1
69
+ end
70
+
71
+ it 'sets the text of the label associated with the view to the path of the document, if the document is associated with a file' do
72
+ @doc = Ruber[:world].document __FILE__
73
+ @view = @doc.create_view
74
+ @add_view_proc.call @view
75
+ @view.parent.label.should == @doc.path
76
+ end
77
+
78
+ it 'sets the text of the label associated with the view to the documen name of the document, if the document is associated with a file' do
79
+ @add_view_proc.call @view
80
+ @view.parent.label.should == @doc.document_name
81
+ end
82
+
83
+ it 'uses the URL of the document as label for the view if the document is associated with a remote file' do
84
+ url = KDE::Url.new 'http://xyz.org/abc'
85
+ flexmock(@doc).should_receive(:url).and_return url
86
+ @add_view_proc.call @view
87
+ @view.parent.label.should == @doc.url.pretty_url
88
+ end
89
+
90
+ it 'updates the tool tip of the tab containing the view' do
91
+ doc = Ruber[:world].new_document
92
+ @add_view_proc.call @view
93
+ @env.editor_for! doc, :new => @view
94
+ exp = @doc.document_name + "\n" + doc.document_name
95
+ @env.tab_widget.tab_tool_tip(0).should == exp
96
+ end
97
+
98
+ it 'doesn\'t repeat a document multiple times in the tool tip of the tab' do
99
+ Ruber[:world].close_all :documents, :discard
100
+ doc = Ruber[:world].new_document
101
+ view = @env.editor_for! doc, :new => :current_tab
102
+ @add_view_proc.call @view
103
+ @env.editor_for! @doc, :existing => :never, :new => :current_tab
104
+ exp = [doc, @doc].map{|d| d.document_name}.join "\n"
105
+ @env.tab_widget.tab_tool_tip(0).should == exp
106
+ end
107
+
108
+ it 'reacts to the view getting focus' do
109
+ @add_view_proc.call @view
110
+ @view.instance_eval{emit focus_in(self)}
111
+ @env.active_editor.should == @view
112
+ end
113
+
114
+ end
115
+
116
+ describe '.new' do
117
+
118
+ context 'when the first argument is a Project' do
119
+
120
+ before do
121
+ @file = File.join Dir.tmpdir, 'environment_new_test'
122
+ @project = Ruber::Project.new @file, "Environment New Test"
123
+ end
124
+
125
+ it 'makes the new environment child of the second argument' do
126
+ obj = Qt::Object.new
127
+ env = Ruber::World::Environment.new @project, obj
128
+ env.parent.should == obj
129
+ end
130
+
131
+ it 'doesn\'t create empty documents' do
132
+ env = Ruber::World::Environment.new @project
133
+ env.views.should be_empty
134
+ end
135
+
136
+ end
137
+
138
+ context 'when the first argument is nil' do
139
+
140
+ it 'makes the new enviroment child of the second argument' do
141
+ obj = Qt::Object.new
142
+ env = Ruber::World::Environment.new nil, obj
143
+ env.parent.should == obj
144
+ end
145
+
146
+ it 'creates an environment having no project associated with it' do
147
+ env = Ruber::World::Environment.new nil
148
+ env.project.should be_nil
149
+ end
150
+
151
+ end
152
+
153
+ it 'associates a parentless tab widget with the environment' do
154
+ env = Ruber::World::Environment.new nil
155
+ env.tab_widget.should be_a(KDE::TabWidget)
156
+ env.tab_widget.parent.should be_nil
157
+ end
158
+
159
+ it 'swtiches the document mode of the tab widget on' do
160
+ env = Ruber::World::Environment.new nil
161
+ env.tab_widget.document_mode.should be_true
162
+ end
163
+
164
+ it 'creates an hint solver' do
165
+ env = Ruber::World::Environment.new nil
166
+ hint_solver = env.instance_variable_get(:@hint_solver)
167
+ hint_solver.should be_a(Ruber::World::HintSolver)
168
+ end
169
+
170
+ it 'deactivates the environment' do
171
+ env = Ruber::World::Environment.new nil
172
+ env.should_not be_active
173
+ end
174
+
175
+ it 'hides the tab widget' do
176
+ env = Ruber::World::Environment.new nil
177
+ env.tab_widget.should be_hidden
178
+ end
179
+
180
+ it 'creates a view for a new, empty document with object name default_document' do
181
+ env = Ruber::World::Environment.new nil
182
+ env.views.count.should == 1
183
+ env.views[0].document.text.should == ''
184
+ env.views[0].document.object_name.should == 'default_document'
185
+ end
186
+
187
+ end
188
+
189
+ describe '#editor_for!' do
190
+
191
+ before do
192
+ @solver = @env.instance_variable_get :@hint_solver
193
+ end
194
+
195
+ it 'uses the Ruber::World::Environment::DEFAULT_HINTS as default hints argument' do
196
+ doc = Ruber[:world].new_document
197
+ view = doc.create_view
198
+ flexmock(@solver).should_receive(:find_editor).with(doc, Ruber::World::Environment::DEFAULT_HINTS).once.and_return(view)
199
+ @env.editor_for!(doc)
200
+ end
201
+
202
+ it 'merges the given hints with the default ones' do
203
+ doc = Ruber[:world].new_document
204
+ view = doc.create_view
205
+ exp_hints = Ruber::World::Environment::DEFAULT_HINTS.merge(:create_if_needed => false)
206
+ flexmock(@solver).should_receive(:find_editor).with(doc, exp_hints).once.and_return(view)
207
+ @env.editor_for!(doc, :create_if_needed => false)
208
+ end
209
+
210
+ it 'closes the default document if it\'s pristine' do
211
+ @env.editor_for! __FILE__
212
+ Ruber[:world].documents.find{|d| d.object_name == 'default_document'}.should be_nil
213
+ end
214
+
215
+ it 'doesn\'t close the default environment if the first argument is the default document itself' do
216
+ @env.editor_for! Ruber[:world].documents.find{|d| d.object_name == "default_document"}
217
+ Ruber[:world].documents.find{|d| d.object_name == "default_document"}.should_not be_nil
218
+ end
219
+
220
+ it 'doesn\'t close the default document if it is not pristine' do
221
+ flexmock(@env.documents[0]).should_receive(:pristine?).and_return false
222
+ @env.editor_for! __FILE__
223
+ Ruber[:world].documents.find{|d| d.object_name == 'default_document'}.should_not be_nil
224
+ end
225
+
226
+ it 'doesn\'t close the default document if it has no view associated with it' do
227
+ default_doc = Ruber[:world].documents.find{|d| d.object_name == 'default_document'}
228
+ default_doc.views[0].close
229
+ @env.editor_for! __FILE__
230
+ Ruber[:world].documents.should include(default_doc)
231
+ end
232
+
233
+ it 'doesn\'t close the default document if it has more than one view associated with it' do
234
+ default_doc = Ruber[:world].documents.find{|d| d.object_name == 'default_document'}
235
+ default_doc.create_view
236
+ @env.editor_for! __FILE__
237
+ Ruber[:world].documents.should include(default_doc)
238
+ end
239
+
240
+ context 'when the first argument is a document' do
241
+
242
+ before do
243
+ @doc = Ruber[:world].new_document
244
+ end
245
+
246
+ context 'when the tab widget contains an editor for the given document matching the given hints' do
247
+
248
+ it 'returns that editor' do
249
+ view = @doc.create_view
250
+ flexmock(@solver).should_receive(:find_editor).with(@doc, Hash).once.and_return(view)
251
+ @env.editor_for!(@doc, {}).should == view
252
+ end
253
+
254
+ end
255
+
256
+ context 'when the tab widget does not contain an editor for the given document matching the given hints' do
257
+
258
+ context 'if the create_if_needed hint is false' do
259
+
260
+ it 'returns nil' do
261
+ flexmock(@solver).should_receive(:find_editor).with(@doc, Hash).and_return nil
262
+ @env.editor_for!(@doc, {:create_if_needed => false}).should be_nil
263
+ end
264
+
265
+ end
266
+
267
+ context 'if the create_if_needed hint is true' do
268
+
269
+ before do
270
+ @add_view_proc = lambda do |view|
271
+ flexmock(view.document).should_receive(:create_view).and_return view
272
+ @env.editor_for! view.document, :existing => :never, :new => :new_tab
273
+ end
274
+ end
275
+
276
+ it 'creates and returns a new editor' do
277
+ @env.editor_for!(@doc, :create_if_needed => true).should be_a(Ruber::EditorView)
278
+ end
279
+
280
+ it 'places the new editor in the position returned by the hint solver #place_editor method if it is not nil' do
281
+ old_editor = @doc.create_view
282
+ pane = @env.send :create_tab, old_editor
283
+ @env.send :add_editor, old_editor, pane
284
+ # pane = Ruber::Pane.new old_editor
285
+ tabs = @env.tab_widget
286
+ tabs.add_tab pane, 'Tab'
287
+ tabs.current_index = 0
288
+ editor = @env.editor_for! @doc, {:existing => :never, :create_if_needed => true, :new => :current_tab}
289
+ pane.splitter.widget(1).view.should == editor
290
+ end
291
+
292
+ it 'respects the :split hint' do
293
+ old_editor = @doc.create_view
294
+ pane = @env.send :create_tab, old_editor
295
+ @env.send :add_editor, old_editor, pane
296
+ tabs = @env.tab_widget
297
+ tabs.add_tab pane, 'Tab'
298
+ tabs.current_index = 0
299
+ editor = @env.editor_for! @doc, {:existing => :never, :create_if_needed => true, :new => :current_tab, :split => :vertical}
300
+ pane.splitter.orientation.should == Qt::Vertical
301
+ end
302
+
303
+ it 'places the new editor in a new tab if the hint solver\'s #place_editor method returns nil' do
304
+ old_editor = @doc.create_view
305
+ pane = @env.send :create_tab, old_editor
306
+ @env.send :add_editor, old_editor, pane
307
+ tabs = @env.tab_widget
308
+ tabs.add_tab pane, 'Tab'
309
+ tabs.current_index = 0
310
+ editor = @env.editor_for! @doc, {:existing => :never, :create_if_needed => true, :new => :newt_tab}
311
+ new_pane = tabs.widget(1)
312
+ new_pane.view.should == editor
313
+ end
314
+
315
+ it 'uses the document name as tab\'s caption when placing the editor in a new tab' do
316
+ editor = @env.editor_for! @doc, {:existing => :never, :create_if_needed => true, :new => :newt_tab}
317
+ @env.tab_widget.tab_text(0).should == @doc.document_name
318
+ end
319
+
320
+ it 'uses the document icon as tab\'s icon when placing the editor in a new tab' do
321
+ doc = Ruber[:world].document __FILE__
322
+ editor = @env.editor_for! @doc, {:existing => :never, :create_if_needed => true, :new => :newt_tab}
323
+ exp_image = @doc.icon.pixmap(Qt::Size.new(16,16)).to_image
324
+ @env.tab_widget.tab_icon(0).pixmap(Qt::Size.new(16,16)).to_image.should == exp_image
325
+ end
326
+
327
+ it_behaves_like 'when adding a view'
328
+
329
+ end
330
+
331
+ end
332
+
333
+ end
334
+
335
+ context 'when the first argument is a string' do
336
+
337
+ after do
338
+ @doc.close if @doc
339
+ end
340
+
341
+ context 'and the world contains a document associated with the given file' do
342
+
343
+ it 'returns an editor for the document' do
344
+ @doc = Ruber[:world].document __FILE__
345
+ editor = @env.editor_for! __FILE__
346
+ editor.document.path.should == __FILE__
347
+ end
348
+
349
+ it 'doesn\'t create a new document' do
350
+ @doc = Ruber[:world].document __FILE__
351
+ editor = @env.editor_for! __FILE__
352
+ editor.document.should == @doc
353
+ end
354
+
355
+ end
356
+
357
+ context 'and the world doesn\'t contain a document associated with the given file' do
358
+
359
+ it 'returns an editor for the document' do
360
+ editor = @env.editor_for! __FILE__
361
+ editor.document.path.should == __FILE__
362
+ @doc = editor.document
363
+ end
364
+
365
+ end
366
+
367
+ end
368
+
369
+ context 'when the first argument is an URL' do
370
+
371
+ after do
372
+ @doc.close if @doc
373
+ end
374
+
375
+ context 'and the world contains a document associated with the given file' do
376
+
377
+ it 'returns an editor for the document' do
378
+ @doc = Ruber[:world].document __FILE__
379
+ editor = @env.editor_for! KDE::Url.new(__FILE__)
380
+ editor.document.path.should == __FILE__
381
+ end
382
+
383
+ it 'doesn\'t create a new document' do
384
+ @doc = Ruber[:world].document __FILE__
385
+ editor = @env.editor_for! KDE::Url.new(__FILE__)
386
+ editor.document.should == @doc
387
+ end
388
+
389
+ end
390
+
391
+ context 'and the world doesn\'t contain a document associated with the given file' do
392
+
393
+ it 'returns an editor for the document' do
394
+ editor = @env.editor_for! KDE::Url.new(__FILE__)
395
+ editor.document.path.should == __FILE__
396
+ @doc = editor.document
397
+ end
398
+
399
+ end
400
+
401
+ end
402
+
403
+ end
404
+
405
+ describe '#tab' do
406
+
407
+ before do
408
+ @views = [
409
+ @env.editor_for!(__FILE__),
410
+ @env.editor_for!(__FILE__, :existing => :never, :new => :current_tab),
411
+ @env.editor_for!(__FILE__, :existing => :never, :new => :new_tab)
412
+ ]
413
+ end
414
+
415
+ context 'when the argument is a Pane' do
416
+
417
+ it 'returns the toplevel pane containing the argument' do
418
+ view = @env.editor_for! __FILE__, :existing => :never, :new => @views[1],
419
+ :split => :vertical
420
+ pane = view.parent
421
+ @env.tab(pane).should == @env.tab_widget.widget(0)
422
+ end
423
+
424
+ it 'returns the pane itself if it is a toplevel pane' do
425
+ toplevel = @views[2].parent
426
+ @env.tab(toplevel).should == toplevel
427
+ end
428
+
429
+ it 'returns nil if the toplevel pane doesn\'t belong to the tab widget associated with the environment' do
430
+ doc = Ruber[:world].document __FILE__
431
+ view = doc.create_view
432
+ pane = Ruber::Pane.new view
433
+ @env.tab(pane).should be_nil
434
+ end
435
+
436
+ end
437
+
438
+ context 'when the argument is a view' do
439
+
440
+ it 'returns the toplevel pane containing the argument' do
441
+ view = @env.editor_for! __FILE__, :existing => :never, :new => @views[1],
442
+ :split => :vertical
443
+ @env.tab(view).should == @env.tab_widget.widget(0)
444
+ end
445
+
446
+ it 'returns the parent of the view if it is a toplevel pane' do
447
+ toplevel = @views[2].parent
448
+ @env.tab(@views[2]).should == toplevel
449
+ end
450
+
451
+ it 'returns nil if the toplevel pane doesn\'t belong to the tab widget associated with the environment' do
452
+ doc = Ruber[:world].document __FILE__
453
+ view = doc.create_view
454
+ pane = Ruber::Pane.new view
455
+ @env.tab(view).should be_nil
456
+ end
457
+
458
+ it 'returns nil if the view isn\'t in a pane' do
459
+ doc = Ruber[:world].document __FILE__
460
+ view = doc.create_view
461
+ @env.tab(view).should be_nil
462
+ end
463
+
464
+ end
465
+
466
+ end
467
+
468
+ describe '#tabs' do
469
+
470
+ it 'returns an array containing all the toplevel tabs contained in the environment in order' do
471
+ doc = Ruber[:world].new_document
472
+ 3.times{@env.editor_for! doc, :existing => :never}
473
+ tab_widget = @env.tab_widget
474
+ @env.tabs.should == 3.times.map{|i| tab_widget.widget i}
475
+ end
476
+
477
+ it 'returns an empty array if there is no tab in the tab widget' do
478
+ @env.documents[0].close false
479
+ @env.tabs.should be_empty
480
+ end
481
+
482
+ end
483
+
484
+ describe '#documents' do
485
+
486
+ before do
487
+ @docs = [Ruber::Document.new, Ruber[:world].document(__FILE__)]
488
+ @env.editor_for! @docs[0]
489
+ @env.editor_for! @docs[1], :existing => :never
490
+ end
491
+
492
+ it 'returns DocumentList' do
493
+ @env.documents.should be_a(Ruber::World::DocumentList)
494
+ end
495
+
496
+ it 'returns a list containing all the documents associated with a view in the environment' do
497
+ @env.documents.should == [@docs[0], @docs[1]]
498
+ end
499
+
500
+ it 'returns a list which doesn\'t contain documents which have been closed' do
501
+ @docs[1].close
502
+ @env.documents.should == [@docs[0]]
503
+ end
504
+
505
+ end
506
+
507
+ describe '#views' do
508
+
509
+ before do
510
+ @docs = 3.times.map{Ruber::Document.new}
511
+ @editors = []
512
+ @editors << @env.editor_for!(@docs[0])
513
+ @editors << @env.editor_for!(@docs[1], :new => :current_tab)
514
+ @editors << @env.editor_for!(@docs[2], :new => :current_tab)
515
+ @editors << @env.editor_for!(@docs[0], :existing => :never, :new => :new_tab)
516
+ @editors << @env.editor_for!(@docs[2], :existing => :never, :new => :new_tab)
517
+ end
518
+
519
+ context 'when called without arguments' do
520
+
521
+ it 'returns a list containing all the views in the environment' do
522
+ @env.views.sort_by{|v| v.object_id}.should == @editors.sort_by{|v| v.object_id}
523
+ end
524
+
525
+ it 'returns a list containing the views in activation order, from most recently activated to
526
+ least recently activated' do
527
+ @env.activate_editor @editors[1]
528
+ @env.activate_editor @editors[4]
529
+ @env.activate_editor @editors[2]
530
+ exp = [@editors[2], @editors[4], @editors[1], @editors[0], @editors[3]]
531
+ @env.views.should == exp
532
+ end
533
+
534
+ it 'returns a list which doesn\'t contain duplicate arguments if a view is created by splitting another one' do
535
+ @env.views.select{|v| v == @editors[1]}.count.should == 1
536
+ end
537
+
538
+ end
539
+
540
+ context 'when called with a document as argument' do
541
+
542
+ it 'returns a list containing all the views in the environment which are associated with the given document' do
543
+ exp = @editors.select{|v| v.document == @docs[0]}.sort_by{|v| v.object_id}
544
+ @env.views(@docs[0]).sort_by{|v| v.object_id}.should == exp
545
+ end
546
+
547
+ it 'returns a list containing the views in activation order, from most recently activated to
548
+ least recently activated' do
549
+ @env.activate_editor @editors[3]
550
+ @env.views(@docs[0]).should == [@editors[3], @editors[0]]
551
+ end
552
+
553
+ end
554
+
555
+ end
556
+
557
+ describe '#activate_editor' do
558
+
559
+ before do
560
+ clients = Ruber[:main_window].gui_factory.clients
561
+ clients.each{|c| Ruber[:main_window].gui_factory.remove_client c unless c.is_a? Ruber::MainWindow}
562
+ @env.activate
563
+ @docs = 3.times.map{Ruber::Document.new}
564
+ @editors = []
565
+ @editors << @env.editor_for!(@docs[0])
566
+ @editors << @env.editor_for!(@docs[1], :new => :current_tab)
567
+ @editors << @env.editor_for!(@docs[2], :new => :current_tab)
568
+ @editors << @env.editor_for!(@docs[0], :existing => :never, :new => :new_tab)
569
+ @editors << @env.editor_for!(@docs[2], :existing => :never, :new => :new_tab)
570
+ end
571
+
572
+ context 'when there\'s no active editor' do
573
+
574
+ it 'merges the editor\'s GUI with the main window\'s' do
575
+ factory = Ruber[:main_window].gui_factory
576
+ #MainWindow#gui_factory returns a different ruby object each time, so
577
+ #we can't set a mock on it.
578
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
579
+ flexmock(factory).should_receive(:add_client).with(@editors[2].send(:internal)).once
580
+ @env.activate_editor @editors[2]
581
+ end
582
+
583
+ it 'marks the view as last activated' do
584
+ @env.activate_editor @editors[4]
585
+ @env.views[0].should == @editors[4]
586
+ @env.activate_editor @editors[2]
587
+ @env.views[0].should == @editors[2]
588
+ end
589
+
590
+ it 'changes the label and icon of the tab to match those of the document corresponding to the activated editor' do
591
+ @env.activate_editor @editors[2]
592
+ @env.tab_widget.tab_text(0).should == @editors[2].document.document_name
593
+ exp_image = @editors[2].document.icon.pixmap(Qt::Size.new(16,16)).to_image
594
+ @env.tab_widget.tab_icon(0).pixmap(Qt::Size.new(16,16)).to_image.should
595
+ end
596
+
597
+ it 'activates the document associated with the activate editor' do
598
+ flexmock(@editors[2].document).should_receive(:activate).once
599
+ @env.activate_editor @editors[2]
600
+ end
601
+
602
+ it 'emits the active_editor_changed signal passing the new active view as argument' do
603
+ test = flexmock{|m| m.should_receive(:active_editor_changed).with(@editors[2]).once}
604
+ @env.connect(SIGNAL('active_editor_changed(QWidget*)')){|w| test.active_editor_changed w}
605
+ @env.activate_editor @editors[2]
606
+ end
607
+
608
+ it 'makes the tab containing the ativated editor current' do
609
+ @env.activate_editor @editors[2]
610
+ @env.tab_widget.current_index.should == 0
611
+ @env.activate_editor @editors[4]
612
+ @env.tab_widget.current_index.should == 2
613
+ end
614
+
615
+ it 'returns the new active editor' do
616
+ @env.activate_editor(@editors[2]).should == @editors[2]
617
+ end
618
+
619
+ it 'does nothing if the argument is nil' do
620
+ factory = Ruber[:main_window].gui_factory
621
+ #MainWindow#gui_factory returns a different ruby object each time, so
622
+ #we can't set a mock on it.
623
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
624
+ flexmock(factory).should_receive(:add_client).never
625
+ flexmock(@editors[2].document).should_receive(:activate).never
626
+ @env.activate_editor nil
627
+ end
628
+
629
+ end
630
+
631
+ context 'when there\'s an active editor' do
632
+
633
+ before do
634
+ @env.activate_editor @editors[3]
635
+ end
636
+
637
+ it 'deactivates the currently active editor' do
638
+ factory = Ruber[:main_window].gui_factory
639
+ #MainWindow#gui_factory returns a different ruby object each time, so
640
+ #we can't set a mock on it.
641
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
642
+ flexmock(factory).should_receive(:remove_client).with(@editors[3].send(:internal)).once
643
+ @env.activate_editor @editors[2]
644
+ end
645
+
646
+ it 'deactivates the document corresponding to the previously active editor' do
647
+ flexmock(@editors[3].document).should_receive(:deactivate).once
648
+ @env.activate_editor @editors[2]
649
+ end
650
+
651
+ it 'merges the editor\'s GUI with the main window\'s' do
652
+ factory = Ruber[:main_window].gui_factory
653
+ #MainWindow#gui_factory returns a different ruby object each time, so
654
+ #we can't set a mock on it.
655
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
656
+ flexmock(factory).should_receive(:add_client).with(@editors[2].send(:internal)).once
657
+ @env.activate_editor @editors[2]
658
+ end
659
+
660
+ it 'marks the view as last activated' do
661
+ @env.activate_editor @editors[4]
662
+ @env.views[0].should == @editors[4]
663
+ @env.activate_editor @editors[2]
664
+ @env.views[0].should == @editors[2]
665
+ end
666
+
667
+ it 'changes the label and icon of the tab to match those of the document corresponding to the activated editor' do
668
+ @env.activate_editor @editors[2]
669
+ @env.tab_widget.tab_text(0).should == @editors[2].document.document_name
670
+ exp_image = @editors[2].document.icon.pixmap(Qt::Size.new(16,16)).to_image
671
+ @env.tab_widget.tab_icon(0).pixmap(Qt::Size.new(16,16)).to_image.should
672
+ end
673
+
674
+ it 'activates the document associated with the activate editor' do
675
+ flexmock(@editors[2].document).should_receive(:activate).once
676
+ @env.activate_editor @editors[2]
677
+ end
678
+
679
+ it 'makes the tab containing the ativated editor current' do
680
+ @env.activate_editor @editors[2]
681
+ @env.tab_widget.current_index.should == 0
682
+ @env.activate_editor @editors[4]
683
+ @env.tab_widget.current_index.should == 2
684
+ end
685
+
686
+ it 'emits the active_editor_changed signal passing the new active view as argument' do
687
+ test = flexmock{|m| m.should_receive(:active_editor_changed).with(@editors[2]).once}
688
+ @env.connect(SIGNAL('active_editor_changed(QWidget*)')){|w| test.active_editor_changed w}
689
+ @env.activate_editor @editors[2]
690
+ end
691
+
692
+ it 'returns the new active editor' do
693
+ @env.activate_editor(@editors[2]).should == @editors[2]
694
+ end
695
+
696
+ it 'does nothing if the given editor was already active' do
697
+ @env.activate_editor @editors[2]
698
+ factory = Ruber[:main_window].gui_factory
699
+ #MainWindow#gui_factory returns a different ruby object each time, so
700
+ #we can't set a mock on it.
701
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
702
+ flexmock(@env).should_receive(:deactivate_editor).never
703
+ flexmock(factory).should_receive(:add_client).never
704
+ flexmock(@editors[3].document).should_receive(:deactivate).never
705
+ flexmock(@editors[2].document).should_receive(:activate).never
706
+ flexmock(@env).should_receive(:emit).never
707
+ @env.activate_editor @editors[2]
708
+ end
709
+
710
+ it 'doesn\'t attempt to merge the argument\'s GUI if the argument is nil' do
711
+ @env.activate_editor @editors[2]
712
+ factory = Ruber[:main_window].gui_factory
713
+ #MainWindow#gui_factory returns a different ruby object each time, so
714
+ #we can't set a mock on it.
715
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
716
+ flexmock(factory).should_receive(:remove_client).with(@editors[2].send(:internal)).once
717
+ flexmock(factory).should_receive(:add_client).never
718
+ flexmock(@editors[2].document).should_receive(:deactivate).once
719
+ mk = flexmock{|m| m.should_receive(:active_editor_changed).once.with(nil)}
720
+ @env.connect(SIGNAL('active_editor_changed(QWidget*)')){|v| mk.active_editor_changed v}
721
+ @env.activate_editor nil
722
+ end
723
+
724
+ end
725
+
726
+ context 'if the environment is not active' do
727
+
728
+ before do
729
+ @env.deactivate
730
+ end
731
+
732
+ it 'doesn\'t attempt to merge the view\'s GUI with the main window\'s' do
733
+ factory = Ruber[:main_window].gui_factory
734
+ #MainWindow#gui_factory returns a different ruby object each time, so
735
+ #we can't set a mock on it.
736
+ flexmock(Ruber[:main_window]).should_receive(:gui_factory).and_return factory
737
+ flexmock(factory).should_receive(:add_client).never
738
+ @env.activate_editor @editors[1]
739
+ end
740
+
741
+ it 'doesn\'t change the active editor' do
742
+ @env.activate_editor @editors[1]
743
+ @env.active_editor.should be_nil
744
+ end
745
+
746
+ it 'marks the view as last activated' do
747
+ @env.activate_editor @editors[2]
748
+ @env.views[0].should == @editors[2]
749
+ end
750
+
751
+ it 'changes the current tab index' do
752
+ @env.tab_widget.current_index = 0
753
+ @env.activate_editor @editors[3]
754
+ @env.tab_widget.current_index.should == 1
755
+ end
756
+
757
+ it 'changes the text and icon of the tab to match those of the editor' do
758
+ @env.tab_widget.set_tab_icon 0, Qt::Icon.new
759
+ @env.tab_widget.set_tab_text 0, "Test"
760
+ @env.activate_editor @editors[1]
761
+ @env.tab_widget.tab_text(0).should == @editors[1].document.document_name
762
+ exp_icon = @editors[1].document.icon.pixmap(Qt::Size.new(16,16)).to_image
763
+ icon = @env.tab_widget.tab_icon(0).pixmap(Qt::Size.new(16,16)).to_image
764
+ exp_icon.should == icon
765
+ end
766
+
767
+ it 'doesn\'t emit the active_editor_changed signal' do
768
+ mk = flexmock{|m| m.should_receive(:active_editor_changed).never}
769
+ @env.connect(SIGNAL('active_editor_changed(QWidget*)')){mk.active_editor_changed}
770
+ @env.activate_editor @editors[3]
771
+ end
772
+
773
+ it 'doesn\'t activate the document associated with the editor' do
774
+ flexmock(@editors[2].document).should_receive(:activate).never
775
+ @env.activate_editor @editors[2]
776
+ end
777
+
778
+ end
779
+
780
+ it 'gives focus to the editor if #focus_on_editors? returns true' do
781
+ flexmock(@env).should_receive(:focus_on_editors?).and_return(true)
782
+ flexmock(@editors[2]).should_receive(:set_focus).once
783
+ @env.activate_editor @editors[2]
784
+ end
785
+
786
+ it 'doesn\'t give focus to the editor if #focus_on_editors? returns false' do
787
+ flexmock(@env).should_receive(:focus_on_editors?).and_return(false)
788
+ flexmock(@editors[2]).should_receive(:set_focus).never
789
+ @env.activate_editor @editors[2]
790
+ end
791
+
792
+ end
793
+
794
+ describe '#deactivate' do
795
+
796
+ before do
797
+ @doc = Ruber[:world].new_document
798
+ @editor = @env.editor_for! @doc
799
+ @env.activate
800
+ end
801
+
802
+ it 'deactivates the active editor if it exists' do
803
+ @env.activate_editor @editor
804
+ flexmock(@env).should_receive(:deactivate_editor).with(@editor).once
805
+ @env.deactivate
806
+ end
807
+
808
+ it 'behaves like Activable#deactivate' do
809
+ mk = flexmock{|m| m.should_receive(:deactivated).once}
810
+ @env.connect(SIGNAL(:deactivated)){mk.deactivated}
811
+ @env.deactivate
812
+ @env.should_not be_active
813
+ end
814
+
815
+ end
816
+
817
+ describe '#activate' do
818
+
819
+ before do
820
+ Ruber[:world].close_all :documents, :discard
821
+ @doc = Ruber[:world].new_document
822
+ @env.activate
823
+ @env.deactivate
824
+ end
825
+
826
+ it 'activates the last activated editor' do
827
+ editors = 3.times.map{@env.editor_for! @doc, :existing => :never}
828
+ @env.activate
829
+ @env.activate_editor editors[1]
830
+ @env.deactivate
831
+ flexmock(@env).should_receive(:activate_editor).with(editors[1]).once
832
+ @env.activate
833
+ end
834
+
835
+ it 'makes all documents inactive if there is no editor in the environment' do
836
+ flexmock(@env).should_receive(:activate_editor).with(nil).once
837
+ @env.activate
838
+ end
839
+
840
+ it 'behaves like Activable#activate' do
841
+ mk = flexmock{|m| m.should_receive(:activated).once}
842
+ @env.connect(SIGNAL(:activated)){mk.activated}
843
+ @env.activate
844
+ @env.should be_active
845
+ end
846
+
847
+ end
848
+
849
+ describe '#active_editor' do
850
+
851
+ context 'if the environment is active' do
852
+
853
+ before do
854
+ Ruber[:world].close_all :documents, :discard
855
+ @env.activate
856
+ end
857
+
858
+ it 'returns nil if there\'s no active editor' do
859
+ @env.active_editor.should be_nil
860
+ end
861
+
862
+ it 'returns the active editor if it exists' do
863
+ doc = Ruber[:world].new_document
864
+ editors = 3.times.map{@env.editor_for! doc, :existing => :never}
865
+ @env.activate_editor editors[1]
866
+ @env.active_editor.should == editors[1]
867
+ end
868
+
869
+ end
870
+
871
+ context 'if the environment is not active' do
872
+
873
+ it 'always returns nil' do
874
+ @env.deactivate
875
+ @env.active_editor.should be_nil
876
+ @env.activate
877
+ doc = Ruber[:world].new_document
878
+ editors = 3.times.map{@env.editor_for! doc, :existing => :never}
879
+ @env.activate_editor editors[1]
880
+ @env.deactivate
881
+ @env.active_editor.should be_nil
882
+ end
883
+
884
+ end
885
+
886
+ end
887
+
888
+ describe '#active_document' do
889
+
890
+ context 'if the environment is active' do
891
+
892
+ before do
893
+ Ruber[:world].close_all :documents, :discard
894
+ @env.activate
895
+ end
896
+
897
+ it 'returns nil if there\'s no active editor' do
898
+ @env.active_document.should be_nil
899
+ end
900
+
901
+ it 'returns the document associated with the active editor if it exists' do
902
+ doc = Ruber[:world].new_document
903
+ editors = 3.times.map{@env.editor_for! doc, :existing => :never}
904
+ @env.activate_editor editors[1]
905
+ @env.active_document.should == editors[1].document
906
+ end
907
+
908
+ end
909
+
910
+ context 'if the environment is not active' do
911
+
912
+ it 'always returns nil' do
913
+ @env.deactivate
914
+ @env.active_document.should be_nil
915
+ @env.activate
916
+ doc = Ruber[:world].new_document
917
+ editors = 3.times.map{@env.editor_for! doc, :existing => :never}
918
+ @env.activate_editor editors[1]
919
+ @env.deactivate
920
+ @env.active_document.should be_nil
921
+ end
922
+
923
+ end
924
+
925
+ end
926
+
927
+ describe 'when the current tab changes' do
928
+
929
+ it 'activates the last active editor in the new tab' do
930
+ doc = Ruber[:world].new_document
931
+ views1 = 2.times.map{@env.editor_for! doc, :existing => :never, :new => :current_tab}
932
+ views2 = 2.times.map{@env.editor_for! doc, :existing => :never, :new => :new_tab}
933
+ @env.activate_editor views2[1]
934
+ @env.activate_editor views1[1]
935
+ @env.activate_editor views2[1]
936
+ @env.tab_widget.current_index = 0
937
+ @env.active_editor.should == views1[1]
938
+ end
939
+
940
+ end
941
+
942
+ describe 'when an editor is closed' do
943
+
944
+ before do
945
+ @doc = Ruber[:world].new_document
946
+ end
947
+
948
+ context 'if the view is the active one' do
949
+
950
+ before do
951
+ @views = @views = 4.times.map{|i| @env.editor_for! @doc, :existing => :never}
952
+ end
953
+
954
+ it 'deactivates it' do
955
+ @env.activate_editor @views[2]
956
+ @env.activate_editor @views[3]
957
+ @env.activate_editor @views[0]
958
+ @env.activate_editor @views[1]
959
+ @views[1].close
960
+ @env.active_editor.should_not == @views[1]
961
+ end
962
+
963
+ end
964
+
965
+ context 'if there are other editors in the same tab' do
966
+
967
+ before do
968
+ @views = 4.times.map{|i| @env.editor_for! @doc, :existing => :never, :new => (i == 3 ? :new_tab : :current_tab) }
969
+ end
970
+
971
+ it 'removes the view from the tab' do
972
+ pane = @env.tab_widget.widget 0
973
+ @views[1].close
974
+ pane.should_not include(@views[1])
975
+ end
976
+
977
+ it 'activates the previously activated view in the same tab if the view was active' do
978
+ @env.activate_editor @views[2]
979
+ @env.activate_editor @views[1]
980
+ @views[1].close
981
+ @env.active_editor.should == @views[2]
982
+ end
983
+
984
+ it 'gives focus to view which previously had focus in the same tab, if the closed view was active and focus_on_editors? returns true' do
985
+ flexmock(@env).should_receive(:focus_on_editor?).and_return true
986
+ @env.activate_editor @views[2]
987
+ @env.activate_editor @views[1]
988
+ @views[2].instance_eval{emit focus_in(self)}
989
+ @views[1].instance_eval{emit focus_in(self)}
990
+ flexmock(@views[2]).should_receive(:set_focus).once
991
+ @views[1].close
992
+ end
993
+
994
+ it 'doesn\'t give focus to view which previously had focus in the same tab, if focus_on_editors? returns false' do
995
+ flexmock(@env).should_receive(:focus_on_editors?).and_return false
996
+ @env.activate_editor @views[2]
997
+ @env.activate_editor @views[1]
998
+ @views[2].instance_eval{emit focus_in(self)}
999
+ @views[1].instance_eval{emit focus_in(self)}
1000
+ flexmock(@views[2]).should_receive(:set_focus).never
1001
+ @views[1].close
1002
+ end
1003
+
1004
+ end
1005
+
1006
+ context 'if there\'s no other editor in the same tab' do
1007
+
1008
+ before do
1009
+ @views = 2.times.map{@env.editor_for! @doc, :existing => :never, :new => :new_tab}
1010
+ end
1011
+
1012
+ it 'removes the tab' do
1013
+ @views[1].close
1014
+ @env.tab_widget.count.should == 1
1015
+ end
1016
+
1017
+ end
1018
+
1019
+ it 'removes the view from the list of views' do
1020
+ views = 3.times.map{@env.editor_for! @doc, :existing => :never}
1021
+ views[1].close
1022
+ @env.views.should == [views[0], views[2]]
1023
+ end
1024
+
1025
+ end
1026
+
1027
+ describe '#close_editor' do
1028
+
1029
+ before do
1030
+ @doc = Ruber[:world].new_document
1031
+ end
1032
+
1033
+ context 'if the given editor is the last editor associated with the document' do
1034
+
1035
+ it 'closes the document, passing the second argument to Document#close' do
1036
+ editor = @env.editor_for! @doc
1037
+ class << @doc
1038
+ alias_method :close!, :close
1039
+ end
1040
+ flexmock(@doc).should_receive(:close).once.with(false)
1041
+ @env.close_editor editor, false
1042
+ @doc.close!
1043
+ end
1044
+
1045
+ end
1046
+
1047
+ context 'if the given editor is not the only one associated with the document' do
1048
+
1049
+ it 'only closes the editor' do
1050
+ class << @doc
1051
+ alias_method :close!, :close
1052
+ end
1053
+ editor = @env.editor_for! @doc
1054
+ class << editor
1055
+ alias_method :close!, :close
1056
+ end
1057
+ other_editor = @doc.create_view
1058
+ flexmock(@doc).should_receive(:close).never
1059
+ flexmock(editor).should_receive(:close).once
1060
+ @env.close_editor editor, false
1061
+ editor.close!
1062
+ @doc.close!
1063
+ end
1064
+
1065
+ end
1066
+
1067
+ end
1068
+
1069
+ describe '#close' do
1070
+
1071
+ context 'if the environment is associated with a project' do
1072
+
1073
+ before do
1074
+ @file = File.join Dir.tmpdir, 'environment_remove_from_project_test'
1075
+ @project = Ruber::Project.new @file, "Test"
1076
+ @env = Ruber::World::Environment.new @project
1077
+ @docs = 4.times.map{Ruber[:world].new_document}
1078
+ @env_views = []
1079
+ @env_views += 2.times.map{@env.editor_for! @docs[0], :existing => :never}
1080
+ @env_views += 3.times.map{@env.editor_for! @docs[1], :existing => :never}
1081
+ @env_views += 3.times.map{@env.editor_for! @docs[2], :existing => :never}
1082
+ @other_views = [@docs[2].create_view, @docs[3].create_view]
1083
+ end
1084
+
1085
+ after do
1086
+ FileUtils.rm_f @file
1087
+ end
1088
+
1089
+ context 'if the argument is :save' do
1090
+
1091
+ it 'calls the project\'s close method passing true as argument' do
1092
+ flexmock(@project).should_receive(:close).with(true).once
1093
+ @env.close :save
1094
+ end
1095
+
1096
+ it 'returns the value returned by the project\'s close method' do
1097
+ flexmock(@project).should_receive(:close).once.and_return(true)
1098
+ @env.close(:save).should == true
1099
+ flexmock(@project).should_receive(:close).once.and_return(false)
1100
+ @env.close(:save).should == false
1101
+ end
1102
+
1103
+ end
1104
+
1105
+ context 'if the argument is :discard' do
1106
+
1107
+ it 'calls the project\'s close method passing false as argument' do
1108
+ flexmock(@project).should_receive(:close).with(false).once
1109
+ @env.close :discard
1110
+ end
1111
+
1112
+ it 'returns the value returned by the project\'s close method' do
1113
+ flexmock(@project).should_receive(:close).once.and_return(true)
1114
+ @env.close(:discard).should == true
1115
+ flexmock(@project).should_receive(:close).once.and_return(false)
1116
+ @env.close(:discard).should == false
1117
+ end
1118
+
1119
+ end
1120
+
1121
+ end
1122
+
1123
+ context 'if the environment is not associated with a project' do
1124
+
1125
+ before do
1126
+ @docs = 4.times.map{Ruber[:world].new_document}
1127
+ @env_views = []
1128
+ @env_views += 2.times.map{@env.editor_for! @docs[0], :existing => :never}
1129
+ @env_views += 3.times.map{@env.editor_for! @docs[1], :existing => :never}
1130
+ @env_views << @env.editor_for!(@docs[2])
1131
+ @other_views = [@docs[2].create_view, @docs[3].create_view]
1132
+ end
1133
+
1134
+ context 'if the argument is :save' do
1135
+
1136
+ it 'calls MainWindow#save_documents passing the list of documents all of whose views are in the environment' do
1137
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).with( [@docs[0], @docs[1]]).once
1138
+ @env.close :save
1139
+ end
1140
+
1141
+ context 'if MainWindow#save returns true' do
1142
+
1143
+ before do
1144
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).and_return true
1145
+ end
1146
+
1147
+ it 'emits the closing signal passing itself as argument' do
1148
+ mk = flexmock{|m| m.should_receive(:env_closing).once.with(@env.object_id)}
1149
+ @env.connect(SIGNAL('closing(QObject*)')){|e| mk.env_closing e.object_id}
1150
+ @env.close :save
1151
+ end
1152
+
1153
+ it 'deactivates itself' do
1154
+ @env.activate
1155
+ @env.close :save
1156
+ @env.should_not be_active
1157
+ end
1158
+
1159
+ it 'closes all the documents whose views are all contained in the environment without asking' do
1160
+ 2.times{|i| flexmock(@docs[i]).should_receive(:close).with(false).once}
1161
+ 2.upto(3){|i| flexmock(@docs[i]).should_receive(:close).never}
1162
+ @env.close :save
1163
+ end
1164
+
1165
+ it 'closes all the views in the environment whose documents have views not associated with the enviroment' do
1166
+ @env_views.select{|v| v.document == @docs[2]}.each{|v| flexmock(v).should_receive(:close).once}
1167
+ @env.close :save
1168
+ end
1169
+
1170
+ it 'disposes of itself' do
1171
+ flexmock(@env).should_receive(:delete_later).once
1172
+ @env.close :save
1173
+ end
1174
+
1175
+ it 'returns true' do
1176
+ @env.close(:save).should == true
1177
+ end
1178
+
1179
+ end
1180
+
1181
+ context 'if MainWindow#save returns false' do
1182
+
1183
+ before do
1184
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).and_return false
1185
+ end
1186
+
1187
+ it 'does nothing' do
1188
+ @env_views.each{|v| flexmock(v).should_receive(:close).never}
1189
+ @docs.each{|d| flexmock(d).should_receive(:close).never}
1190
+ @env.close :save
1191
+ end
1192
+
1193
+ it 'returns false' do
1194
+ @env.close(:save).should == false
1195
+ end
1196
+
1197
+ end
1198
+
1199
+ end
1200
+
1201
+ context 'if the argument is :discard' do
1202
+
1203
+
1204
+ it 'doesn\'t call MainWindow#save_documents' do
1205
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).never
1206
+ @env.close :discard
1207
+ end
1208
+
1209
+ it 'emits the closing signal passing itself as argument' do
1210
+ mk = flexmock{|m| m.should_receive(:env_closing).once.with(@env.object_id)}
1211
+ @env.connect(SIGNAL('closing(QObject*)')){|e| mk.env_closing e.object_id}
1212
+ @env.close :discard
1213
+ end
1214
+
1215
+ it 'deactivates itself' do
1216
+ @env.activate
1217
+ @env.close :discard
1218
+ @env.should_not be_active
1219
+ end
1220
+
1221
+ it 'closes all the documents whose views are all contained in the environment without asking' do
1222
+ 2.times{|i| flexmock(@docs[i]).should_receive(:close).with(false).once}
1223
+ 2.upto(3){|i| flexmock(@docs[i]).should_receive(:close).never}
1224
+ @env.close :discard
1225
+ end
1226
+
1227
+ it 'closes all the views in the environment whose documents have views not associated with the enviroment' do
1228
+ @env_views.select{|v| v.document == @docs[2]}.each{|v| flexmock(v).should_receive(:close).once}
1229
+ @env.close :discard
1230
+ end
1231
+
1232
+ it 'disposes of itself' do
1233
+ flexmock(@env).should_receive(:delete_later).once
1234
+ @env.close :discard
1235
+ end
1236
+
1237
+ it 'returns true' do
1238
+ @env.close(:discard).should == true
1239
+ end
1240
+
1241
+ end
1242
+
1243
+ end
1244
+
1245
+ end
1246
+
1247
+ describe '#close_editors' do
1248
+
1249
+ before do
1250
+ @docs = 3.times.map{Ruber::Document.new}
1251
+ @views = []
1252
+ @docs.each_with_index do |doc, i|
1253
+ views = 3.times.map{@env.editor_for! doc, :existing => :never}
1254
+ @views[i] = views
1255
+ end
1256
+ end
1257
+
1258
+ context 'if the second argument is false' do
1259
+
1260
+ it 'closes without asking all documents whose views are all to be closed' do
1261
+ flexmock(@docs[0]).should_receive(:close).once.with(false)
1262
+ flexmock(@docs[2]).should_receive(:close).once.with(false)
1263
+ flexmock(@docs[1]).should_receive(:close).never
1264
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], false
1265
+ end
1266
+
1267
+ it 'closes the editors associated with documents having some views not to be closed' do
1268
+ flexmock(@docs[0]).should_receive(:close).once.with(false)
1269
+ flexmock(@docs[2]).should_receive(:close).never
1270
+ flexmock(@docs[1]).should_receive(:close).never
1271
+ other_view = @docs[2].create_view
1272
+ (@views[2] + [@views[1][0]]).each do |v|
1273
+ flexmock(v).should_receive(:close).once
1274
+ end
1275
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], false
1276
+ end
1277
+
1278
+ end
1279
+
1280
+ context 'if the second argument is true' do
1281
+
1282
+ it 'calls MainWindow#save_documents passing all the documents whose views are all to be closed' do
1283
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).with([@docs[0], @docs[2]]).once
1284
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], true
1285
+ end
1286
+
1287
+ context 'if MainWindow#save_documents returns false' do
1288
+
1289
+ it 'does nothing' do
1290
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).and_return false
1291
+ @views.flatten.each{|v| flexmock(v).should_receive(:close).never}
1292
+ @docs.each{|d| flexmock(d).should_receive(:close).never}
1293
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], true
1294
+ end
1295
+
1296
+ end
1297
+
1298
+ context 'if MainWindow#save_documents returns true' do
1299
+
1300
+ before do
1301
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).and_return true
1302
+ end
1303
+
1304
+ it 'closes without asking all documents whose views are all to be closed' do
1305
+ flexmock(@docs[0]).should_receive(:close).once.with(false)
1306
+ flexmock(@docs[2]).should_receive(:close).once.with(false)
1307
+ flexmock(@docs[1]).should_receive(:close).never
1308
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], true
1309
+ end
1310
+
1311
+ it 'closes the editors associated with documents having some views not to be closed' do
1312
+ flexmock(@docs[0]).should_receive(:close).once.with(false)
1313
+ flexmock(@docs[2]).should_receive(:close).never
1314
+ flexmock(@docs[1]).should_receive(:close).never
1315
+ other_view = @docs[2].create_view
1316
+ (@views[2] + [@views[1][0]]).each do |v|
1317
+ flexmock(v).should_receive(:close).once
1318
+ end
1319
+ @env.close_editors @views[0] + @views[2] + [@views[1][0]], true
1320
+ end
1321
+
1322
+ end
1323
+
1324
+ end
1325
+
1326
+ end
1327
+
1328
+ describe '#display_document' do
1329
+
1330
+ before do
1331
+ @doc = Ruber[:world].new_document
1332
+ end
1333
+
1334
+ it 'retrieves an editor for the given document according to the hints' do
1335
+ ed = @env.editor_for! @doc
1336
+ hints = {:existing => :always, :strategy => :last}
1337
+ flexmock(@env).should_receive(:editor_for!).with(@doc, hints).once.and_return ed
1338
+ @env.display_document @doc, hints
1339
+ end
1340
+
1341
+ it 'activates the editor' do
1342
+ ed = @env.editor_for! @doc
1343
+ hints = {:existing => :always, :strategy => :last}
1344
+ @env.display_document @doc, hints
1345
+ @env.active_editor.should == ed
1346
+ end
1347
+
1348
+ it 'moves the cursor to the line and column corresponding to the :line and :column hints' do
1349
+ ed = @env.editor_for! @doc
1350
+ flexmock(ed).should_receive(:go_to).with(10, 6).once
1351
+ hints = {:existing => :always, :strategy => :last, :line => 10, :column => 6}
1352
+ @env.display_document @doc, hints
1353
+ end
1354
+
1355
+ it 'uses 0 as column hint if the line hint is given and the column hint is not' do
1356
+ ed = @env.editor_for! @doc
1357
+ flexmock(ed).should_receive(:go_to).with(10, 0).once
1358
+ hints = {:existing => :always, :strategy => :last, :line => 10}
1359
+ @env.display_document @doc, hints
1360
+ end
1361
+
1362
+ it 'doesn\'t move the cursor if the line hint is not given' do
1363
+ ed = @env.editor_for! @doc
1364
+ flexmock(ed).should_receive(:go_to).never
1365
+ hints = {:existing => :always, :strategy => :last}
1366
+ @env.display_document @doc, hints
1367
+ hints[:column] = 4
1368
+ @env.display_document @doc, hints
1369
+ end
1370
+
1371
+ it 'returns the editor' do
1372
+ ed = @env.display_document @doc
1373
+ ed.should be_a(Ruber::EditorView)
1374
+ ed.document.should == @doc
1375
+ end
1376
+
1377
+ end
1378
+
1379
+ context 'when a view receives focus' do
1380
+
1381
+ it 'is made active' do
1382
+ doc = Ruber[:world].new_document
1383
+ @views = 2.times.map{@env.editor_for! doc, :existing => :never}
1384
+ @env.activate_editor @views[0]
1385
+ @views[1].instance_eval{emit focus_in(self)}
1386
+ @env.active_editor.should == @views[1]
1387
+ end
1388
+
1389
+ end
1390
+
1391
+ context 'when the close button on a tab is pressed' do
1392
+
1393
+ before do
1394
+ Ruber[:world].close_all :documents, :discard
1395
+ @doc = Ruber[:world].new_document
1396
+ @views = 3.times.map{@env.editor_for! @doc, :existing => :never, :new => :current_tab}
1397
+ @other_view = @env.editor_for! @doc, :existing => :never, :new => :new_tab
1398
+ end
1399
+
1400
+ it 'closes all the editors in the tab' do
1401
+ flexmock(@env).should_receive(:close_editors).once.with(FlexMock.on{|a| a.sort_by(&:object_id) == @views.sort_by(&:object_id)})
1402
+ @env.tab_widget.instance_eval{emit tabCloseRequested(0)}
1403
+ end
1404
+
1405
+ it 'does nothing if the user chooses to abort the operation' do
1406
+ flexmock(Ruber::MainWindow).should_receive(:save_documents).and_return false
1407
+ @views.each{|v| flexmock(v).should_receive(:close).never}
1408
+ end
1409
+
1410
+ end
1411
+
1412
+ context 'when a view is split' do
1413
+
1414
+ before do
1415
+ @doc = Ruber[:world].new_document
1416
+ @view = @env.editor_for! @doc
1417
+ end
1418
+
1419
+ it 'adds the new view to the list' do
1420
+ new_view = @doc.create_view
1421
+ @env.tab(@view).split @view, new_view, Qt::Vertical
1422
+ @env.views.should include(new_view)
1423
+ end
1424
+
1425
+ it 'adds the document associated with the view to the list of documents, if needed' do
1426
+ doc = Ruber[:world].new_document
1427
+ new_view = doc.create_view
1428
+ @env.tab(@view).split @view, new_view, Qt::Vertical
1429
+ @env.documents.should include(doc)
1430
+ end
1431
+
1432
+ it 'updates the tool tip of the tab' do
1433
+ doc = Ruber[:world].new_document
1434
+ new_view = doc.create_view
1435
+ @env.tab(@view).split @view, new_view, Qt::Vertical
1436
+ exp = @doc.document_name + "\n" + doc.document_name
1437
+ @env.tab_widget.tab_tool_tip(0).should == exp
1438
+ end
1439
+
1440
+ it 'reacts to the view getting focus' do
1441
+ new_view = @doc.create_view
1442
+ @env.tab(@view).split @view, new_view, Qt::Vertical
1443
+ new_view.instance_eval{emit focus_in(self)}
1444
+ @env.active_editor.should == new_view
1445
+ end
1446
+
1447
+ it 'reacts to the view being closed' do
1448
+ new_view = @doc.create_view
1449
+ @env.tab(@view).split @view, new_view, Qt::Vertical
1450
+ new_view.close
1451
+ @env.views.should_not include(new_view)
1452
+ end
1453
+
1454
+ end
1455
+
1456
+ context 'when a view is replaced by another' do
1457
+
1458
+ before do
1459
+ @doc = Ruber[:world].new_document
1460
+ @view = @env.editor_for! @doc
1461
+ end
1462
+
1463
+ it 'adds the new view to the list' do
1464
+ new_view = @doc.create_view
1465
+ @env.tab(@view).replace_view @view, new_view
1466
+ @env.views.should include(new_view)
1467
+ end
1468
+
1469
+ it 'removes the replaced view from the list' do
1470
+ new_view = @doc.create_view
1471
+ @env.tab(@view).replace_view @view, new_view
1472
+ @env.views.should_not include(@view)
1473
+ end
1474
+
1475
+ it 'adds the document associated with the view to the list of documents, if needed' do
1476
+ doc = Ruber[:world].new_document
1477
+ new_view = doc.create_view
1478
+ @env.tab(@view).replace_view @view, new_view
1479
+ @env.documents.should include(doc)
1480
+ end
1481
+
1482
+ it 'removes the document associated with the replaced view if it was the only view associated with it in the environment' do
1483
+ doc = Ruber[:world].new_document
1484
+ new_view = doc.create_view
1485
+ @env.tab(@view).replace_view @view, new_view
1486
+ @env.documents.should_not include(@doc)
1487
+ end
1488
+
1489
+ it 'doesn\'t remove the document associated with the replaced view if it wasn\'t the only view associated with it in the environment' do
1490
+ doc = Ruber[:world].new_document
1491
+ new_view = doc.create_view
1492
+ @env.editor_for! @doc, :existing => :never, :new => :new_tab
1493
+ @env.tab(@view).replace_view @view, new_view
1494
+ @env.documents.should include(@doc)
1495
+ end
1496
+
1497
+ it 'updates the tool tip of the tab' do
1498
+ doc = Ruber[:world].new_document
1499
+ new_view = doc.create_view
1500
+ @env.tab(@view).replace_view @view, new_view
1501
+ exp = doc.document_name
1502
+ @env.tab_widget.tab_tool_tip(0).should == exp
1503
+ end
1504
+
1505
+ it 'reacts to the new view getting focus' do
1506
+ new_view = @doc.create_view
1507
+ @env.tab(@view).replace_view @view, new_view
1508
+ new_view.instance_eval{emit focus_in(self)}
1509
+ @env.active_editor.should == new_view
1510
+ end
1511
+
1512
+ it 'doesn\'t react to the replaced view getting focus' do
1513
+ new_view = @doc.create_view
1514
+ @env.tab(@view).replace_view @view, new_view
1515
+ @env.activate_editor nil
1516
+ @view.instance_eval{emit focus_in(self)}
1517
+ @env.active_editor.should be_nil
1518
+ end
1519
+
1520
+ it 'reacts to the view being closed' do
1521
+ new_view = @doc.create_view
1522
+ @env.tab(@view).replace_view @view, new_view
1523
+ new_view.close
1524
+ @env.views.should_not include(new_view)
1525
+ end
1526
+
1527
+ it 'doesn\'t react to the replaced view being closed anymore' do
1528
+ new_view = @doc.create_view
1529
+ @env.tab(@view).replace_view @view, new_view
1530
+ flexmock(@env).should_receive(:editor_closing).never
1531
+ @view.close
1532
+ end
1533
+
1534
+ end
1535
+
1536
+ context 'when the URL of a document changes' do
1537
+
1538
+ before do
1539
+ @doc = Ruber[:world].new_document
1540
+ end
1541
+
1542
+ context 'if the document is associated with a view in the environment' do
1543
+
1544
+ before do
1545
+ @views = 2.times.map{@env.editor_for! @doc, :existing => :never}
1546
+ @url = KDE::Url.new __FILE__
1547
+ flexmock(@doc).should_receive(:url).and_return @url
1548
+ flexmock(@doc).should_receive(:document_name).and_return File.basename(__FILE__)
1549
+ flexmock(@doc).should_receive(:path).and_return(__FILE__)
1550
+ end
1551
+
1552
+ it 'updates the tool tip of the tabs containing views associated with the document' do
1553
+ @doc.instance_eval{emit document_url_changed(self)}
1554
+ @env.tab_widget.to_a.each_index{|i|@env.tab_widget.tab_tool_tip(i).should == File.basename(__FILE__)}
1555
+ end
1556
+
1557
+ it 'updates the label of the editors associated with the document' do
1558
+ @doc.instance_eval{emit document_url_changed(self)}
1559
+ @views.each{|v| v.parent.label.should == @url.path}
1560
+ end
1561
+
1562
+ it 'updates the text amd icon of any tabs having a view associated with the document as last activated view' do
1563
+ pix = Qt::Pixmap.new(16,16)
1564
+ pix.fill Qt::Color.new(Qt.blue)
1565
+ icon = Qt::Icon.new pix
1566
+ flexmock(@doc).should_receive(:icon).and_return icon
1567
+ other_doc = Ruber[:world].new_document
1568
+ other_views = 2.times.map{|i| @env.editor_for! other_doc, :existing => :never, :new => @views[i]}
1569
+ @env.activate_editor other_views[1]
1570
+ @doc.instance_eval{emit document_url_changed(self)}
1571
+ @env.tab_widget.tab_text(0).should == File.basename(__FILE__)
1572
+ @env.tab_widget.tab_icon(0).pixmap(16,16).to_image.should == pix.to_image
1573
+ @env.tab_widget.tab_text(1).should == other_doc.document_name
1574
+ @env.tab_widget.tab_icon(1).pixmap(16,16).to_image.should_not == pix.to_image
1575
+ end
1576
+
1577
+ end
1578
+
1579
+ end
1580
+
1581
+ describe 'when the modified status of a document associated with a view in the environment changes' do
1582
+
1583
+ before do
1584
+ @doc = Ruber[:world].new_document
1585
+ @other_doc = Ruber[:world].new_document
1586
+ @views = 2.times.map{@env.editor_for! @doc, :existing => :never}
1587
+ end
1588
+
1589
+ context 'if the document has become modified' do
1590
+
1591
+ after do
1592
+ @doc.close false
1593
+ end
1594
+
1595
+ it 'updates the label of the views associated with the document by putting [modified] after the name of the document' do
1596
+ other_views=2.times.map{@env.editor_for! @other_doc, :existing => :never}
1597
+ @doc.text = 'x'
1598
+ @views.each do |v|
1599
+ v.parent.label.should == @doc.document_name + ' [modified]'
1600
+ end
1601
+ other_views.each do |v|
1602
+ v.parent.label.should == @other_doc.document_name
1603
+ end
1604
+ end
1605
+
1606
+ it 'updates the icon of any tabs having a view associated with the document as last activated view' do
1607
+ img = Ruber::Document::ICONS[:modified].pixmap(16,16).to_image
1608
+ other_views = 2.times.map{|i| @env.editor_for! @other_doc, :existing => :never, :new => @views[i]}
1609
+ @env.activate_editor other_views[1]
1610
+ @doc.text = 'x'
1611
+ @env.tab_widget.tab_icon(0).pixmap(16,16).to_image.should == img
1612
+ @env.tab_widget.tab_icon(1).pixmap(16,16).to_image.should_not == img
1613
+ end
1614
+
1615
+ end
1616
+
1617
+ context 'if the document has become not modified' do
1618
+
1619
+ before do
1620
+ @doc.text = 'x'
1621
+ end
1622
+
1623
+ after do
1624
+ @doc.close false
1625
+ end
1626
+
1627
+ it 'updates the label of the views associated with the document' do
1628
+ other_views=2.times.map{@env.editor_for! @other_doc, :existing => :never}
1629
+ @doc.modified = false
1630
+ @views.each do |v|
1631
+ v.parent.label.should == @doc.document_name
1632
+ end
1633
+ other_views.each do |v|
1634
+ v.parent.label.should == @other_doc.document_name
1635
+ end
1636
+ end
1637
+
1638
+ it 'updates the icon of any tabs having a view associated with the document as last activated view' do
1639
+ img = Ruber::Document::ICONS[:modified].pixmap(16,16).to_image
1640
+ other_views = 2.times.map{|i| @env.editor_for! @other_doc, :existing => :never, :new => @views[i]}
1641
+ @env.activate_editor other_views[1]
1642
+ @doc.modified = false
1643
+ @env.tab_widget.tab_icon(0).pixmap(16,16).to_image.should_not == img
1644
+ @env.tab_widget.tab_icon(1).pixmap(16,16).to_image.should_not == img
1645
+ end
1646
+
1647
+ end
1648
+
1649
+ end
1650
+
1651
+ describe "#focus_on_editors?" do
1652
+
1653
+ before do
1654
+ @views = Array.new(3){@env.editor_for! @doc, :existing => :never}
1655
+ end
1656
+
1657
+ it 'returns true if one of the views in the environment received focus after the last one lost focus' do
1658
+ @views[1].instance_eval{emit focus_out(self)}
1659
+ @views[2].instance_eval{emit focus_in(self)}
1660
+ @env.focus_on_editors?.should be_true
1661
+ end
1662
+
1663
+ it 'returns false if no view in the environment got focus after the last one
1664
+ lost focus' do
1665
+ @env.activate_editor @views[1]
1666
+ flexmock(@views[1]).should_receive(:is_active_window).once.and_return true
1667
+ @views[1].instance_eval{emit focus_out(self)}
1668
+ @env.focus_on_editors?.should be_false
1669
+ end
1670
+
1671
+ it 'returns true if there are no views' do
1672
+ @views.each{|v| @env.close_editor v, false}
1673
+ @env.focus_on_editors?.should be_true
1674
+ end
1675
+
1676
+ end
1677
+
1678
+ describe '#query_save' do
1679
+
1680
+ before do
1681
+ @docs = Array.new(3){Ruber[:world].new_document}
1682
+ 2.times{@env.editor_for! @docs[0], :existing => :never}
1683
+ 2.times{@env.editor_for! @docs[1], :existing => :never}
1684
+ @docs[1].create_view
1685
+ 2.times{@docs[2].create_view}
1686
+ end
1687
+
1688
+ context 'if the application\'s status is different from :asking_to_quit' do
1689
+
1690
+ before do
1691
+ flexmock(Ruber[:app]).should_receive(:status).and_return(:running)
1692
+ end
1693
+
1694
+ it 'calls MainWindow#save_documents passing all the documents not having views outside the environment' do
1695
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).once.with([@docs[0]])
1696
+ @env.query_close
1697
+ end
1698
+
1699
+ it 'returns the value returned by MainWindow#save_documents' do
1700
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).once.and_return(false)
1701
+ @env.query_close.should == false
1702
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).once.and_return(true)
1703
+ @env.query_close.should == true
1704
+ end
1705
+
1706
+ end
1707
+
1708
+ context 'if the application\'s status is from :asking_to_quit' do
1709
+
1710
+ before do
1711
+ flexmock(Ruber[:app]).should_receive(:status).and_return(:asking_to_quit)
1712
+ end
1713
+
1714
+ it 'doesn\'t call MainWindow#save_documents' do
1715
+ flexmock(Ruber[:main_window]).should_receive(:save_documents).never
1716
+ @env.query_close
1717
+ end
1718
+
1719
+ it 'returns true' do
1720
+ @env.query_close.should == true
1721
+ end
1722
+
1723
+ end
1724
+
1725
+ end
1726
+
1727
+ describe '#remove_from_project' do
1728
+
1729
+ context 'if the environment is associated with a project' do
1730
+
1731
+ before do
1732
+ @file = File.join Dir.tmpdir, 'environment_remove_from_project_test'
1733
+ @project = Ruber::Project.new @file, "Test"
1734
+ @env = Ruber::World::Environment.new @project
1735
+ @docs = 4.times.map{Ruber[:world].new_document}
1736
+ @env_views = []
1737
+ @env_views += 2.times.map{@env.editor_for! @docs[0], :existing => :never}
1738
+ @env_views += 3.times.map{@env.editor_for! @docs[1], :existing => :never}
1739
+ @env_views += 3.times.map{@env.editor_for! @docs[2], :existing => :never}
1740
+ @other_views = [@docs[2].create_view, @docs[3].create_view]
1741
+ end
1742
+
1743
+ it 'emits the closing signal passing itself as argument' do
1744
+ mk = flexmock{|m| m.should_receive(:env_closing).once.with(@env.object_id)}
1745
+ @env.connect(SIGNAL('closing(QObject*)')){|e| mk.env_closing e.object_id}
1746
+ @env.remove_from_project
1747
+ end
1748
+
1749
+ it 'deactivates itself' do
1750
+ @env.activate
1751
+ @env.remove_from_project
1752
+ @env.should_not be_active
1753
+ end
1754
+
1755
+ it 'closes all the documents whose views are all contained in the environment without asking' do
1756
+ 2.times{|i| flexmock(@docs[i]).should_receive(:close).with(false).once}
1757
+ 2.upto(3){|i| flexmock(@docs[i]).should_receive(:close).never}
1758
+ @env.remove_from_project
1759
+ end
1760
+
1761
+ it 'closes all the views in the environment whose documents have views not associated with the enviroment without closing their documents' do
1762
+ flexmock(@docs[2]).should_receive(:close).never
1763
+ @env_views.each{|v| flexmock(v).should_receive(:close).once if v.document == @docs[2]}
1764
+ @env.remove_from_project
1765
+ end
1766
+
1767
+ end
1768
+
1769
+ context 'if the environment is not associated with a project' do
1770
+
1771
+ it 'raises RuntimeError' do
1772
+ lambda{@env.remove_from_project}.should raise_error(RuntimeError, "environment not associated with a project")
1773
+ end
1774
+
1775
+ end
1776
+
1777
+ end
1778
+
1779
+ describe '#replace_editor' do
1780
+
1781
+ before do
1782
+ Ruber[:world].close_all :all, :discard
1783
+ @old_view = @env.editor_for! __FILE__
1784
+
1785
+ @new_view = Ruber[:world].new_document.create_view
1786
+ end
1787
+
1788
+ it 'replaces the editor given as first argument with the one given as second argument' do
1789
+ flexmock(@old_view.parent).should_receive(:replace_view).with(@old_view, @new_view).once
1790
+ @env.replace_editor @old_view, @new_view
1791
+ end
1792
+
1793
+ it 'returns the new editor' do
1794
+ @env.replace_editor(@old_view, @new_view).should == @new_view
1795
+ end
1796
+
1797
+ context 'if the view to replace is the last view associated with its document' do
1798
+
1799
+ it 'calls the document\'s query_close method before replacing the view' do
1800
+ flexmock(@old_view.document).should_receive(:query_close).globally.ordered.once.and_return true
1801
+ flexmock(@old_view.parent).should_receive(:replace_view).with(@old_view, @new_view).once.globally.ordered
1802
+ @env.replace_editor @old_view, @new_view
1803
+ end
1804
+
1805
+ it 'does nothing if the document\'s query_close method returns false' do
1806
+ flexmock(@old_view.document).should_receive(:query_close).and_return false
1807
+ flexmock(@old_view.parent).should_receive(:replace_view).with(@old_view, @new_view).never
1808
+ @env.replace_editor @old_view, @new_view
1809
+ end
1810
+
1811
+ it 'closes the document after replacing the view' do
1812
+ mk = flexmock do |m|
1813
+ m.should_receive(:document_closing).with(@old_view.document).once
1814
+ end
1815
+ @old_view.document.connect(SIGNAL('closing(QObject*)')) do |doc|
1816
+ mk.document_closing doc
1817
+ end
1818
+ @env.replace_editor @old_view, @new_view
1819
+ end
1820
+
1821
+ end
1822
+
1823
+ context 'if the view to replace is not the last associated with its document' do
1824
+
1825
+ before do
1826
+ @other_view = @old_view.document.create_view
1827
+ end
1828
+
1829
+ it 'doesn\'t call the query_close method of the document associated with the view to replace' do
1830
+ flexmock(@old_view.document).should_receive(:query_close).never
1831
+ @env.replace_editor @old_view, @new_view
1832
+ end
1833
+
1834
+ it 'doesn\'t close the document associated with the view to replace' do
1835
+ mk = flexmock do |m|
1836
+ m.should_receive(:document_closing).with(@old_view.document).never
1837
+ end
1838
+ @old_view.document.connect(SIGNAL('closing(QObject*)')) do |doc|
1839
+ mk.document_closing doc
1840
+ end
1841
+ @env.replace_editor @old_view, @new_view
1842
+ end
1843
+
1844
+ it 'closes the replaced editor' do
1845
+ flexmock(@old_view).should_receive(:close).once
1846
+ @env.replace_editor @old_view, @new_view
1847
+ end
1848
+
1849
+ end
1850
+
1851
+ context 'if the second argument is a Document' do
1852
+
1853
+ before do
1854
+ @new_view = nil
1855
+ @doc = Ruber[:world].new_document
1856
+ end
1857
+
1858
+ it 'creates a new view for the document using the document\'s create_view method' do
1859
+ view = @doc.create_view
1860
+ flexmock(@doc).should_receive(:create_view).once.and_return view
1861
+ flexmock(@env).should_receive(:editor_for!).never
1862
+ flexmock(@old_view.parent).should_receive(:replace_view).once.with(@old_view, view)
1863
+ @env.replace_editor @old_view, @doc
1864
+ end
1865
+
1866
+ end
1867
+
1868
+ context 'if the second argument is a String' do
1869
+
1870
+ it 'creates a new view for the document associated to that string' do
1871
+ file = '/xyz/abc.rb'
1872
+ doc = Ruber[:world].new_document
1873
+ flexmock(Ruber[:world]).should_receive(:document).with(file).once.and_return doc
1874
+ view = doc.create_view
1875
+ flexmock(doc).should_receive(:create_view).once.and_return view
1876
+ flexmock(@env).should_receive(:editor_for!).never
1877
+ flexmock(@old_view.parent).should_receive(:replace_view).once.with(@old_view, view)
1878
+ @env.replace_editor @old_view, file
1879
+ end
1880
+
1881
+ end
1882
+
1883
+ context 'if the second argument is a KDE::Url' do
1884
+
1885
+ it 'creates a new view for the document associated to that string' do
1886
+ url = KDE::Url.new 'file:///xyz/abc.rb'
1887
+ doc = Ruber[:world].new_document
1888
+ flexmock(Ruber[:world]).should_receive(:document).with(url).once.and_return doc
1889
+ view = doc.create_view
1890
+ flexmock(doc).should_receive(:create_view).once.and_return view
1891
+ flexmock(@env).should_receive(:editor_for!).never
1892
+ flexmock(@old_view.parent).should_receive(:replace_view).once.with(@old_view, view)
1893
+ @env.replace_editor @old_view, url
1894
+ end
1895
+
1896
+ end
1897
+
1898
+ end
1899
+
1900
+ end