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
@@ -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