ruber 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data/COPYING +339 -0
  2. data/INSTALL +137 -0
  3. data/LICENSE +8 -0
  4. data/bin/ruber +65 -0
  5. data/data/share/apps/ruber/core_components.yaml +31 -0
  6. data/data/share/apps/ruber/ruberui.rc +109 -0
  7. data/data/share/icons/ruber.png +0 -0
  8. data/data/share/pixmaps/ruby.png +0 -0
  9. data/icons/ruber-16.png +0 -0
  10. data/icons/ruber-32.png +0 -0
  11. data/icons/ruber-48.png +0 -0
  12. data/icons/ruber-8.png +0 -0
  13. data/lib/ruber/application/application.rb +288 -0
  14. data/lib/ruber/application/plugin.yaml +11 -0
  15. data/lib/ruber/component_manager.rb +899 -0
  16. data/lib/ruber/config/config.rb +82 -0
  17. data/lib/ruber/config/plugin.yaml +3 -0
  18. data/lib/ruber/document_project.rb +209 -0
  19. data/lib/ruber/documents/document_list.rb +416 -0
  20. data/lib/ruber/documents/plugin.yaml +4 -0
  21. data/lib/ruber/editor/document.rb +506 -0
  22. data/lib/ruber/editor/editor_view.rb +167 -0
  23. data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
  24. data/lib/ruber/exception_widgets.rb +245 -0
  25. data/lib/ruber/external_program_plugin.rb +397 -0
  26. data/lib/ruber/filtered_output_widget.rb +342 -0
  27. data/lib/ruber/gui_states_handler.rb +231 -0
  28. data/lib/ruber/kde_config_option_backend.rb +167 -0
  29. data/lib/ruber/kde_sugar.rb +249 -0
  30. data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
  31. data/lib/ruber/main_window/main_window.rb +524 -0
  32. data/lib/ruber/main_window/main_window_actions.rb +537 -0
  33. data/lib/ruber/main_window/main_window_internal.rb +239 -0
  34. data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
  35. data/lib/ruber/main_window/output_color_widget.rb +35 -0
  36. data/lib/ruber/main_window/plugin.yaml +58 -0
  37. data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
  38. data/lib/ruber/main_window/status_bar.rb +156 -0
  39. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
  40. data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
  41. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
  42. data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
  43. data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
  44. data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
  45. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
  46. data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
  47. data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
  48. data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
  49. data/lib/ruber/main_window/workspace.rb +442 -0
  50. data/lib/ruber/output_widget.rb +1093 -0
  51. data/lib/ruber/plugin.rb +264 -0
  52. data/lib/ruber/plugin_like.rb +589 -0
  53. data/lib/ruber/plugin_specification.rb +106 -0
  54. data/lib/ruber/plugin_specification_reader.rb +451 -0
  55. data/lib/ruber/project.rb +493 -0
  56. data/lib/ruber/project_backend.rb +105 -0
  57. data/lib/ruber/projects/plugin.yaml +11 -0
  58. data/lib/ruber/projects/project_files_list.rb +314 -0
  59. data/lib/ruber/projects/project_files_widget.rb +301 -0
  60. data/lib/ruber/projects/project_list.rb +314 -0
  61. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
  62. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
  63. data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
  64. data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
  65. data/lib/ruber/qt_sugar.rb +673 -0
  66. data/lib/ruber/settings_container.rb +515 -0
  67. data/lib/ruber/settings_dialog.rb +244 -0
  68. data/lib/ruber/settings_dialog_manager.rb +503 -0
  69. data/lib/ruber/utils.rb +414 -0
  70. data/lib/ruber/yaml_option_backend.rb +159 -0
  71. data/outsider_files +15 -0
  72. data/plugins/autosave/autosave.rb +404 -0
  73. data/plugins/autosave/plugin.yaml +16 -0
  74. data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
  75. data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
  76. data/plugins/command/command.png +0 -0
  77. data/plugins/command/command.rb +74 -0
  78. data/plugins/command/plugin.yaml +11 -0
  79. data/plugins/find_in_files/find_in_files.rb +337 -0
  80. data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
  81. data/plugins/find_in_files/find_in_files_ui.rc +11 -0
  82. data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
  83. data/plugins/find_in_files/plugin.yaml +23 -0
  84. data/plugins/find_in_files/ui/config_widget.rb +58 -0
  85. data/plugins/find_in_files/ui/config_widget.ui +41 -0
  86. data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
  87. data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
  88. data/plugins/project_browser/plugin.yaml +10 -0
  89. data/plugins/project_browser/project_browser.rb +245 -0
  90. data/plugins/rake/plugin.yaml +39 -0
  91. data/plugins/rake/rake.png +0 -0
  92. data/plugins/rake/rake.rb +567 -0
  93. data/plugins/rake/rake_extension.rb +153 -0
  94. data/plugins/rake/rake_widgets.rb +615 -0
  95. data/plugins/rake/rakeui.rc +27 -0
  96. data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
  97. data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
  98. data/plugins/rake/ui/choose_task_widget.rb +77 -0
  99. data/plugins/rake/ui/choose_task_widget.ui +72 -0
  100. data/plugins/rake/ui/config_widget.rb +127 -0
  101. data/plugins/rake/ui/config_widget.ui +123 -0
  102. data/plugins/rake/ui/project_widget.rb +217 -0
  103. data/plugins/rake/ui/project_widget.ui +246 -0
  104. data/plugins/rspec/plugin.yaml +30 -0
  105. data/plugins/rspec/rspec.png +0 -0
  106. data/plugins/rspec/rspec.rb +945 -0
  107. data/plugins/rspec/rspec.svg +90 -0
  108. data/plugins/rspec/rspecui.rc +20 -0
  109. data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
  110. data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
  111. data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
  112. data/plugins/ruby_development/plugin.yaml +27 -0
  113. data/plugins/ruby_development/ruby_development.png +0 -0
  114. data/plugins/ruby_development/ruby_development.rb +453 -0
  115. data/plugins/ruby_development/ruby_developmentui.rc +19 -0
  116. data/plugins/ruby_development/ui/project_widget.rb +112 -0
  117. data/plugins/ruby_development/ui/project_widget.ui +108 -0
  118. data/plugins/ruby_runner/config_widget.rb +116 -0
  119. data/plugins/ruby_runner/plugin.yaml +26 -0
  120. data/plugins/ruby_runner/project_widget.rb +62 -0
  121. data/plugins/ruby_runner/ruby.png +0 -0
  122. data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
  123. data/plugins/ruby_runner/ruby_runner.rb +411 -0
  124. data/plugins/ruby_runner/ui/config_widget.rb +92 -0
  125. data/plugins/ruby_runner/ui/config_widget.ui +91 -0
  126. data/plugins/ruby_runner/ui/project_widget.rb +60 -0
  127. data/plugins/ruby_runner/ui/project_widget.ui +48 -0
  128. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
  129. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
  130. data/plugins/state/plugin.yaml +28 -0
  131. data/plugins/state/state.rb +520 -0
  132. data/plugins/state/ui/config_widget.rb +92 -0
  133. data/plugins/state/ui/config_widget.ui +89 -0
  134. data/plugins/syntax_checker/plugin.yaml +18 -0
  135. data/plugins/syntax_checker/syntax_checker.rb +662 -0
  136. data/ruber.desktop +10 -0
  137. data/spec/annotation_model_spec.rb +174 -0
  138. data/spec/common.rb +119 -0
  139. data/spec/component_manager_spec.rb +1259 -0
  140. data/spec/document_list_spec.rb +626 -0
  141. data/spec/document_project_spec.rb +373 -0
  142. data/spec/document_spec.rb +779 -0
  143. data/spec/editor_view_spec.rb +167 -0
  144. data/spec/external_program_plugin_spec.rb +676 -0
  145. data/spec/filtered_output_widget_spec.rb +642 -0
  146. data/spec/gui_states_handler_spec.rb +304 -0
  147. data/spec/kde_config_option_backend_spec.rb +214 -0
  148. data/spec/kde_sugar_spec.rb +101 -0
  149. data/spec/ktexteditor_wrapper_spec.rb +305 -0
  150. data/spec/output_widget_spec.rb +1703 -0
  151. data/spec/plugin_spec.rb +1393 -0
  152. data/spec/plugin_specification_reader_spec.rb +1765 -0
  153. data/spec/plugin_specification_spec.rb +401 -0
  154. data/spec/project_backend_spec.rb +172 -0
  155. data/spec/project_files_list_spec.rb +401 -0
  156. data/spec/project_list_spec.rb +511 -0
  157. data/spec/project_spec.rb +990 -0
  158. data/spec/qt_sugar_spec.rb +328 -0
  159. data/spec/settings_container_spec.rb +617 -0
  160. data/spec/settings_dialog_manager_spec.rb +773 -0
  161. data/spec/settings_dialog_spec.rb +419 -0
  162. data/spec/state_spec.rb +991 -0
  163. data/spec/utils_spec.rb +406 -0
  164. data/spec/workspace_spec.rb +869 -0
  165. data/spec/yaml_option_backend_spec.rb +246 -0
  166. metadata +284 -0
@@ -0,0 +1,101 @@
1
+ require 'spec/common'
2
+
3
+ require 'ruber/kde_sugar'
4
+
5
+ describe 'KDE::Url' do
6
+
7
+ it 'should be serializable using YAML' do
8
+ u = KDE::Url.new 'http:///xyz.org/a%20file%20with%20spaces.txt'
9
+ res = YAML.load(YAML.dump(u))
10
+ res.should == u
11
+ res.should_not equal(u)
12
+ end
13
+
14
+ it 'should be marshallable' do
15
+ u = KDE::Url.new 'http:///xyz.org/a%20file%20with%20spaces.txt'
16
+ res = Marshal.load(Marshal.dump(u))
17
+ res.should == u
18
+ res.should_not equal(u)
19
+ end
20
+
21
+ describe '#local_file?' do
22
+ it "calls is_local_file" do
23
+ u = KDE::Url.new 'http://www.kde.org'
24
+ flexmock(u).should_receive(:is_local_file).once
25
+ u.local_file?
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ describe 'KDE::MimeType#=~' do
32
+
33
+ before do
34
+ @mime = KDE::MimeType.mime_type 'application/x-ruby'
35
+ end
36
+
37
+ it 'should return true if the mimetype is a child of the argument or if they\'re equal and false otherwise' do
38
+ (@mime =~ 'application/x-ruby').should be_true
39
+ (@mime =~ 'text/plain').should be_true
40
+ (@mime =~ 'text/x-python').should be_false
41
+ end
42
+
43
+ it 'should return invert the match if the argument starts with a !' do
44
+ (@mime =~ '!application/x-ruby').should be_false
45
+ (@mime =~ '!text/plain').should be_false
46
+ (@mime =~ '!text/x-python').should be_true
47
+ end
48
+
49
+ it 'should return true only if the argument is equal to the mimetype\'s name if the argument starts with =' do
50
+ (@mime =~ '=application/x-ruby').should be_true
51
+ (@mime =~ '=text/plain').should be_false
52
+ (@mime =~ '=text/x-python').should be_false
53
+ end
54
+
55
+ it 'should make an exact match and invert it if the argument starts with != or =!' do
56
+ (@mime =~ '!=application/x-ruby').should be_false
57
+ (@mime =~ '!=text/plain').should be_true
58
+ (@mime =~ '!=text/x-python').should be_true
59
+ (@mime =~ '=!application/x-ruby').should be_false
60
+ (@mime =~ '=!text/plain').should be_true
61
+ (@mime =~ '=!text/x-python').should be_true
62
+ end
63
+
64
+ end
65
+
66
+ describe KDE::ComboBox do
67
+
68
+ before do
69
+ @combo = KDE::ComboBox.new
70
+ @combo.add_items %w[a b c d]
71
+ end
72
+
73
+ describe '#items' do
74
+
75
+ it 'returns an array containing the items in the combo box' do
76
+ @combo.items.should == %w[a b c d]
77
+ end
78
+
79
+ end
80
+
81
+ describe '#each' do
82
+
83
+ it 'calls the block passing each item in turn if a block is given' do
84
+ m = flexmock do |mk|
85
+ %w[a b c d].each{|i| mk.should_receive(:test).once.with(i).ordered}
86
+ end
87
+ @combo.each{|i| m.test i}
88
+ end
89
+
90
+ it 'returns an enumerator whose each method passes each item in turn to the block' do
91
+ m = flexmock do |mk|
92
+ %w[a b c d].each{|i| mk.should_receive(:test).once.with(i).ordered}
93
+ end
94
+ enum = @combo.each
95
+ enum.should be_a(Enumerator)
96
+ enum.each{|i| m.test i}
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,305 @@
1
+ require 'spec/common'
2
+
3
+ require 'ktexteditor'
4
+ require 'ruber/editor/ktexteditor_wrapper'
5
+
6
+ describe Ruber::KTextEditorWrapper do
7
+
8
+ class SimpleWrapped < Qt::Object
9
+
10
+ include Ruber::KTextEditorWrapper
11
+
12
+ attr_reader :doc
13
+ def initialize
14
+ super
15
+ @doc = KTextEditor::EditorChooser.editor('katepart').create_document( self)
16
+ end
17
+
18
+ end
19
+
20
+ describe '.prepare_wrapper_connections' do
21
+
22
+ it 'takes two arguments' do
23
+ lambda{Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, {}}.should_not raise_error
24
+ end
25
+
26
+ it 'creates signals for the class given as first argument having the keys of the hash as names and the arguments obtained by rearranging the arguments of the wrapped signal as indicated in the second entry of the value' do
27
+ data = {
28
+ 'first_signal' => ['QObject*, QString', [1, 0]],
29
+ 'second_signal' => ['int, int, QObject*', [2,0,1]]
30
+ }
31
+ flexmock(SimpleWrapped).should_receive(:signals).once.with('first_signal(QString, QObject*)')
32
+ flexmock(SimpleWrapped).should_receive(:signals).once.with('second_signal(QObject*, int, int)')
33
+ Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
34
+ end
35
+
36
+ it 'replaces nil with "QObject*" in the new argument list if the class isn\'t a Qt::Widget' do
37
+ data = {
38
+ 'first_signal' => ['QObject*, QString', [1, 0, nil]],
39
+ }
40
+ flexmock(SimpleWrapped).should_receive(:signals).once.with('first_signal(QString, QObject*, QObject*)')
41
+ Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
42
+ end
43
+
44
+ it 'replaces nil with "QWidget*" in the new argument list if the class is a Qt::Widget' do
45
+ data = {
46
+ 'first_signal' => ['QObject*, QString', [1, 0, nil]],
47
+ }
48
+ flexmock(SimpleWrapped).should_receive(:ancestors).and_return [Qt::Widget, SimpleWrapped]
49
+ flexmock(SimpleWrapped).should_receive(:signals).once.with('first_signal(QString, QObject*, QWidget*)')
50
+ Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
51
+ end
52
+
53
+ it 'creates a slot in the class passed as first argument for each entry in the hash which has the same argument list as the original signal and the name given by "__emit_sig_signal", wehere sig is the signal name' do
54
+ data = {
55
+ 'first_signal' => ['QObject*, QString', [1, 0]],
56
+ 'second_signal' => ['int, int, QObject*', [2,0,1]]
57
+ }
58
+ flexmock(SimpleWrapped).should_receive(:slots).once.with('__emit_first_signal_signal(QObject*, QString)')
59
+ flexmock(SimpleWrapped).should_receive(:slots).once.with('__emit_second_signal_signal(int, int, QObject*)')
60
+ Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
61
+ end
62
+
63
+ it 'creates a method in the class with the same name passed to the slot which calls the corresponding signal using as argument those in the argument list, correctly sorted, and self where the second array in the entry has nil' do
64
+ data = {
65
+ 'first_signal' => ['QObject*, QString', [1, 0]],
66
+ 'second_signal' => ['int, int, QObject*', [2,0,1]],
67
+ 'third_signal' => ['QString, KTextEditor::Document*', [nil, 0]]
68
+ }
69
+ methods = []
70
+ methods << <<-EOS
71
+ def __emit_first_signal_signal(a0, a1)
72
+ emit first_signal(a1, a0)
73
+ end
74
+ EOS
75
+
76
+ methods << <<-EOS
77
+ def __emit_second_signal_signal(a0, a1, a2)
78
+ emit second_signal(a2, a0, a1)
79
+ end
80
+ EOS
81
+
82
+ methods << <<-EOS
83
+ def __emit_third_signal_signal(a0, a1)
84
+ emit third_signal(self, a0)
85
+ end
86
+ EOS
87
+
88
+ methods.each{|m| flexmock(SimpleWrapped).should_receive(:class_eval).once.with(m)}
89
+ Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
90
+ end
91
+
92
+ it 'returns a hash whose keys are the hash keys converted to camelcase and with the arguments added and whose entries are the names of the created slots' do
93
+ data = {
94
+ 'first_signal' => ['QObject*, QString', [1, 0]],
95
+ 'second_signal' => ['int, int, QObject*', [2,0,1]],
96
+ 'third_signal' => ['QString', [nil, 0]]
97
+ }
98
+ res = Ruber::KTextEditorWrapper.prepare_wrapper_connections SimpleWrapped, data
99
+ exp = {
100
+ 'firstSignal(QObject*, QString)' => '__emit_first_signal_signal(QObject*, QString)',
101
+ 'secondSignal(int, int, QObject*)' => '__emit_second_signal_signal(int, int, QObject*)',
102
+ 'thirdSignal(QString)' => '__emit_third_signal_signal(QString)',
103
+ }
104
+ res.should == exp
105
+ end
106
+
107
+ end
108
+
109
+ describe '#initialize_wrapper' do
110
+
111
+ before do
112
+ @w = SimpleWrapped.new
113
+ end
114
+
115
+ it 'takes two arguments' do
116
+ lambda{@w.send :initialize_wrapper, Qt::Object.new, {}}.should_not raise_error
117
+ end
118
+
119
+ it 'calls the connect_wrapped_signals method passing it the second argument' do
120
+ flexmock(@w).should_receive(:connect_wrapped_signals).once.with({'a' => 'b'})
121
+ @w.send :initialize_wrapper, Qt::Object.new, {'a' => 'b'}
122
+ end
123
+
124
+ it 'creates an interface proxy passing it the argument' do
125
+ obj = Qt::Object.new
126
+ prx = Ruber::KTextEditorWrapper::InterfaceProxy.new obj
127
+ flexmock(Ruber::KTextEditorWrapper::InterfaceProxy).should_receive(:new).once.with(obj).and_return prx
128
+ @w.send :initialize_wrapper, obj, {}
129
+ @w.instance_variable_get(:@_interface).should be_a(Ruber::KTextEditorWrapper::InterfaceProxy)
130
+ @w.instance_variable_get(:@_wrapped).should equal(obj)
131
+ end
132
+
133
+ end
134
+
135
+ describe '#internal' do
136
+
137
+ before do
138
+ @w = SimpleWrapped.new
139
+ @w.send :initialize_wrapper, @w.doc, {}
140
+ end
141
+
142
+ it 'returns the argument passed to initialize_wrapper' do
143
+ @w.send(:internal).should equal(@w.doc)
144
+ end
145
+
146
+ end
147
+
148
+
149
+ describe '#interface' do
150
+
151
+ before do
152
+ @w = SimpleWrapped.new
153
+ @w.send :initialize_wrapper, @w.doc, {}
154
+ end
155
+
156
+ it 'sets the proxy\'s interface to the argument' do
157
+ @w.interface('modification_interface')
158
+ @w.instance_variable_get(:@_interface).instance_variable_get(:@interface).should be_a(KTextEditor::ModificationInterface)
159
+ end
160
+
161
+ it 'returns the proxy' do
162
+ @w.interface('modification_interface').should be_a(Ruber::KTextEditorWrapper::InterfaceProxy)
163
+ end
164
+
165
+ end
166
+
167
+ describe '#connect_wrapped_signals' do
168
+
169
+ before do
170
+ @w = SimpleWrapped.new
171
+ def @w.connect *args
172
+ end
173
+ @w.send :initialize_wrapper, @w.doc, {}
174
+ end
175
+
176
+ it 'takes one argument' do
177
+ lambda{@w.send :connect_wrapped_signals, {}}.should_not raise_error
178
+ end
179
+
180
+ it 'calls the connect method of the wrapped object for each entry in the argument, using the wrapped object as sender and self as receiver' do
181
+ flexmock(@w).should_receive(:connect).once.with(@w.doc, SIGNAL('a'), @w, SLOT('b'))
182
+ flexmock(@w).should_receive(:connect).once.with(@w.doc, SIGNAL('c'), @w, SLOT('d'))
183
+ @w.send :connect_wrapped_signals, {'a' => 'b', 'c' => 'd'}
184
+ end
185
+
186
+ end
187
+
188
+ describe '#method_missing' do
189
+
190
+ before do
191
+ @w = SimpleWrapped.new
192
+ @w.send :initialize_wrapper, @w.doc, {}
193
+ end
194
+
195
+ it 'attempts to call the superclass method' do
196
+ @w.objectName = 'xyz'
197
+ @w.object_name.should == 'xyz'
198
+ end
199
+
200
+ it 'calls the method with the same name, arguments and block in the wrapped object if the superclass method raises NoMethodError' do
201
+ flexmock(@w.doc).should_receive(:test).with('xyz', Proc).once
202
+ @w.test('xyz'){puts 'xyz'}
203
+ end
204
+
205
+ it 'calls the method with the same name, arguments and block in the wrapped object if the superclass method raises NameError' do
206
+ lambda{@w.instance_eval("text")}.should_not raise_error
207
+ end
208
+
209
+ it 'calls the method with the same name, arguments and block in the wrapped object if the superclass method raises NotImplementedError' do
210
+ pending 'I don\'t remember when calling super causes a NotImplementedError exception, so I can\'t test this situation right now'
211
+ end
212
+
213
+ end
214
+
215
+
216
+ end
217
+
218
+ describe Ruber::KTextEditorWrapper::InterfaceProxy do
219
+
220
+ before do
221
+ @doc = KTextEditor::EditorChooser.editor('katepart').create_document(nil)
222
+ end
223
+
224
+ describe ', when created' do
225
+
226
+ it 'takes the wrapped object as argument and stores it' do
227
+ proxy = nil
228
+ lambda{proxy = Ruber::KTextEditorWrapper::InterfaceProxy.new @doc}.should_not raise_error
229
+ proxy.instance_variable_get(:@obj).should equal(@doc)
230
+ end
231
+
232
+ it 'has a nil interface' do
233
+ proxy = Ruber::KTextEditorWrapper::InterfaceProxy.new @doc
234
+ proxy.instance_variable_get(:@interface).should be_nil
235
+ end
236
+
237
+ end
238
+
239
+ describe '#interface=, when called with a string or symbol' do
240
+
241
+ before do
242
+ @proxy = Ruber::KTextEditorWrapper::InterfaceProxy.new @doc
243
+ end
244
+
245
+ it 'stores the object cast to the interface obtained from the string passed as argument' do
246
+ @proxy.interface = 'mark_interface'
247
+ @proxy.instance_variable_get(:@interface).should be_a(KTextEditor::MarkInterface)
248
+ @proxy.interface = :modification_interface
249
+ @proxy.instance_variable_get(:@interface).should be_a(KTextEditor::ModificationInterface)
250
+ end
251
+
252
+ end
253
+
254
+ describe '#interface=, when called with a class' do
255
+
256
+ before do
257
+ @proxy = Ruber::KTextEditorWrapper::InterfaceProxy.new @doc
258
+ end
259
+
260
+ it 'stores the object cast to the class given as argument' do
261
+ @proxy.interface = KTextEditor::MarkInterface
262
+ @proxy.instance_variable_get(:@interface).should be_a(KTextEditor::MarkInterface)
263
+ end
264
+
265
+ end
266
+
267
+ describe '#method_missing' do
268
+
269
+ class SimpleWrapped < Qt::Object
270
+
271
+ include Ruber::KTextEditorWrapper
272
+
273
+ attr_reader :doc
274
+ def initialize
275
+ super
276
+ @doc = KTextEditor::EditorChooser.editor('katepart').create_document( self)
277
+ initialize_wrapper @doc, {}
278
+ end
279
+
280
+ end
281
+
282
+ before do
283
+ @obj = SimpleWrapped.new
284
+ @proxy = Ruber::KTextEditorWrapper::InterfaceProxy.new @obj.doc
285
+ end
286
+
287
+ it 'calls the same method on the stored interface' do
288
+ @proxy.interface = :modification_interface
289
+ lambda{@proxy.modified_on_disk_warning = true}.should_not raise_error
290
+ flexmock(@proxy.instance_variable_get(:@interface)).should_receive(:modified_on_disk_warning=).once.with(true)
291
+ @proxy.modified_on_disk_warning = true
292
+ end
293
+
294
+ it 'replaces any argument whose class mixes-in Ruber::KTextEditorWrapper with the wrapped object' do
295
+ @proxy.interface = :modification_interface
296
+ #A method called test_method doesn't exist in the interface. However, this
297
+ #is enough to test that the @doc argument is converted to the correct class
298
+ #without my having to search for an actual method taking a document as argument
299
+ flexmock(@proxy.instance_variable_get(:@interface)).should_receive(:test_method).once.with(@obj.doc, true)
300
+ @proxy.test_method @obj, true
301
+ end
302
+
303
+ end
304
+
305
+ end
@@ -0,0 +1,1703 @@
1
+ require 'spec/common'
2
+ require 'ruber/output_widget'
3
+
4
+ describe Ruber::OutputWidget::ActionList do
5
+
6
+ before do
7
+ @list = Ruber::OutputWidget::ActionList.new
8
+ @list << 'a' << 'b' << nil << 'c' << nil << 'd' << 'e' << nil << 'f' << 'g'
9
+ end
10
+
11
+ describe '#insert_after' do
12
+
13
+ describe ', when the first argument is an integer' do
14
+
15
+ it 'inserts the entries, in order, after a number of nil entries given by the first argument' do
16
+ @list.insert_after 2, 'x', 'y'
17
+ @list.should == ['a', 'b', nil, 'c', nil, 'x', 'y', 'd', 'e', nil, 'f', 'g']
18
+ end
19
+
20
+ it 'inserts the entries in order at the end of the list if the list contains less separators than requested' do
21
+ @list.insert_after 10, 'x', 'y'
22
+ @list.should == ['a', 'b', nil, 'c', nil, 'd', 'e', nil, 'f', 'g', 'x', 'y']
23
+ end
24
+
25
+ end
26
+
27
+ describe 'when the first argument is a string' do
28
+
29
+ it 'inserts the entries, in order, after the first entry equal to the first argument' do
30
+ @list.insert_after 'd', 'x', 'y'
31
+ @list.should == ['a', 'b', nil, 'c', nil, 'd', 'x', 'y', 'e', nil, 'f', 'g']
32
+ end
33
+
34
+ it 'inserts the entries in order at the end of the list if the list doesn\'t contain the first argument' do
35
+ @list.insert_after 'z', 'x', 'y'
36
+ @list.should == ['a', 'b', nil, 'c', nil, 'd', 'e', nil, 'f', 'g', 'x', 'y']
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ describe '#insert_before' do
44
+
45
+ describe ', when the first argument is an integer' do
46
+
47
+ it 'inserts the entries, in order, before the nth nil entry, where n is the first argument' do
48
+ @list.insert_before 2, 'x', 'y'
49
+ @list.should == ['a', 'b', nil, 'c', 'x', 'y', nil, 'd', 'e', nil, 'f', 'g']
50
+ end
51
+
52
+ it 'inserts the entries in order at the end of the list if the list contains less separators than requested' do
53
+ @list.insert_before 10, 'x', 'y'
54
+ @list.should == ['a', 'b', nil, 'c', nil, 'd', 'e', nil, 'f', 'g', 'x', 'y']
55
+ end
56
+
57
+ end
58
+
59
+ describe 'when the first argument is a string' do
60
+
61
+ it 'inserts the entries, in order, before the first entry equal to the first argument' do
62
+ @list.insert_before 'd', 'x', 'y'
63
+ @list.should == ['a', 'b', nil, 'c', nil, 'x', 'y', 'd', 'e', nil, 'f', 'g']
64
+ end
65
+
66
+ it 'inserts the entries in order at the end of the list if the list doesn\'t contain the first argument' do
67
+ @list.insert_before 'z', 'x', 'y'
68
+ @list.should == ['a', 'b', nil, 'c', nil, 'd', 'e', nil, 'f', 'g', 'x', 'y']
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ describe Ruber::OutputWidget do
78
+
79
+ it 'inherits from Qt::Widget' do
80
+ Ruber::OutputWidget.ancestors.should include(Qt::Widget)
81
+ end
82
+
83
+ it 'includes the GuiStatesHandler modules' do
84
+ Ruber::OutputWidget.ancestors.should include(Ruber::GuiStatesHandler)
85
+ end
86
+
87
+ describe ', when created' do
88
+
89
+ it 'can take up to two arguments' do
90
+ lambda{Ruber::OutputWidget.new}.should_not raise_error
91
+ lambda{Ruber::OutputWidget.new Qt::Widget.new}.should_not raise_error
92
+ lambda{Ruber::OutputWidget.new Qt::Widget.new, :view => :list}.should_not raise_error
93
+ end
94
+
95
+ it 'has a grid layout' do
96
+ Ruber::OutputWidget.new.layout.should be_a(Qt::GridLayout)
97
+ end
98
+
99
+ it 'uses the object passed in the model option as model, if given' do
100
+ mod = Qt::StringListModel.new
101
+ ow = Ruber::OutputWidget.new(nil, :model => mod)
102
+ ow.model.should equal(mod)
103
+ end
104
+
105
+ it 'creates a model which is an instance of Ruber::OutputWidget::Model if the model option isn\'t given' do
106
+ ow = Ruber::OutputWidget.new
107
+ ow.model.should be_a(Ruber::OutputWidget::Model)
108
+ end
109
+
110
+ it 'makes sure the model contains at least one column' do
111
+ ow = Ruber::OutputWidget.new
112
+ ow.model.should be_a(Ruber::OutputWidget::Model)
113
+ ow.model.column_count.should >= 1
114
+ mod = Qt::StringListModel.new
115
+ ow = Ruber::OutputWidget.new nil, :model => mod
116
+ ow.model.column_count.should >= 1
117
+ mod = Qt::StringListModel.new
118
+ mod.insert_columns(0,5)
119
+ ow = Ruber::OutputWidget.new nil, :model => mod
120
+ ow.model.column_count.should >= 1
121
+ end
122
+
123
+ it 'uses the content of the view option as view, if it\'s a Qt::Widget' do
124
+ v = Qt::TreeView.new
125
+ ow = Ruber::OutputWidget.new nil, :view => v
126
+ ow.view.should be_the_same_as(v)
127
+ end
128
+
129
+ it 'takes ownership of the view, if the view option is a Qt::Widget' do
130
+ v = Qt::TreeView.new
131
+ ow = Ruber::OutputWidget.new nil, :view => v
132
+ ow.view.parent.should be_the_same_as(ow)
133
+ end
134
+
135
+ it 'creates a new instance of class Ruber::OutputWidget::ListView and uses it as view if the view option is :list or is missing' do
136
+ w = Ruber::OutputWidget.new Qt::Widget.new, :view => :list
137
+ w.view.should be_a(Ruber::OutputWidget::ListView)
138
+ w.view.parent.should equal(w)
139
+ w = Ruber::OutputWidget.new
140
+ w.view.should be_a(Ruber::OutputWidget::ListView)
141
+ end
142
+
143
+ it 'creates a new instance of class Ruber::OutputWidget::ListView and uses it as view if the view option is :tree' do
144
+ w = Ruber::OutputWidget.new Qt::Widget.new, :view => :tree
145
+ w.view.should be_a(Ruber::OutputWidget::TreeView)
146
+ w.view.parent.should equal(w)
147
+ end
148
+
149
+ it 'creates an instance of class OutputWidget::TableView with parent self and stores it in the @view instance variable if the second argument is :table' do
150
+ w = Ruber::OutputWidget.new Qt::Widget.new, :view => :table
151
+ w.view.should be_a(Ruber::OutputWidget::TableView)
152
+ w.view.parent.should equal(w)
153
+ end
154
+
155
+ it 'inserts the view in the layout at position (0,0)' do
156
+ w = Ruber::OutputWidget.new
157
+ w.layout.item_at_position(0,0).widget.should be_a(Ruber::OutputWidget::ListView)
158
+ end
159
+
160
+ it 'sets the selection mode to Extended' do
161
+ w = Ruber::OutputWidget.new
162
+ w.view.selection_mode.should == Qt::AbstractItemView::ExtendedSelection
163
+ end
164
+
165
+ it 'makes the view use the widget\'s model' do
166
+ w = Ruber::OutputWidget.new
167
+ w.view.model.should be_the_same_as(w.model)
168
+ end
169
+
170
+ it 'makes the model child of the view' do
171
+ mod = Qt::StandardItemModel.new
172
+ view = Qt::ListView.new
173
+ ow = Ruber::OutputWidget.new nil, :model => mod, :view => view
174
+ ow.model.parent.should be_the_same_as(view)
175
+ end
176
+
177
+ it 'connects the view\'s selection model\'s selectionChanged signal with its own selection_changed slot' do
178
+ ow = Ruber::OutputWidget.new
179
+ flexmock(ow).should_receive(:selection_changed).once.with(Qt::ItemSelection, Qt::ItemSelection)
180
+ ow.view.selection_model.instance_eval{emit selectionChanged(Qt::ItemSelection.new, Qt::ItemSelection.new)}
181
+ end
182
+
183
+ it 'connects the view\'s "activated(QModelIndex)" signal with its "maybe_open_file(QModelIndex)" slot' do
184
+ ow = Ruber::OutputWidget.new
185
+ ow.model.append_row Qt::StandardItem.new('x')
186
+ flexmock(ow).should_receive(:maybe_open_file).once.with(ow.model.index(0,0))
187
+ ow.view.instance_eval{emit activated(ow.model.index(0,0))}
188
+ end
189
+
190
+ it 'connects the model\'s rowsInserted signal with its own rows_changed slot' do
191
+ ow = Ruber::OutputWidget.new
192
+ flexmock(ow).should_receive(:rows_changed).once
193
+ ow.model.insertRows(0, 4)
194
+ end
195
+
196
+ it 'connects the model\'s rowsRemoved signal with its own rows_changed slot' do
197
+ ow = Ruber::OutputWidget.new
198
+ 5.times{|i| ow.model.append_row Qt::StandardItem.new(i.to_s)}
199
+ flexmock(ow).should_receive(:rows_changed).once
200
+ ow.model.removeRows(0, 4)
201
+ end
202
+
203
+ it 'connects the model\'s rowsInserted signal to the do_auto_scroll slot' do
204
+ ow = Ruber::OutputWidget.new
205
+ flexmock(ow).should_receive(:do_auto_scroll).once.with(Qt::ModelIndex.new, 0, 3)
206
+ ow.model.insertRows(0, 4)
207
+ end
208
+
209
+ it 'connects the view\'s "context_menu_requested(QPoint)" signal with its "show_menu(QPoint)" slot' do
210
+ w = Ruber::OutputWidget.new
211
+ flexmock(w).should_receive(:show_menu).once.with(Qt::Point.new(2,3))
212
+ w.view.instance_eval{emit context_menu_requested(Qt::Point.new(2,3))}
213
+ end
214
+
215
+ it 'has an empty menu' do
216
+ w = Ruber::OutputWidget.new
217
+ w.instance_variable_get(:@menu).should be_empty
218
+ end
219
+
220
+ it 'calls the initialize_states_handler method' do
221
+ w = Ruber::OutputWidget.new
222
+ w.instance_variable_get(:@gui_state_handler_states).should be_a(Hash)
223
+ w.instance_variable_get(:@gui_state_handler_handlers).should be_a(Hash)
224
+ end
225
+
226
+ it 'inserts the "copy", "copy_selected" and "clear" entries in the action list' do
227
+ w = Ruber::OutputWidget.new
228
+ w.instance_variable_get(:@action_list).should == ['copy', 'copy_selected', nil, 'clear']
229
+ end
230
+
231
+ it 'creates the actions for the "copy", "copy_selected" and "clear" entries' do
232
+ w = Ruber::OutputWidget.new
233
+ actions = w.instance_variable_get(:@actions)
234
+ actions['copy'].should be_a(KDE::Action)
235
+ actions['copy_selected'].should be_a(KDE::Action)
236
+ actions['clear'].should be_a(KDE::Action)
237
+ end
238
+
239
+ it 'connects the "copy" action\'s triggered signal with its copy slot' do
240
+ w = Ruber::OutputWidget.new
241
+ flexmock(w).should_receive(:copy).once
242
+ w.instance_variable_get(:@actions)['copy'].instance_eval{emit triggered}
243
+ end
244
+
245
+ it 'connects the "copy_selected" action\'s triggered signal with its copy_selected slot' do
246
+ w = Ruber::OutputWidget.new
247
+ flexmock(w).should_receive(:copy_selected).once
248
+ w.instance_variable_get(:@actions)['copy_selected'].instance_eval{emit triggered}
249
+ end
250
+
251
+ it 'connects the "clear" action\'s triggered signal with its clear_output slot' do
252
+ w = Ruber::OutputWidget.new
253
+ flexmock(w).should_receive(:clear_output).once
254
+ w.instance_variable_get(:@actions)['clear'].instance_eval{emit triggered}
255
+ end
256
+
257
+ it 'register handlers for the "copy", "copy_selected" and "clear" actions' do
258
+ w = Ruber::OutputWidget.new
259
+ handlers = w.instance_variable_get(:@gui_state_handler_handlers)
260
+ actions = w.instance_variable_get(:@actions)
261
+ handlers['no_text'].map(&:action).should == [actions['copy'], actions['copy_selected'], actions['clear']]
262
+ handlers['no_selection'].map(&:action).should == [actions['copy_selected']]
263
+ end
264
+
265
+ it 'creates an handler which returns true if the no_text state is false and true otherwise for the "copy" action' do
266
+ w = Ruber::OutputWidget.new
267
+ handlers = w.instance_variable_get(:@gui_state_handler_handlers)
268
+ handlers['no_text'][0].handler.call('no_text' => true).should be_false
269
+ handlers['no_text'][0].handler.call('no_text' => false).should be_true
270
+ end
271
+
272
+ it 'creates an handler which returns true only if both the no_text and no_selection states are false for the "copy_selected" action' do
273
+ w = Ruber::OutputWidget.new
274
+ handlers = w.instance_variable_get(:@gui_state_handler_handlers)
275
+ h = handlers['no_text'][1].handler
276
+ h.call('no_text' => true, 'no_selection' => true).should be_false
277
+ h.call('no_text' => false, 'no_selection' => true).should be_false
278
+ h.call('no_text' => true, 'no_selection' => false).should be_false
279
+ h.call('no_text' => false, 'no_selection' => false).should be_true
280
+ end
281
+
282
+ it 'creates an handler which returns true if the no_text state is false and true otherwise for the "clear" action' do
283
+ w = Ruber::OutputWidget.new
284
+ handlers = w.instance_variable_get(:@gui_state_handler_handlers)
285
+ handlers['no_text'][2].handler.call('no_text' => true).should be_false
286
+ handlers['no_text'][2].handler.call('no_text' => false).should be_true
287
+ end
288
+
289
+ it 'sets the "no_text" state to true' do
290
+ w = Ruber::OutputWidget.new
291
+ w.gui_state('no_text').should be_true
292
+ end
293
+
294
+ it 'sets the "no_selection" state to true' do
295
+ w = Ruber::OutputWidget.new
296
+ w.gui_state('no_selection').should be_true
297
+ end
298
+
299
+ it 'has no color registered' do
300
+ w = Ruber::OutputWidget.new
301
+ w.instance_variable_get(:@colors).should == {}
302
+ end
303
+
304
+ it 'has auto_scrolling enabled' do
305
+ w = Ruber::OutputWidget.new
306
+ w.auto_scroll.should be_true
307
+ end
308
+
309
+ it 'has the ignore_word_wrap_option attribute set to false' do
310
+ w = Ruber::OutputWidget.new
311
+ w.ignore_word_wrap_option.should be_false
312
+ end
313
+
314
+ it 'has no working dir' do
315
+ w = Ruber::OutputWidget.new
316
+ w.working_dir.should be_nil
317
+ end
318
+
319
+ it 'sets the @skip_first_file_in_title instance variable to true' do
320
+ w = Ruber::OutputWidget.new
321
+ w.skip_first_file_in_title.should be_true
322
+ end
323
+
324
+ it 'sets the @use_default_font to the value specified in opts' do
325
+ w = Ruber::OutputWidget.new nil, :use_default_font => true
326
+ w.instance_variable_get(:@use_default_font).should be_true
327
+ w = Ruber::OutputWidget.new nil
328
+ w.instance_variable_get(:@use_default_font).should be_nil
329
+ end
330
+
331
+ end
332
+
333
+ describe 'fill_menu' do
334
+
335
+ before do
336
+ @ow = Ruber::OutputWidget.new
337
+ end
338
+
339
+ it 'emits the "about_to_fill_menu()" signal' do
340
+ m = flexmock{|mk| mk.should_receive(:setup_actions).once}
341
+ @ow.connect(SIGNAL(:about_to_fill_menu)){m.setup_actions}
342
+ @ow.send :fill_menu
343
+ end
344
+
345
+ it 'inserts the actions and separators in the same order as they are in the @action_list instance variable, taking them from the @actions instance variable' do
346
+ menu = @ow.instance_variable_get(:@menu)
347
+ class << @ow
348
+ public :action_list, :actions
349
+ end
350
+ @ow.action_list.insert_before 'copy_selected', 'test1', nil, 'test2'
351
+ @ow.action_list << 'test3'
352
+ @ow.actions['test1'] = KDE::Action.new(nil)
353
+ @ow.actions['test2'] = KDE::Action.new(nil)
354
+ @ow.actions['test3'] = KDE::Action.new(nil)
355
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['copy']).once.ordered
356
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['test1']).once.ordered
357
+ flexmock(menu).should_receive(:add_separator).once.ordered
358
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['test2']).once.ordered
359
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['copy_selected']).once.ordered
360
+ flexmock(menu).should_receive(:add_separator).once.ordered
361
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['clear']).once.ordered
362
+ flexmock(menu).should_receive(:add_action).with(@ow.actions['test3']).once.ordered
363
+ @ow.send :fill_menu
364
+ end
365
+
366
+ end
367
+
368
+ describe '#show_menu' do
369
+
370
+ before do
371
+ @ow = Ruber::OutputWidget.new
372
+ end
373
+
374
+ it 'fills the menu if it is empty' do
375
+ flexmock(@ow).should_receive(:fill_menu).once
376
+ @ow.send :show_menu, Qt::Point.new(2,3)
377
+ end
378
+
379
+ it 'doesn\'t fill the menu if it isn\'t empty' do
380
+ @ow.send :fill_menu
381
+ #The following line is needed to avoid displaying the menu
382
+ flexmock(@ow.instance_variable_get(:@menu)).should_receive(:popup)
383
+ flexmock(@ow).should_receive(:fill_menu).never
384
+ @ow.send :show_menu, Qt::Point.new(2,3)
385
+ end
386
+
387
+ it 'calls the popup method of the menu, passing it the argument, after filling it' do
388
+ flexmock(@ow).should_receive(:fill_menu).once.ordered
389
+ flexmock(@ow.instance_variable_get(:@menu)).should_receive(:popup).with(Qt::Point.new(2,3)).once.ordered
390
+ @ow.send :show_menu, Qt::Point.new(2,3)
391
+ end
392
+
393
+ end
394
+
395
+ describe '#data_changed' do
396
+
397
+ before do
398
+ @ow = Ruber::OutputWidget.new
399
+ @model = @ow.model
400
+ end
401
+
402
+ it 'sets the "no_text" state to false if the model contains at least an item' do
403
+ flexmock(@model).should_receive(:row_count).once.and_return 3
404
+ @ow.send(:rows_changed)
405
+ @ow.state('no_text').should be_false
406
+ end
407
+
408
+ it 'sets the "no_text" state to true if the model contains at least an item' do
409
+ @ow.send(:rows_changed)
410
+ @ow.state('no_text').should be_true
411
+ end
412
+
413
+ end
414
+
415
+ describe '#selection_changed' do
416
+
417
+ before do
418
+ @ow = Ruber::OutputWidget.new
419
+ @model = @ow.model
420
+ 3.times{|i| @model.append_row Qt::StandardItem.new(i.to_s)}
421
+ end
422
+
423
+ it 'sets the "no_selection" state to false if the selection contains at least one item' do
424
+ sm = @ow.view.selection_model
425
+ sm.select @model.index(0,0), Qt::ItemSelectionModel::Select
426
+ @ow.send :selection_changed, Qt::ModelIndex.new, Qt::ModelIndex.new
427
+ @ow.state('no_selection').should be_false
428
+ end
429
+
430
+ it 'sets the "no_selection" state to true if the selection contains at least one item' do
431
+ sm = @ow.view.selection_model
432
+ sm.select @model.index(0,0), Qt::ItemSelectionModel::Select
433
+ sm.select @model.index(0,0), Qt::ItemSelectionModel::Deselect
434
+ @ow.send :selection_changed, Qt::ModelIndex.new, Qt::ModelIndex.new
435
+ @ow.state('no_selection').should be_true
436
+ end
437
+
438
+ end
439
+
440
+ describe '#set_color_for' do
441
+
442
+ before do
443
+ @ow = Ruber::OutputWidget.new
444
+ end
445
+
446
+ it 'stores the given color under the given name' do
447
+ @ow.set_color_for :error, Qt::Color.new(Qt.red)
448
+ @ow.instance_variable_get(:@colors)[:error].should == Qt::Color.new(255, 0, 0)
449
+ end
450
+
451
+ it 'overwrites an existing entry with the same name' do
452
+ @ow.set_color_for :error, Qt::Color.new(Qt.red)
453
+ @ow.set_color_for :error, Qt::Color.new(Qt.blue)
454
+ @ow.instance_variable_get(:@colors)[:error].should == Qt::Color.new(0, 0, 255)
455
+ end
456
+
457
+ end
458
+
459
+ describe '#scroll_to' do
460
+
461
+ before do
462
+ @ow = Ruber::OutputWidget.new
463
+ @mod = @ow.model
464
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
465
+ end
466
+
467
+ describe ', when called with a positive integer' do
468
+
469
+ it 'it scrolls the view so that the row with the argument as index is at the bottom' do
470
+ idx = @mod.index(2, 0)
471
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
472
+ @ow.scroll_to 2
473
+ end
474
+
475
+ it 'scrolls so that the last item is at the bottom if the argument is greater than the index of the last row' do
476
+ idx = @mod.index(4, 0)
477
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
478
+ @ow.scroll_to 6
479
+ end
480
+
481
+ end
482
+
483
+ describe ', when called with a negative integer' do
484
+
485
+ it 'scrolls the view so that the row with index the argument, counting from below, is at the bottom' do
486
+ idx = @mod.index(1, 0)
487
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
488
+ @ow.scroll_to -4
489
+ end
490
+
491
+ it 'scrolls so that the first item is at the bottom if the absolute value of the argument is greater than the index of the last row - 1' do
492
+ idx = @mod.index(0, 0)
493
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
494
+ @ow.scroll_to -8
495
+ end
496
+
497
+ end
498
+
499
+ describe ', when called with a Qt::ModelIndex' do
500
+
501
+ it 'scrolls the view so that the item corresponding to the index is at the bottom of the view' do
502
+ @mod.append_column(5.times.map{|i| Qt::StandardItem.new (2*i).to_s})
503
+ idx = @mod.index(2,1)
504
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
505
+ @ow.scroll_to idx
506
+ end
507
+
508
+ it 'scrolls so that the last element is at the bottom if the index is invalid' do
509
+ idx = @mod.index(4,0)
510
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
511
+ @ow.scroll_to Qt::ModelIndex.new
512
+ end
513
+
514
+ end
515
+
516
+ describe ', when called with nil' do
517
+
518
+ it 'scrolls so that the last element is at the bottom' do
519
+ idx = @mod.index(4,0)
520
+ flexmock(@ow.view).should_receive(:scroll_to).with(idx, Qt::AbstractItemView::PositionAtBottom).once
521
+ @ow.scroll_to nil
522
+ end
523
+
524
+ end
525
+
526
+ end
527
+
528
+ describe '#set_output_type' do
529
+
530
+ before do
531
+ @ow = Ruber::OutputWidget.new nil
532
+ @colors = {:message => Qt::Color.new(Qt.blue), :error => Qt::Color.new(Qt.green)}
533
+ @colors.each_pair{|k, v| @ow.set_color_for k, v}
534
+ @mod = @ow.model
535
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
536
+ end
537
+
538
+ it 'sets the foreground of the given index with the color associated with the type' do
539
+ @ow.set_output_type @mod.index(2,0), :error
540
+ @ow.model.item(2,0).foreground.color.should == @colors[:error]
541
+ end
542
+
543
+ it 'sets the role corresponding to Ruber::OutputWidget::OutputTypeRole to a string version of the type' do
544
+ @ow.set_output_type @mod.index(2,0), :error
545
+ @ow.model.item(2,0).data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'error'
546
+ end
547
+
548
+ it 'doesn\'t change the foreground if there\'s no color defined for the given type' do
549
+ color = Qt::Color.new(Qt.yellow)
550
+ @ow.model.item(2,0).foreground = Qt::Brush.new(color)
551
+ @ow.set_output_type @mod.index(2,0), :test
552
+ @ow.model.item(2,0).foreground.color.should == color
553
+ end
554
+
555
+ it 'doesn\'t change the output type if there\'s no color defined for the given type' do
556
+ @ow.model.item(2,0).set_data(Qt::Variant.new('other'), Ruber::OutputWidget::OutputTypeRole)
557
+ @ow.set_output_type @mod.index(2,0), :test
558
+ @ow.model.item(2,0).data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'other'
559
+ end
560
+
561
+ it 'returns the type if the type was changed successfully' do
562
+ @ow.set_output_type(@mod.index(2,0), :error).should == :error
563
+ end
564
+
565
+ it 'returns nil if the type wasn\'t changed successfully' do
566
+ @ow.set_output_type(@mod.index(2,0), :test).should be_nil
567
+ end
568
+
569
+ end
570
+
571
+ describe '#do_auto_scroll' do
572
+
573
+ before do
574
+ @ow = Ruber::OutputWidget.new
575
+ 5.times{|i| @ow.model.append_row Qt::StandardItem.new(i.to_s)}
576
+ end
577
+
578
+ it 'calls the scroll_to method passing the index of the model associated with the view corresponding to the last row and column 0 under the given parent, if auto scrolling is enabled' do
579
+ flexmock(@ow.view).should_receive(:model).once.and_return(@ow.model)
580
+ flexmock(@ow).should_receive(:scroll_to).once.with(@ow.model.index(3,0))
581
+ @ow.send :do_auto_scroll, Qt::ModelIndex.new, 1, 3
582
+ end
583
+
584
+ it 'does nothing if auto scrolling is disabled' do
585
+ @ow.auto_scroll = false
586
+ flexmock(@ow).should_receive(:scroll_to).never
587
+ @ow.send :do_auto_scroll, Qt::ModelIndex.new, 1, 3
588
+ end
589
+
590
+ end
591
+
592
+ describe '#with_auto_scrolling' do
593
+
594
+ before do
595
+ @ow = Ruber::OutputWidget.new
596
+ end
597
+
598
+ it 'calls the block after setting the value of the auto_scroll attribute to the argument' do
599
+ as = true
600
+ @ow.with_auto_scrolling(false){as = @ow.auto_scroll}
601
+ as.should be_false
602
+ @ow.auto_scroll = false
603
+ @ow.with_auto_scrolling(true){as = @ow.auto_scroll}
604
+ as.should be_true
605
+ end
606
+
607
+ it 'restores the value of the auto_scroll attribute after executing the block' do
608
+ @ow.with_auto_scrolling(false){}
609
+ @ow.auto_scroll.should be_true
610
+ @ow.with_auto_scrolling(true){}
611
+ @ow.auto_scroll.should be_true
612
+ @ow.auto_scroll = false
613
+ @ow.with_auto_scrolling(false){}
614
+ @ow.auto_scroll.should be_false
615
+ @ow.with_auto_scrolling(true){}
616
+ @ow.auto_scroll.should be_false
617
+ end
618
+
619
+ it 'restores the value of the auto_scroll attribute even if the block raises an exception' do
620
+ @ow.with_auto_scrolling(false){raise StandardError} rescue nil
621
+ @ow.auto_scroll.should be_true
622
+ @ow.with_auto_scrolling(true){raise StandardError} rescue nil
623
+ @ow.auto_scroll.should be_true
624
+ @ow.auto_scroll = false
625
+ @ow.with_auto_scrolling(false){raise StandardError} rescue nil
626
+ @ow.auto_scroll.should be_false
627
+ @ow.with_auto_scrolling(true){raise StandardError} rescue nil
628
+ @ow.auto_scroll.should be_false
629
+ end
630
+
631
+ end
632
+
633
+ describe '#title=' do
634
+
635
+ before do
636
+ @ow = Ruber::OutputWidget.new
637
+ @ow.set_color_for :message, Qt::Color.new(Qt.blue)
638
+ 3.times{|i| @ow.model.append_row Qt::StandardItem.new(i.to_s)}
639
+ end
640
+
641
+ it 'adds a new entry of type message at index 0, 0 if no title exists' do
642
+ old_rc = @ow.model.row_count
643
+ @ow.title = 'x'
644
+ @ow.model.row_count.should == old_rc + 1
645
+ it = @ow.model.item 0
646
+ it.text.should == 'x'
647
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
648
+ it.data(Ruber::OutputWidget::IsTitleRole).to_bool.should be_true
649
+ end
650
+
651
+ it 'replaces the old title with the new one if a title already existed' do
652
+ @ow.title = 'x'
653
+ old_rc = @ow.model.row_count
654
+ @ow.title = 'y'
655
+ @ow.model.row_count.should == old_rc
656
+ it = @ow.model.item 0
657
+ it.text.should == 'y'
658
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
659
+ it.data(Ruber::OutputWidget::IsTitleRole).to_bool.should be_true
660
+ end
661
+
662
+ end
663
+
664
+ describe '#has_title?' do
665
+
666
+ before do
667
+ @ow = Ruber::OutputWidget.new
668
+ @ow.set_color_for :message, Qt::Color.new(Qt.blue)
669
+ 3.times{|i| @ow.model.append_row Qt::StandardItem.new(i.to_s)}
670
+ end
671
+
672
+ it 'returns true if the item at row 0, column 0 has the IsTitleRole set to true' do
673
+ @ow.title = 'x'
674
+ @ow.should have_title
675
+ end
676
+
677
+ it 'returns false if the item at row 0, column 0 has the IsTitleRole set to false or unset' do
678
+ @ow.should_not have_title
679
+ @ow.model.item(0).set_data Qt::Variant.new(false), Ruber::OutputWidget::IsTitleRole
680
+ @ow.should_not have_title
681
+ end
682
+
683
+ it 'returns false if the model is empty' do
684
+ @ow.model.clear
685
+ @ow.should_not have_title
686
+ end
687
+
688
+ end
689
+
690
+ describe '#load_settings' do
691
+
692
+ before do
693
+ @colors = {
694
+ :message => Qt::Color.new(0,0,0),
695
+ :message_good => Qt::Color.new(0, 0, 255),
696
+ :message_bad => Qt::Color.new(104, 0, 104),
697
+ :output => Qt::Color.new(0, 0, 255),
698
+ :output1 => Qt::Color.new(0, 0, 150),
699
+ :output2 => Qt::Color.new(0, 255, 255),
700
+ :error => Qt::Color.new(255, 0, 0),
701
+ :error1 => Qt::Color.new(150, 0, 0),
702
+ :error2 => Qt::Color.new(255, 255, 0),
703
+ :warning => Qt::Color.new(160, 160, 164),
704
+ :warning1 => Qt::Color.new(104, 104, 104),
705
+ :warning2 => Qt::Color.new(192, 192, 192),
706
+ }
707
+ @config = flexmock do |m|
708
+ @colors.each_pair{|k, v| m.should_receive(:[]).with(:output_colors, k).and_return(v).by_default}
709
+ m.should_receive(:[]).with(:general, :wrap_output).and_return(false).by_default
710
+ m.should_receive(:[]).with(:general, :output_font).and_return(Qt::Font.new('Courier', 10)).by_default
711
+ end
712
+ flexmock(Ruber).should_receive(:[]).with(:config).and_return @config
713
+ @ow = Ruber::OutputWidget.new
714
+ end
715
+
716
+ it 'reads the colors stored in the output_colors config group' do
717
+ @ow.send :load_settings
718
+ res = @ow.instance_variable_get(:@colors)
719
+ @colors.each_pair{|k, v| res[k].should == v}
720
+ end
721
+
722
+ it 'changes the foreground role of all the entries according to the new settings' do
723
+ mod = @ow.model
724
+ @colors.each_key do |k|
725
+ it = Qt::StandardItem.new k.to_s
726
+ it.foreground = Qt::Brush.new Qt::Color.new(Qt.green)
727
+ it.set_data Qt::Variant.new(k.to_s), Ruber::OutputWidget::OutputTypeRole
728
+ mod.append_row it
729
+ end
730
+ @ow.send :load_settings
731
+ mod.row_count.times do |i|
732
+ it = mod.item i
733
+ it.foreground.color.should == @colors[it.text.to_sym]
734
+ end
735
+ end
736
+
737
+ it 'doesn\'t change items which have an unknown output type' do
738
+ mod = @ow.model
739
+ color = Qt::Color.new(123, 18, 234)
740
+ it1 = Qt::StandardItem.new 'x'
741
+ it1.set_data Qt::Variant.new('unknown'), Ruber::OutputWidget::OutputTypeRole
742
+ it1.foreground = Qt::Brush.new(color)
743
+ mod.append_row it1
744
+ it2 = Qt::StandardItem.new 'y'
745
+ it2.foreground = Qt::Brush.new(color)
746
+ mod.append_row it2
747
+ @ow.send :load_settings
748
+ it1.foreground.color.should == color
749
+ it2.foreground.color.should == color
750
+ end
751
+
752
+ it 'also changes the color of children items' do
753
+ mod = @ow.model
754
+ it1 = Qt::StandardItem.new('parent'){set_data Qt::Variant.new('error'), Ruber::OutputWidget::OutputTypeRole}
755
+ it2 = Qt::StandardItem.new('child'){set_data Qt::Variant.new('output'), Ruber::OutputWidget::OutputTypeRole}
756
+ it1.append_row it2
757
+ mod.append_row it1
758
+ @ow.send :load_settings
759
+ it1.foreground.color.should == @colors[:error]
760
+ it2.foreground.color.should == @colors[:output]
761
+ end
762
+
763
+ it 'sets the view font to the value stored in the general/output_font setting if the @use_default_font instance variable is false' do
764
+ flexmock(@ow.view).should_receive(:font=).with(Qt::Font.new('Courier', 10)).once
765
+ @ow.send :load_settings
766
+ end
767
+
768
+ it 'doesn\'t change the view font if the @use_default_font instance variable is true' do
769
+ @ow.instance_variable_set(:@use_default_font, true)
770
+ flexmock(@ow.view).should_receive(:font=).never
771
+ @ow.send :load_settings
772
+ end
773
+
774
+
775
+ it 'attempts to set the word_wrap property of the view according to the general/wrap_output setting' do
776
+ flexmock(@ow.view).should_receive(:word_wrap=).with(false).once
777
+ @ow.send :load_settings
778
+ end
779
+
780
+ it 'doesn\'t attempt to change the word_wrap property of the view if the ignore_word_wrap_option attribute is true' do
781
+ @ow.ignore_word_wrap_option = true
782
+ flexmock(@ow.view).should_receive(:word_wrap=).never
783
+ @ow.send :load_settings
784
+ end
785
+
786
+ it 'doesn\'t fail if the view doesn\'t have a word_wrap= method' do
787
+ flexmock(@ow.view).should_receive(:word_wrap=).with(false).once.and_raise(NoMethodError)
788
+ lambda{@ow.send :load_settings}.should_not raise_error
789
+ end
790
+
791
+ end
792
+
793
+ describe '#clear_output' do
794
+
795
+ it 'removes all the rows in the model' do
796
+ ow = Ruber::OutputWidget.new
797
+ mod = ow.model
798
+ 5.times{|i| mod.append_row Qt::StandardItem.new(i.to_s)}
799
+ it = mod.item(2)
800
+ it.append_row(Qt::StandardItem.new('x'))
801
+ ow.send(:clear_output)
802
+ mod.row_count.should == 0
803
+ end
804
+
805
+ end
806
+
807
+ describe '#copy' do
808
+
809
+ before do
810
+ @ow = Ruber::OutputWidget.new
811
+ @mod = @ow.model
812
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
813
+ end
814
+
815
+ it 'calls the text_for_clipboard method passing it an array containing all the indexes' do
816
+ c1 = Qt::StandardItem.new 'c1'
817
+ c2 = Qt::StandardItem.new 'c2'
818
+ c3 = Qt::StandardItem.new 'c3'
819
+ c1.append_row c3
820
+ it = @mod.item(3,0)
821
+ it.append_row c1
822
+ it.append_row c2
823
+ exp = [@mod.index(0,0), @mod.index(1,0), @mod.index(2,0), it.index, c1.index, c3.index, c2.index, @mod.index(4,0)]
824
+ flexmock(@ow).should_receive(:text_for_clipboard).once.with(exp)
825
+ @ow.send :copy
826
+ end
827
+
828
+ it 'inserts the value returned by text_for_clipboard in the clipboard' do
829
+ text = random_string
830
+ flexmock(@ow).should_receive(:text_for_clipboard).once.with(5.times.map{|i| @mod.index(i,0)}).and_return text
831
+ @ow.send :copy
832
+ KDE::Application.clipboard.text.should == text
833
+ end
834
+
835
+ end
836
+
837
+ describe '#copy_selected' do
838
+
839
+ before do
840
+ @ow = Ruber::OutputWidget.new
841
+ @mod = @ow.model
842
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
843
+ @mod.append_column 5.times.map{|i| Qt::StandardItem.new (i+5).to_s}
844
+ sm = @ow.view.selection_model
845
+ @exp = [[1,0], [2,1], [3,1]].map{|i, j| @mod.index i, j}
846
+ @exp.each{|i| sm.select i, Qt::ItemSelectionModel::Select}
847
+ end
848
+
849
+ it 'calls the text_for_clipboard method passing the list of selected items as argument' do
850
+ flexmock(@ow).should_receive(:text_for_clipboard).once.with @exp
851
+ @ow.send :copy_selected
852
+ end
853
+
854
+ it 'inserts the value returned by text_for_clipboard in the clipboard' do
855
+ text = random_string
856
+ flexmock(@ow).should_receive(:text_for_clipboard).once.with(@exp).and_return text
857
+ @ow.send :copy_selected
858
+ KDE::Application.clipboard.text.should == text
859
+ end
860
+
861
+ end
862
+
863
+ describe '#text_for_clipboard' do
864
+
865
+ before do
866
+ @ow = Ruber::OutputWidget.new
867
+ @mod = @ow.model
868
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
869
+ @mod.append_column 5.times.map{|i| Qt::StandardItem.new (i+5).to_s}
870
+ sm = @ow.view.selection_model
871
+ @exp = [[1,0], [2,1], [3,1]].map{|i, j| @mod.index i, j}
872
+ @exp.each{|i| sm.select i, Qt::ItemSelectionModel::Select}
873
+ end
874
+
875
+ it 'returns a string where the text of all the top-level items in a single row in the argument are on the same line, separated by tabs' do
876
+ text = @ow.send :text_for_clipboard, [@mod.index(0,0), @mod.index(1,1), @mod.index(1,0), @mod.index(0,1)]
877
+ text.should == "0\t5\n1\t6"
878
+ end
879
+
880
+ it 'ignores any child item' do
881
+ @mod.item(0,0).append_row Qt::StandardItem.new('c')
882
+ text = @ow.send :text_for_clipboard, [@mod.index(0,0), @mod.index(1,1), @mod.index(1,0), @mod.index(0,1), @mod.index(0,0, @mod.index(0,0))]
883
+ text.should == "0\t5\n1\t6"
884
+ end
885
+
886
+ end
887
+
888
+ describe '#maybe_open_file' do
889
+
890
+ before do
891
+ begin
892
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).and_return(0).by_default
893
+ rescue NameError
894
+ Ruber::Application = flexmock{|m| m.should_receive(:keyboard_modifiers).and_return(0).by_default}
895
+ end
896
+ @ow = Ruber::OutputWidget.new
897
+ @mod = @ow.model
898
+ @mod.append_row Qt::StandardItem.new ''
899
+ @mw = flexmock{|m| m.should_ignore_missing}
900
+ flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
901
+ end
902
+
903
+ after do
904
+ Ruber.send :remove_const, :Application unless Ruber::Application.is_a?(KDE::Application)
905
+ end
906
+
907
+ it 'calls the find_filename_in_index method passing it the index' do
908
+ flexmock(@ow).should_receive(:find_filename_in_index).once.with @mod.index(0,0)
909
+ @ow.send :maybe_open_file, @mod.index(0,0)
910
+ end
911
+
912
+ describe ', when the find_filename_in_index methods returns an array' do
913
+
914
+ before do
915
+ flexmock(@ow).should_receive(:find_filename_in_index).with(@mod.index(0,0)).and_return([__FILE__, 10]).by_default
916
+ end
917
+
918
+ it 'opens displays the file corresponding to the first entry of the array in the editor, scrolling to the line corresponding to the second entry minus 1' do
919
+ @mw.should_receive(:display_document).once.with(__FILE__, 9)
920
+ @ow.send :maybe_open_file, @mod.index(0,0)
921
+ end
922
+
923
+ it 'doesn\'t subtract 1 from the line number if it is 0' do
924
+ @mw.should_receive(:display_document).once.with(__FILE__, 0)
925
+ @ow.should_receive(:find_filename_in_index).once.and_return [__FILE__, 0]
926
+ @ow.send :maybe_open_file, @mod.index(0,0)
927
+ end
928
+
929
+ it 'hides the tool widget if the Meta key is not pressed' do
930
+ @mw.should_receive(:hide_tool).with(@ow).once
931
+ @ow.send :maybe_open_file, @mod.index(0,0)
932
+ end
933
+
934
+ it 'doesn\'t hide the tool widget if the Meta key is pressed' do
935
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return(Qt::MetaModifier.to_i)
936
+ @mw.should_receive(:hide_tool).with(@ow).never
937
+ @ow.send :maybe_open_file, @mod.index(0,0)
938
+ end
939
+
940
+ it 'does nothing if the Control and/or Shift modifiers are pressed' do
941
+ flexmock(@ow).should_receive(:find_filename_in_index).never
942
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return(Qt::ShiftModifier.to_i)
943
+ @ow.send :maybe_open_file, @mod.index(0,0)
944
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return(Qt::ControlModifier.to_i)
945
+ @ow.send :maybe_open_file, @mod.index(0,0)
946
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return((Qt::ShiftModifier|Qt::ControlModifier).to_i)
947
+ @ow.send :maybe_open_file, @mod.index(0,0)
948
+ end
949
+
950
+ it 'ignores the Control and the shift modifiers if the selection mode of the view is NoSelection' do
951
+ @ow.view.selection_mode = Qt::AbstractItemView::NoSelection
952
+ flexmock(@ow).should_receive(:find_filename_in_index).with(@mod.index(0,0)).and_return([__FILE__, 10]).times(3)
953
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return(Qt::ShiftModifier.to_i)
954
+ @ow.send :maybe_open_file, @mod.index(0,0)
955
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return(Qt::ControlModifier.to_i)
956
+ @ow.send :maybe_open_file, @mod.index(0,0)
957
+ flexmock(Ruber::Application).should_receive(:keyboard_modifiers).once.and_return((Qt::ShiftModifier|Qt::ControlModifier).to_i)
958
+ @ow.send :maybe_open_file, @mod.index(0,0)
959
+ end
960
+
961
+ end
962
+
963
+ describe ', when the find_filename_in_index methods returns nil' do
964
+
965
+ it 'does nothing' do
966
+ @mw.should_receive(:display_document).never
967
+ flexmock(@ow).should_receive(:find_filename_in_index).once.with(@mod.index(0,0)).and_return nil
968
+ @ow.send :maybe_open_file, @mod.index(0,0)
969
+ end
970
+
971
+ end
972
+
973
+ end
974
+
975
+ describe '#find_filename_in_index' do
976
+
977
+ before do
978
+ @ow = Ruber::OutputWidget.new
979
+ @mod = @ow.model
980
+ @mod.append_row Qt::StandardItem.new('')
981
+ end
982
+
983
+ it 'calls the find_filename_in_string method, passing it the text of the index, if the argument is a Qt::ModelIndex' do
984
+ @mod.item(0,0).text = __FILE__
985
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with __FILE__
986
+ @ow.send :find_filename_in_index, @mod.index(0,0)
987
+ end
988
+
989
+ it 'calls the find_filename_in_string method, passing it the argument, if the argument is a string' do
990
+ @mod.item(0,0).text = __FILE__
991
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with __FILE__
992
+ @ow.send :find_filename_in_index, __FILE__
993
+ end
994
+
995
+ it 'returns nil if find_filename_in_string returns nil' do
996
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return nil
997
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should be_nil
998
+ end
999
+
1000
+ it 'returns an array having the value returned by find_filename_in_string as first element and 0 as second if find_filename_in_string returns a string' do
1001
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return __FILE__
1002
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 0]
1003
+ end
1004
+
1005
+ it 'returns an array having the value returned by find_filename_in_string as first element and 0 as second if find_filename_in_string returns an array with one element' do
1006
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return [__FILE__]
1007
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 0]
1008
+ end
1009
+
1010
+ it 'returns the value returned by find_filename_in_string if it is an array with two elements' do
1011
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return [__FILE__, 6]
1012
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 6]
1013
+ end
1014
+
1015
+ it 'removes the first filename from the index text before passing it to find_filename_in_string if the index corresponds to the title and the @skip_first_file_in_title instance variable is true' do
1016
+ @mod.clear
1017
+ @ow.title = "/usr/bin/ruby #{__FILE__}"
1018
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with(" #{__FILE__}").and_return [__FILE__, 0]
1019
+ @ow.send :find_filename_in_index, @mod.index(0,0)
1020
+ end
1021
+
1022
+ it 'doesn\'t alter the item text before passing it to find_filename_in_string if the item is not the title' do
1023
+ @mod.item(0,0).text = "/usr/bin/ruby #{__FILE__}"
1024
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with("/usr/bin/ruby #{__FILE__}").and_return ['/usr/bin/ruby', 0]
1025
+ @ow.send :find_filename_in_index, @mod.index(0,0)
1026
+ end
1027
+
1028
+ it 'doesn\'t alter the text before passing it to find_filename_in_string if the argument is a string' do
1029
+ text = "/usr/bin/ruby #{__FILE__}"
1030
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with("/usr/bin/ruby #{__FILE__}").and_return ['/usr/bin/ruby', 0]
1031
+ @ow.send :find_filename_in_index, text
1032
+ end
1033
+
1034
+ it 'doesn\'t alter the title text before passing it to find_filename_in_string if the @skip_first_file_in_title instance variable is false' do
1035
+ @mod.clear
1036
+ @ow.title = "/usr/bin/ruby #{__FILE__}"
1037
+ @ow.skip_first_file_in_title = false
1038
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with("/usr/bin/ruby #{__FILE__}").and_return ['/usr/bin/ruby', 0]
1039
+ @ow.send :find_filename_in_index, @mod.index(0,0)
1040
+ end
1041
+
1042
+ describe ', when the string or the first element of the array returned by find_filename_in_string is not an absolute path' do
1043
+
1044
+ it 'considers the path relative to the working_dir and transforms it into an absolute path' do
1045
+ @ow.working_dir = File.dirname(__FILE__)
1046
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return [File.basename(__FILE__), 6]
1047
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return [File.basename(__FILE__)]
1048
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return File.basename(__FILE__)
1049
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 6]
1050
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 0]
1051
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should == [__FILE__, 0]
1052
+ end
1053
+
1054
+ end
1055
+
1056
+ it 'returns nil if the file doesn\'t exist' do
1057
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return '/' + random_string
1058
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should be_nil
1059
+ end
1060
+
1061
+ it 'returns nil if the file is a directory' do
1062
+ flexmock(@ow).should_receive(:find_filename_in_string).once.with('').and_return File.dirname(__FILE__)
1063
+ @ow.send(:find_filename_in_index, @mod.index(0,0)).should be_nil
1064
+ end
1065
+
1066
+ end
1067
+
1068
+ describe '#find_filename_in_string' do
1069
+
1070
+ before do
1071
+ @ow = Ruber::OutputWidget.new
1072
+ end
1073
+
1074
+ it 'recognizes an absolute path without line numbers' do
1075
+ str = random_string( 1 + rand(10))+ " #{__FILE__} " + random_string(1 + rand(10))
1076
+ res = @ow.send :find_filename_in_string, str
1077
+ res[0].should == __FILE__
1078
+ str = random_string( 1 + rand(10))+ " #{__FILE__}"
1079
+ res = @ow.send :find_filename_in_string, str
1080
+ res[0].should == __FILE__
1081
+ str = "#{__FILE__} " + random_string( 1 + rand(10))
1082
+ res = @ow.send :find_filename_in_string, str
1083
+ res[0].should == __FILE__
1084
+ end
1085
+
1086
+ it 'recognizes and expands an absolute path starting with ~/ without line numbers' do
1087
+ file = '/test/yxz.rb'
1088
+ exp = File.join ENV['HOME'], file
1089
+ str = random_string( 1 + rand(10))+ " ~#{file} " + random_string(1 + rand(10))
1090
+ res = @ow.send :find_filename_in_string, str
1091
+ res[0].should == exp
1092
+ str = random_string( 1 + rand(10))+ " ~#{file}"
1093
+ res = @ow.send :find_filename_in_string, str
1094
+ res[0].should == exp
1095
+ str = "~#{file} " + random_string( 1 + rand(10))
1096
+ res = @ow.send :find_filename_in_string, str
1097
+ res[0].should == exp
1098
+ end
1099
+
1100
+ it 'recognizes and expands an absolute path starting with ~user/ without line numbers' do
1101
+ file = '/test/yxz.rb'
1102
+ exp = File.join ENV['HOME'], file
1103
+ str = random_string( 1 + rand(10))+ " ~#{ENV['USER']}#{file} " + random_string(1 + rand(10))
1104
+ res = @ow.send :find_filename_in_string, str
1105
+ res[0].should == exp
1106
+ str = random_string( 1 + rand(10))+ " ~#{ENV['USER']}#{file}"
1107
+ res = @ow.send :find_filename_in_string, str
1108
+ res[0].should == exp
1109
+ str = "~#{ENV['USER']}#{file} " + random_string( 1 + rand(10))
1110
+ res = @ow.send :find_filename_in_string, str
1111
+ res[0].should == exp
1112
+ end
1113
+
1114
+ it 'recognizes a relative path starting with a single dot and doesn\'t expand it' do
1115
+ str = random_string( 1 + rand(10))+ " .#{__FILE__} " + random_string(1 + rand(10))
1116
+ res = @ow.send :find_filename_in_string, str
1117
+ res[0].should == '.' + __FILE__
1118
+ str = random_string( 1 + rand(10))+ " .#{__FILE__}"
1119
+ res = @ow.send :find_filename_in_string, str
1120
+ res[0].should == '.' + __FILE__
1121
+ str = ".#{__FILE__} " + random_string( 1 + rand(10))
1122
+ res = @ow.send :find_filename_in_string, str
1123
+ res[0].should == '.' + __FILE__
1124
+ end
1125
+
1126
+ it 'recognizes a relative path starting with two dots and doesn\'t expand it' do
1127
+ str = random_string( 1 + rand(10))+ " ..#{__FILE__} " + random_string(1 + rand(10))
1128
+ res = @ow.send :find_filename_in_string, str
1129
+ res[0].should == '..' + __FILE__
1130
+ str = random_string( 1 + rand(10))+ " ..#{__FILE__}"
1131
+ res = @ow.send :find_filename_in_string, str
1132
+ res[0].should == '..' + __FILE__
1133
+ str = "..#{__FILE__} " + random_string( 1 + rand(10))
1134
+ res = @ow.send :find_filename_in_string, str
1135
+ res[0].should == '..' + __FILE__
1136
+ end
1137
+
1138
+ it 'recognizes a relative path not starting with a dot but containing slashes' do
1139
+ file = "test/xyz"
1140
+ str = random_string( 1 + rand(10))+ " #{file} " + random_string(1 + rand(10))
1141
+ res = @ow.send :find_filename_in_string, str
1142
+ res[0].should == file
1143
+ str = random_string( 1 + rand(10))+ " #{file}"
1144
+ res = @ow.send :find_filename_in_string, str
1145
+ res[0].should == file
1146
+ str = "#{file} " + random_string( 1 + rand(10))
1147
+ res = @ow.send :find_filename_in_string, str
1148
+ res[0].should == file
1149
+ end
1150
+
1151
+ it 'doesn\'t recognize sequences ending with a slash' do
1152
+ strs = ["#{__FILE__}/", "~#{__FILE__}/", "~#{ENV['USER']}#{__FILE__}/", ".#{__FILE__}/", "..#{__FILE__}/"]
1153
+ strs.map!{|s| random_string(rand(10)) + ' ' + s + ' ' + random_string(rand(10))}
1154
+ strs.each{|s| res = @ow.send(:find_filename_in_string, s).should be_nil}
1155
+ end
1156
+
1157
+ it 'recognizes filenames ending in a colon followd by digits, which are interpreted as line numbers' do
1158
+ strs = ["#{__FILE__}", "~#{__FILE__}", "~#{ENV['USER']}#{__FILE__}", ".#{__FILE__}", "..#{__FILE__}"]
1159
+ strs.map!{|s| random_string(rand(10)) + ' ' + s + ":10#{rand > 0.5 ? ' ' : ''}" + random_string(rand(10))}
1160
+ @ow.send(:find_filename_in_string, strs[0]).should == [__FILE__, 10]
1161
+ @ow.send(:find_filename_in_string, strs[1]).should == [File.join(ENV['HOME'], __FILE__), 10]
1162
+ @ow.send(:find_filename_in_string, strs[2]).should == [File.join(ENV['HOME'], __FILE__), 10]
1163
+ @ow.send(:find_filename_in_string, strs[3]).should == ['.' + __FILE__, 10]
1164
+ @ow.send(:find_filename_in_string, strs[4]).should == ['..' + __FILE__, 10]
1165
+ end
1166
+
1167
+ it 'recognizes any string not containing spaces and ending in a slash followed by a colon and digits, which are interpreted as line numbers' do
1168
+ file = 'xyz'
1169
+ str = random_string( 1 + rand(10))+ " #{file}:16 " + random_string(1 + rand(10))
1170
+ res = @ow.send :find_filename_in_string, str
1171
+ res.should == [file, 16]
1172
+ str = random_string( 1 + rand(10))+ " #{file}:16"
1173
+ res = @ow.send :find_filename_in_string, str
1174
+ res.should == [file, 16]
1175
+ str = "#{file}:16 " + random_string( 1 + rand(10))
1176
+ res = @ow.send :find_filename_in_string, str
1177
+ res.should == [file, 16]
1178
+ #In the following tests, there's no space between the last digit and the following character
1179
+ str = random_string( 1 + rand(10))+ " #{file}:16" + random_string(1 + rand(10))
1180
+ res = @ow.send :find_filename_in_string, str
1181
+ res.should == [file, 16]
1182
+ str = "#{file}:16" + random_string( 1 + rand(10))
1183
+ res = @ow.send :find_filename_in_string, str
1184
+ res.should == [file, 16]
1185
+ end
1186
+
1187
+ it 'recognizes the file names enclosed in quotes, double quotes, backticks, all brackets and angular brackets' do
1188
+ quotes = %w|' " ` ( [ { < |
1189
+ quotes.each do |q|
1190
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "#{__FILE__}").should == [__FILE__]
1191
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "~#{__FILE__}").should == [File.join(ENV['HOME'], __FILE__)]
1192
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "~#{ENV['USER']}#{__FILE__}").should == [File.join(ENV['HOME'], __FILE__)]
1193
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + ".#{__FILE__}").should == [File.join('.', __FILE__)]
1194
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "..#{__FILE__}").should == [File.join('..', __FILE__)]
1195
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "abc/xyz").should == ['abc/xyz']
1196
+ @ow.send(:find_filename_in_string, random_string( 1 + rand(10))+ ' ' + q + "abc:12").should == ['abc', 12]
1197
+ end
1198
+ end
1199
+
1200
+ it 'only considers the first match' do
1201
+ str = "#{__FILE__.upcase} #{__FILE__}"
1202
+ @ow.send(:find_filename_in_string, str).should == [__FILE__.upcase]
1203
+ end
1204
+
1205
+ end
1206
+
1207
+ describe '#keyReleaseEvent' do
1208
+
1209
+ before do
1210
+ @ow = Ruber::OutputWidget.new
1211
+ @mw = flexmock('main window'){|m| m.should_ignore_missing}
1212
+ @ev = Qt::KeyEvent.new Qt::Event::KeyRelease, Qt::Key_A, Qt::NoModifier, 'a'
1213
+ flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
1214
+ end
1215
+
1216
+ it 'gives focus to the current editor' do
1217
+ ed = flexmock('editor'){|m| m.should_receive(:set_focus).once}
1218
+ ed.should_ignore_missing
1219
+ @mw.should_receive(:active_editor).once.and_return ed
1220
+ @ow.send :keyReleaseEvent, @ev
1221
+ end
1222
+
1223
+ # it 'inserts the text corresponding to the released key in the editor' do
1224
+ # ed = flexmock('editor'){|m| m.should_receive(:insert_text).once.with('a')}
1225
+ # ed.should_ignore_missing
1226
+ # @mw.should_receive(:active_editor).once.and_return ed
1227
+ # @ow.send :keyReleaseEvent, @ev
1228
+ # end
1229
+
1230
+ it 'does nothing if there\'s no active editor' do
1231
+ @mw.should_receive(:active_editor).once.and_return nil
1232
+ lambda{@ow.send :keyReleaseEvent, @ev}.should_not raise_error
1233
+ end
1234
+
1235
+ it 'returns nil' do
1236
+ # ed = flexmock('editor'){|m| m.should_receive(:insert_text).once.with('a')}
1237
+ ed = flexmock('editor'){|m| m.should_ignore_missing}
1238
+ @mw.should_receive(:active_editor).once.and_return ed
1239
+ @mw.should_receive(:active_editor).once.and_return nil
1240
+ @ow.send(:keyReleaseEvent, @ev).should be_nil
1241
+ @ow.send(:keyReleaseEvent, @ev).should be_nil
1242
+ end
1243
+
1244
+ end
1245
+
1246
+ end
1247
+
1248
+ describe Ruber::OutputWidget::Model do
1249
+
1250
+ before do
1251
+ @ow = Ruber::OutputWidget.new
1252
+ end
1253
+
1254
+ it 'inherits from Qt::StandardItemModel' do
1255
+ Ruber::OutputWidget::Model.ancestors.should include(Qt::StandardItemModel)
1256
+ end
1257
+
1258
+ describe ', when created' do
1259
+
1260
+ it 'can take one or two parameters' do
1261
+ lambda{Ruber::OutputWidget::Model.new @ow}.should_not raise_error
1262
+ lambda{Ruber::OutputWidget::Model.new @ow, Qt::Object.new}.should_not raise_error
1263
+ end
1264
+
1265
+ it 'stores the first argument in the "@output_widget" instance variable' do
1266
+ mod = Ruber::OutputWidget::Model.new @ow
1267
+ mod.instance_variable_get(:@output_widget).should be_the_same_as(@ow)
1268
+ end
1269
+
1270
+ it 'uses the second argument (or nil) as parent' do
1271
+ mod = Ruber::OutputWidget::Model.new @ow
1272
+ mod.parent.should be_nil
1273
+ w = Qt::Widget.new
1274
+ mod = Ruber::OutputWidget::Model.new @ow, w
1275
+ mod.parent.should be_the_same_as(w)
1276
+ end
1277
+
1278
+ it 'sets the @global_flags instance variable to Qt::ItemIsEnabled | Qt::ItemIsSelectable converted to an integer' do
1279
+ mod = Ruber::OutputWidget::Model.new @ow
1280
+ mod.instance_variable_get(:@global_flags).should == (Qt::ItemIsEnabled | Qt::ItemIsSelectable).to_i
1281
+ end
1282
+
1283
+ end
1284
+
1285
+ describe '#global_flags=' do
1286
+
1287
+ before do
1288
+ @mod = Ruber::OutputWidget::Model.new @ow
1289
+ end
1290
+
1291
+ it 'sets the @global_flags instance variable to the argument converted to an integer' do
1292
+ @mod.global_flags = Qt::ItemIsEnabled | Qt::ItemIsUserCheckable
1293
+ @mod.instance_variable_get(:@global_flags).should == (Qt::ItemIsEnabled | Qt::ItemIsUserCheckable).to_i
1294
+ end
1295
+
1296
+ it 'doesn\'t attempt to convert the value to an integer if it\'s nil' do
1297
+ @mod.global_flags = nil
1298
+ @mod.instance_variable_get(:@global_flags).should be_nil
1299
+ end
1300
+
1301
+ end
1302
+
1303
+ describe '#flags' do
1304
+
1305
+ before do
1306
+ @mod = @ow.model
1307
+ end
1308
+
1309
+ it 'returns the value specified in the @flags variable if the index is valid and the global_flags attribute is not nil' do
1310
+ flags = Qt::ItemIsEnabled | Qt::ItemIsUserCheckable
1311
+ @mod.global_flags = flags
1312
+ @mod.append_row Qt::StandardItem.new('x')
1313
+ @mod.flags(@mod.index(0,0)).should == flags.to_i
1314
+ end
1315
+
1316
+ it 'returns Qt::NoItemFlags if the inxed is not valid and the global_flags attribute is not nil' do
1317
+ flags = Qt::ItemIsEnabled | Qt::ItemIsUserCheckable
1318
+ @mod.global_flags = flags
1319
+ @mod.append_row Qt::StandardItem.new('x')
1320
+ @mod.flags(Qt::ModelIndex.new).should == Qt::NoItemFlags.to_i
1321
+ end
1322
+
1323
+ it 'calls super if the global_flags attribute is nil' do
1324
+ @mod.global_flags = nil
1325
+ it = Qt::StandardItem.new('x')
1326
+ flags = Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsDragEnabled
1327
+ it.flags = flags
1328
+ @mod.append_row it
1329
+ @mod.flags(it.index).to_i.should == flags.to_i
1330
+ @mod.flags(Qt::ModelIndex.new).to_i.should == Qt::ItemIsDropEnabled.to_i
1331
+ end
1332
+
1333
+ end
1334
+
1335
+ describe '#set' do
1336
+
1337
+ before do
1338
+ @ow = Ruber::OutputWidget.new
1339
+ @mod = @ow.model
1340
+ end
1341
+
1342
+ it 'takes three or four arguments' do
1343
+ lambda{@mod.set 'test', :message, 3}.should_not raise_error
1344
+ lambda{@mod.set 'test', :message, 3, {}}.should_not raise_error
1345
+ end
1346
+
1347
+ it 'creates a new item having the first argument as text and passes it to set_item using the third argument as row and 0 as column if no optional argument are given' do
1348
+ @mod.set 'test', :message, 3
1349
+ @mod.item(3,0).text.should == 'test'
1350
+ flexmock(@mod).should_receive(:set_item).once.with(6, 0, FlexMock.on{|i| i.text == 'test'})
1351
+ @mod.set 'test', :message, 6
1352
+ end
1353
+
1354
+ it 'creates a new item having the first argument as text and passes it to set_item using the third argument as row and the col option as column only the col optional argument is given' do
1355
+ @mod.set 'test', :message, 3, :col => 5
1356
+ @mod.item(3,5).text.should == 'test'
1357
+ flexmock(@mod).should_receive(:set_item).once.with(6, 5, FlexMock.on{|i| i.text == 'test'})
1358
+ @mod.set 'test', :message, 6, :col => 5
1359
+ end
1360
+
1361
+ it 'creates a new item having the first argument as text and passes it to the set_child method of the given parent, using the given row (and column, if given) if the parent option is given' do
1362
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1363
+ @mod.set 'test', :message, 3, :parent => @mod.item(2)
1364
+ @mod.item(2, 0).child(3, 0).text.should == 'test'
1365
+ @mod.set 'TEST', :message, 4, :parent => @mod.item(1), :col => 3
1366
+ @mod.item(1, 0).child(4, 3).text.should == 'TEST'
1367
+ flexmock(@mod.item(4)).should_receive(:set_child).once.with(5, 0, FlexMock.on{|i| i.text == 'Test'})
1368
+ flexmock(@mod.item(0)).should_receive(:set_child).once.with(2, 4, FlexMock.on{|i| i.text == 'Test'})
1369
+ @mod.set 'Test', :message, 5, :parent => @mod.item(4,0)
1370
+ @mod.set 'Test', :message, 2, :col => 4, :parent => @mod.item(0,0)
1371
+ end
1372
+
1373
+ it 'calls the set_output_type method of the output widget passing it the index of the item and the type argument' do
1374
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1375
+ flexmock(@ow).should_receive(:set_output_type).once.with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.row == 3 and i.column == 5}, :message)
1376
+ @mod.set 'text', :message, 3, :col => 5
1377
+ end
1378
+
1379
+ it 'counts rows and columns backwards if negative' do
1380
+ flexmock(@mod).should_receive(:row_count).and_return(7)
1381
+ flexmock(@mod).should_receive(:column_count).and_return(5)
1382
+ flexmock(@mod).should_receive(:set_item).with(2, 0, Qt::StandardItem).once
1383
+ flexmock(@mod).should_receive(:set_item).with(1, 3, Qt::StandardItem).once
1384
+ @mod.set 'test', :message, -5
1385
+ @mod.set 'test', :message, -6, :col => -2
1386
+
1387
+ it = Qt::StandardItem.new 'x'
1388
+ @mod.append_row it
1389
+ flexmock(it).should_receive(:row_count).and_return(7)
1390
+ flexmock(it).should_receive(:column_count).and_return(5)
1391
+ flexmock(it).should_receive(:set_child).with(2, 0, Qt::StandardItem).once
1392
+ flexmock(it).should_receive(:set_child).with(1, 3, Qt::StandardItem).once
1393
+ @mod.set 'test', :message, -5, :parent => it
1394
+ @mod.set 'test', :message, -6, :col => -2, :parent => it
1395
+ end
1396
+
1397
+ it 'returns the new item' do
1398
+ it = @mod.set('text', :message, 3, :col => 5)
1399
+ it.should be_a(Qt::StandardItem)
1400
+ it.text.should == 'text'
1401
+ it.row.should == 3
1402
+ it.column.should == 5
1403
+ end
1404
+
1405
+ end
1406
+
1407
+ describe '#insert' do
1408
+
1409
+ before do
1410
+ @ow = Ruber::OutputWidget.new
1411
+ @mod = @ow.model
1412
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1413
+ end
1414
+
1415
+ it 'takes three or four arguments' do
1416
+ lambda{@mod.insert ['test'], :message, 3}.should_not raise_error
1417
+ lambda{@mod.insert ['test'], :message, 3, {}}.should_not raise_error
1418
+ end
1419
+
1420
+ describe ', when the first argument is an array' do
1421
+
1422
+ it 'creates a row from the array by replacing nil entries with invalid Qt::StandardItem and string entries with Qt::StandardItems with the strings as title and inserts it in the row given as third argument if no optional argument is given' do
1423
+ text = ['x', nil, nil, 'y', nil ]
1424
+ flexmock(@mod).should_receive(:insert_row).with(3, FlexMock.on{|a| a[0].text == 'x' and a[1].text.nil? and a[2].text.nil? and a[3].text == 'y' and a[4].text.nil?}).once
1425
+ @mod.insert text, :message, 3
1426
+ end
1427
+
1428
+ it 'inserts the items as children of the item given in the :parent option, if given' do
1429
+ text = ['x', nil, nil, 'y', nil ]
1430
+ it = @mod.item(2,0)
1431
+ flexmock(it).should_receive(:insert_row).with(3, FlexMock.on{|a| a[0].text == 'x' and a[1].text.nil? and a[2].text.nil? and a[3].text == 'y' and a[4].text.nil?}).once
1432
+ 3.times{it.append_row []}
1433
+ @mod.insert text, :message, 3, :parent => it
1434
+ end
1435
+
1436
+ it 'calls the output widget\'s set_output_type for each valid item passing the second argument if the second argument is a symbol' do
1437
+ text = ['x', nil, nil, 'y', nil ]
1438
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'x'}, :error).once
1439
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'y'}, :error).once
1440
+ @mod.insert text, :error, 3
1441
+ end
1442
+
1443
+ it 'calls the output widget\'s set_output_type for each valid item passing the corresponding item in the second argument if the second argument is an array' do
1444
+ text = ['x', nil, nil, 'y', nil ]
1445
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'x'}, :error).once
1446
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'y'}, :error1).once
1447
+ @mod.insert text, [:error, :error1], 3
1448
+ end
1449
+
1450
+ it 'returns an array with the items corresponding to the strings in the argument' do
1451
+ text = ['x', nil, nil, 'y', nil ]
1452
+ res = @mod.insert text, :error, 3
1453
+ res.should == [@mod.item(3,0), @mod.item(3,3)]
1454
+ end
1455
+
1456
+ end
1457
+
1458
+ describe ', when the first argument is a string' do
1459
+
1460
+ it 'inserts a row having the given text as first column row at the given position if no optional argument is given' do
1461
+ flexmock(@mod).should_receive(:insert_row).with(3, FlexMock.on{|a| a.size == 1 and a[0].is_a?(Qt::StandardItem) and a[0].text == 'x'}).once
1462
+ @mod.insert 'x', :message, 3
1463
+ end
1464
+
1465
+
1466
+ it 'inserts a row having the given text as the given column and all the previous elements empty at the given position if the col optional argument is given' do
1467
+ flexmock(@mod).should_receive(:insert_row).with(3, FlexMock.on{|a| a.size == 4 and a[0].text.nil? and a[1].text.nil? and a[2].text.nil? and a[3].is_a?(Qt::StandardItem) and a[3].text == 'x'}).once
1468
+ 3.times{@mod.append_column []}
1469
+ @mod.insert 'x', :message, 3, :col => 3
1470
+ end
1471
+
1472
+ it 'inserts the new row under the given parent if the :parent optional argument is given' do
1473
+ it = @mod.item(2,0)
1474
+ flexmock(it).should_receive(:insert_row).with(3, FlexMock.on{|a| a.size == 4 and a[0].text.nil? and a[1].text.nil? and a[2].text.nil? and a[3].is_a?(Qt::StandardItem) and a[3].text == 'x'}).once
1475
+ 3.times{it.append_row []}
1476
+ 3.times{it.append_column []}
1477
+ @mod.insert 'x', :message, 3, :col => 3, :parent => it
1478
+ end
1479
+
1480
+ it 'calls the output widget\'s set_output_type for the new item passing the second argument if the second argument is a symbol' do
1481
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'x'}, :error).once
1482
+ @mod.insert 'x', :error, 3
1483
+ end
1484
+
1485
+ it 'calls the output widget\'s set_output_type for the new item passing the first item in the second argument if the second argument is an array' do
1486
+ flexmock(@ow).should_receive(:set_output_type).with(FlexMock.on{|i| i.is_a?(Qt::ModelIndex) and i.data.to_string == 'x'}, :error).once
1487
+ @mod.insert 'x', [:error, :error1], 3
1488
+ end
1489
+
1490
+ it 'returns an array with the items corresponding to the strings in the argument' do
1491
+ res = @mod.insert 'x', :error, 3
1492
+ res.should == [@mod.item(3,0)]
1493
+ end
1494
+
1495
+ end
1496
+
1497
+ it 'counts rows and columns backwards if negative ' do
1498
+ @mod.clear
1499
+ 10.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1500
+ @mod.insert 'x', :message, -3
1501
+ @mod.item(7,0).text.should == 'x'
1502
+
1503
+ @mod.clear
1504
+ 10.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1505
+ 4.times{|i| @mod.append_column []}
1506
+ @mod.insert 'x', :message, -3, :col => -3
1507
+ @mod.item(7,2).text.should == 'x'
1508
+
1509
+ @mod.clear
1510
+ @mod.append_row [Qt::StandardItem.new('p'), Qt::StandardItem.new('x')]
1511
+ it = @mod.item 0,0
1512
+ 10.times{|i| it.append_row Qt::StandardItem.new(i.to_s)}
1513
+ @mod.insert 'x', :message, -3, :parent => it
1514
+ it.child(7,0).text.should == 'x'
1515
+
1516
+ @mod.clear
1517
+ @mod.append_row [Qt::StandardItem.new('p'), Qt::StandardItem.new('x')]
1518
+ it = @mod.item 0,0
1519
+ 10.times{|i| it.append_row Qt::StandardItem.new(i.to_s)}
1520
+ 4.times{|i| it.append_column []}
1521
+ @mod.insert 'x', :message, -3, :parent => it, :col => -3
1522
+ it.child(7,2).text.should == 'x'
1523
+ end
1524
+
1525
+ it 'considers the row to be equal to row_count if the third argument is nil' do
1526
+ @mod.insert 'x', :message, nil
1527
+ @mod.item(@mod.row_count - 1,0).text.should == 'x'
1528
+ end
1529
+
1530
+ it 'always inserts a new row and never changes an existing one' do
1531
+ rc = @mod.row_count
1532
+ @mod.insert 'x', :message, 3
1533
+ @mod.row_count.should == rc + 1
1534
+ @mod.item(3,0).text.should == 'x'
1535
+ @mod.item(4,0).text.should == '3'
1536
+ end
1537
+
1538
+ it 'raises IndexError if the specified row is greater than the row_count of the parent or is less than the opposite of that number' do
1539
+ lambda{@mod.insert 'x', :message, 15}.should raise_error(IndexError, "Row index 15 is out of range. The allowed values are from 0 to 5")
1540
+ lambda{@mod.insert 'x', :message, -15}.should raise_error(IndexError, "Row index -10 is out of range. The allowed values are from 0 to 5")
1541
+ end
1542
+
1543
+ end
1544
+
1545
+ describe '#insert_lines' do
1546
+
1547
+ before do
1548
+ @ow = Ruber::OutputWidget.new
1549
+ @color = Qt::Color.new(0,0,255)
1550
+ @ow.set_color_for :message, @color
1551
+ @mod = @ow.model
1552
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1553
+ end
1554
+
1555
+ it 'inserts each line of the text as a separate item (one below the other), using the #insert method' do
1556
+ text = "a\nb\nc"
1557
+ lines = %w[a b c]
1558
+
1559
+ @mod.insert_lines text, :message, 2
1560
+ lines.each_with_index do |l, i|
1561
+ it = @mod.item(2+i)
1562
+ it.text.should == l
1563
+ it.foreground.color.should == @color
1564
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
1565
+ end
1566
+
1567
+ @mod.clear
1568
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1569
+ @mod.insert_lines text, :message, 2, :col => 3
1570
+ lines.each_with_index do |l, i|
1571
+ it = @mod.item(2+i, 3)
1572
+ it.text.should == l
1573
+ it.foreground.color.should == @color
1574
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
1575
+ end
1576
+
1577
+ @mod.clear
1578
+ 5.times{|i| @mod.append_row Qt::StandardItem.new(i.to_s)}
1579
+ @mod.item(1).insert_columns(0,3)
1580
+ @mod.item(1).insert_rows(0,2)
1581
+ @mod.insert_lines text, :message, 2, :col => 3, :parent => @mod.item(1)
1582
+ lines.each_with_index do |l, i|
1583
+ it = (@mod.item(1)).child(2+i, 3)
1584
+ it.text.should == l
1585
+ it.foreground.color.should == @color
1586
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
1587
+ end
1588
+
1589
+ end
1590
+
1591
+ it 'counts lines and columns backwards if they\'re negative' do
1592
+ text = "a\nb\nc"
1593
+ flexmock(@mod).should_receive(:insert).with('a', :message, -5, :col => -2).once
1594
+ flexmock(@mod).should_receive(:insert).with('b', :message, -4, :col => -2).once
1595
+ flexmock(@mod).should_receive(:insert).with('c', :message, -3, :col => -2).once
1596
+ @mod.insert_lines text, :message, -5, :col => -2
1597
+
1598
+ it = Qt::StandardItem.new 'x'
1599
+ @mod.append_row it
1600
+ flexmock(@mod).should_receive(:insert).with('a', :message, -5, :col => -2, :parent => it).once
1601
+ flexmock(@mod).should_receive(:insert).with('b', :message, -4, :col => -2, :parent => it).once
1602
+ flexmock(@mod).should_receive(:insert).with('c', :message, -3, :col => -2, :parent => it).once
1603
+ @mod.insert_lines text, :message, -5, :col => -2, :parent => it
1604
+ end
1605
+
1606
+ it 'appends the rows at the and if the third argument is nil' do
1607
+ text = "a\nb\nc"
1608
+ flexmock(@mod).should_receive(:insert).with('a', :message, nil,{}).once
1609
+ flexmock(@mod).should_receive(:insert).with('b', :message, nil, {}).once
1610
+ flexmock(@mod).should_receive(:insert).with('c', :message, nil, {}).once
1611
+ @mod.insert_lines text, :message, nil
1612
+
1613
+ it = Qt::StandardItem.new 'x'
1614
+ @mod.append_row it
1615
+ flexmock(@mod).should_receive(:insert).with('a', :message, nil, :parent => it).once
1616
+ flexmock(@mod).should_receive(:insert).with('b', :message, nil, :parent => it).once
1617
+ flexmock(@mod).should_receive(:insert).with('c', :message, nil, :parent => it).once
1618
+ @mod.insert_lines text, :message, nil, :parent => it
1619
+
1620
+ end
1621
+
1622
+ describe 'if the first argument is an array' do
1623
+
1624
+ it 'inserts each entry as a separate item (one below the other), using the #insert method' do
1625
+ text = %w[a b c]
1626
+ @mod.insert_lines text, :message, 2
1627
+ lines = %w[a b c]
1628
+ lines.each_with_index do |l, i|
1629
+ it = @mod.item(2+i)
1630
+ it.text.should == l
1631
+ it.foreground.color.should == @color
1632
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
1633
+ end
1634
+ end
1635
+
1636
+ it 'doesn\'t attempt to separate an entry into lines' do
1637
+ text = %w[a\n b\n c]
1638
+ @mod.insert_lines text, :message, 2
1639
+ lines = %w[a\n b\n c]
1640
+ lines.each_with_index do |l, i|
1641
+ it = @mod.item(2+i)
1642
+ it.text.should == l
1643
+ it.foreground.color.should == @color
1644
+ it.data(Ruber::OutputWidget::OutputTypeRole).to_string.should == 'message'
1645
+ end
1646
+ end
1647
+
1648
+ end
1649
+
1650
+ end
1651
+
1652
+ end
1653
+
1654
+ describe Ruber::OutputWidget::ListView do
1655
+
1656
+ describe '#contextMenuEvent' do
1657
+
1658
+ it 'emits the "context_menu_requested(QPoint)" signal' do
1659
+ e = Qt::ContextMenuEvent.new Qt::ContextMenuEvent::Other, Qt::Point.new(1,2)
1660
+ flexmock(e).should_receive(:global_pos).once.and_return Qt::Point.new(2,3)
1661
+ view = Ruber::OutputWidget::ListView.new
1662
+ m = flexmock{|mk| mk.should_receive(:test).once.with(Qt::Point.new(2,3))}
1663
+ view.connect(SIGNAL('context_menu_requested(QPoint)')){|pt| m.test pt}
1664
+ view.send :contextMenuEvent, e
1665
+ end
1666
+
1667
+ end
1668
+
1669
+ end
1670
+
1671
+ describe Ruber::OutputWidget::TreeView do
1672
+
1673
+ describe '#contextMenuEvent' do
1674
+
1675
+ it 'emits the "context_menu_requested(QPoint)" signal' do
1676
+ e = Qt::ContextMenuEvent.new Qt::ContextMenuEvent::Other, Qt::Point.new(1,2)
1677
+ flexmock(e).should_receive(:global_pos).once.and_return Qt::Point.new(2,3)
1678
+ view = Ruber::OutputWidget::TreeView.new
1679
+ m = flexmock{|mk| mk.should_receive(:test).once.with(Qt::Point.new(2,3))}
1680
+ view.connect(SIGNAL('context_menu_requested(QPoint)')){|pt| m.test pt}
1681
+ view.send :contextMenuEvent, e
1682
+ end
1683
+
1684
+ end
1685
+
1686
+ end
1687
+
1688
+ describe Ruber::OutputWidget::TableView do
1689
+
1690
+ describe '#contextMenuEvent' do
1691
+
1692
+ it 'emits the "context_menu_requested(QPoint)" signal' do
1693
+ e = Qt::ContextMenuEvent.new Qt::ContextMenuEvent::Other, Qt::Point.new(1,2)
1694
+ view = Ruber::OutputWidget::TableView.new
1695
+ flexmock(e).should_receive(:global_pos).once.and_return Qt::Point.new(2,3)
1696
+ m = flexmock{|mk| mk.should_receive(:test).once.with(Qt::Point.new(2,3))}
1697
+ view.connect(SIGNAL('context_menu_requested(QPoint)')){|pt| m.test pt}
1698
+ view.send :contextMenuEvent, e
1699
+ end
1700
+
1701
+ end
1702
+
1703
+ end