ruber 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +42 -1
- data/lib/ruber/application/application.rb +25 -5
- data/lib/ruber/application/plugin.yaml +2 -10
- data/lib/ruber/component_manager.rb +2 -2
- data/lib/ruber/document_project.rb +5 -3
- data/lib/ruber/editor/document.rb +5 -4
- data/lib/ruber/editor/ktexteditor_wrapper.rb +1 -1
- data/lib/ruber/exception_widgets.rb +1 -1
- data/lib/ruber/main_window/main_window.rb +4 -3
- data/lib/ruber/main_window/main_window_actions.rb +2 -2
- data/lib/ruber/main_window/main_window_internal.rb +1 -1
- data/lib/ruber/output_widget.rb +17 -5
- data/lib/ruber/project.rb +34 -3
- data/lib/ruber/project_dir_scanner.rb +171 -0
- data/lib/ruber/settings_container.rb +7 -7
- data/lib/ruber/settings_dialog.rb +24 -24
- data/lib/ruber/version.rb +1 -1
- data/lib/ruber/world/environment.rb +1 -0
- data/lib/ruber/world/plugin.yaml +7 -2
- data/lib/ruber/{application → world}/project_files_widget.rb +0 -0
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.ui +0 -0
- data/lib/ruber/{application → world}/ui/project_files_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_widget.ui +0 -0
- data/plugins/auto_end/auto_end.rb +21 -18
- data/plugins/autosave/autosave.rb +1 -1
- data/plugins/find_in_files/find_in_files.rb +1 -1
- data/plugins/irb/irb.png +0 -0
- data/plugins/irb/irb.rb +142 -0
- data/plugins/irb/irb.svg +240 -0
- data/plugins/irb/irb_controller.rb +541 -0
- data/plugins/irb/irbrc.rb +21 -0
- data/plugins/irb/plugin.yaml +19 -0
- data/plugins/irb/ui/irb_config_widget.rb +151 -0
- data/plugins/irb/ui/irb_config_widget.ui +123 -0
- data/plugins/irb/ui/irb_tool_widget.rb +97 -0
- data/plugins/irb/ui/irb_tool_widget.ui +86 -0
- data/plugins/project_browser/project_browser.rb +1 -1
- data/plugins/rspec/plugin.yaml +6 -3
- data/plugins/rspec/rspec.rb +172 -473
- data/plugins/rspec/tool_widget.rb +462 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +58 -38
- data/plugins/rspec/ui/rspec_project_widget.ui +68 -64
- data/plugins/ruberri/class_formatter.rb +126 -0
- data/plugins/ruberri/method_formatter.rb +90 -0
- data/plugins/ruberri/plugin.yaml +13 -0
- data/plugins/ruberri/ruberri.rb +226 -0
- data/plugins/ruberri/search.rb +111 -0
- data/plugins/ruberri/ui/tool_widget.rb +73 -0
- data/plugins/ruberri/ui/tool_widget.ui +49 -0
- data/plugins/ruby_runner/ruby_runner.rb +2 -2
- data/plugins/ruby_syntax_checker/plugin.yaml +11 -0
- data/plugins/ruby_syntax_checker/ruby_syntax_checker.rb +147 -0
- data/plugins/syntax_checker/plugin.yaml +10 -6
- data/plugins/syntax_checker/syntax_checker.rb +216 -520
- data/plugins/syntax_checker/ui/config_widget.rb +61 -0
- data/plugins/syntax_checker/ui/config_widget.ui +44 -0
- data/plugins/yaml_syntax_checker/plugin.yaml +11 -0
- data/plugins/yaml_syntax_checker/yaml_syntax_checker.rb +62 -0
- data/ruber.desktop +0 -0
- data/spec/auto_end_spec.rb +224 -186
- data/spec/document_project_spec.rb +9 -1
- data/spec/document_spec.rb +9 -0
- data/spec/environment_spec.rb +12 -0
- data/spec/output_widget_spec.rb +69 -2
- data/spec/project_dir_scanner_spec.rb +195 -0
- data/spec/project_spec.rb +43 -73
- data/spec/ruby_syntax_checker_spec.rb +361 -0
- data/spec/syntax_checker_spec.rb +1132 -0
- data/spec/yaml_syntax_checker_spec.rb +130 -0
- metadata +232 -225
- data/lib/ruber/application/project_files_list.rb +0 -320
- data/spec/project_files_list_spec.rb +0 -411
@@ -0,0 +1,462 @@
|
|
1
|
+
module Ruber
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
Filter model used by the RSpec output widget
|
7
|
+
|
8
|
+
It allows to choose whether to accept items corresponding to output to standard error or to reject
|
9
|
+
it. To find out if a given item corresponds to the output of standard error or
|
10
|
+
standard output, this model uses the data contained in a custom role in the output.
|
11
|
+
The index of this role is {RSpec::OutputWidget::OutputTypeRole}.
|
12
|
+
=end
|
13
|
+
class FilterModel < FilteredOutputWidget::FilterModel
|
14
|
+
|
15
|
+
slots 'toggle_display_stderr(bool)'
|
16
|
+
|
17
|
+
=begin rdoc
|
18
|
+
Whether output from standard error should be displayed or not
|
19
|
+
@return [Boolean]
|
20
|
+
=end
|
21
|
+
attr_reader :display_stderr
|
22
|
+
|
23
|
+
=begin rdoc
|
24
|
+
Create a new instance
|
25
|
+
|
26
|
+
The new instance is set not to show the output from standard error
|
27
|
+
|
28
|
+
@param [Qt::Object, nil] parent the parent object
|
29
|
+
=end
|
30
|
+
def initialize parent = nil
|
31
|
+
super
|
32
|
+
@display_stderr = false
|
33
|
+
end
|
34
|
+
|
35
|
+
=begin rdoc
|
36
|
+
Sets whether to display or ignore items corresponding to output to standard error
|
37
|
+
|
38
|
+
If this choice has changed, the model is invalidated.
|
39
|
+
|
40
|
+
@param [Boolean] val whether to display or ignore the output to standard error
|
41
|
+
@return [Boolean] _val_
|
42
|
+
=end
|
43
|
+
def display_stderr= val
|
44
|
+
old, @display_stderr = @display_stderr, val
|
45
|
+
invalidate if old != @display_stderr
|
46
|
+
@display_standard_error
|
47
|
+
end
|
48
|
+
alias_method :toggle_display_stderr, :display_stderr=
|
49
|
+
|
50
|
+
=begin rdoc
|
51
|
+
Override of {FilteredOutputWidget::FilterModel#filterAcceptsRow}
|
52
|
+
|
53
|
+
According to the value of {#display_stderr}, it can filter out items corresponding
|
54
|
+
to standard error. In all other respects, it behaves as the base class method.
|
55
|
+
@param [Integer] r the row number
|
56
|
+
@param [Qt::ModelIndex] parent the parent index
|
57
|
+
@return [Boolean] *true* if the row should be displayed and *false* otherwise
|
58
|
+
=end
|
59
|
+
def filterAcceptsRow r, parent
|
60
|
+
if !@display_stderr
|
61
|
+
idx = source_model.index(r,0,parent)
|
62
|
+
return false if idx.data(OutputWidget::OutputTypeRole).to_string == 'output1'
|
63
|
+
end
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
=begin rdoc
|
70
|
+
Tool widget used by the rspec plugin.
|
71
|
+
|
72
|
+
It displays the output from the spec program in a multi column tree. The name of
|
73
|
+
failing or pending examples are displayed in a full line; all other information,
|
74
|
+
such as the location of the example, the error message and so on are displayed
|
75
|
+
in child items.
|
76
|
+
|
77
|
+
While the examples are being run, a progress bar is shown.
|
78
|
+
=end
|
79
|
+
class ToolWidget < FilteredOutputWidget
|
80
|
+
|
81
|
+
slots :spec_started, 'spec_finished(int, QString)'
|
82
|
+
|
83
|
+
=begin rdoc
|
84
|
+
@param [Qt::Widget, nil] parent the parent widget
|
85
|
+
=end
|
86
|
+
def initialize parent = nil
|
87
|
+
super parent, :view => :tree, :filter => FilterModel.new
|
88
|
+
@toplevel_width = 0
|
89
|
+
@ignore_word_wrap_option = true
|
90
|
+
view.text_elide_mode = Qt::ElideNone
|
91
|
+
model.append_column [] if model.column_count < 2
|
92
|
+
@progress_bar = Qt::ProgressBar.new(self){|w| w.hide}
|
93
|
+
layout.add_widget @progress_bar, 2,0
|
94
|
+
view.header_hidden = true
|
95
|
+
view.header.resize_mode = Qt::HeaderView::ResizeToContents
|
96
|
+
connect Ruber[:rspec], SIGNAL(:process_started), self, SLOT(:spec_started)
|
97
|
+
connect Ruber[:rspec], SIGNAL('process_finished(int, QString)'), self, SLOT('spec_finished(int, QString)')
|
98
|
+
view.word_wrap = true
|
99
|
+
filter.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
|
100
|
+
if !par.valid?
|
101
|
+
st.upto(en) do |i|
|
102
|
+
view.set_first_column_spanned i, par, true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
#without these, the horizontal scrollbars won't be shown
|
107
|
+
connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
|
108
|
+
connect view, SIGNAL('collapsed(QModelIndex)'), self, SLOT(:resize_columns)
|
109
|
+
setup_actions
|
110
|
+
end
|
111
|
+
|
112
|
+
=begin rdoc
|
113
|
+
Displays the data relative to an example in the widget
|
114
|
+
|
115
|
+
Actually, this method simply passes its argument to a more specific method, depending
|
116
|
+
on the data it contains.
|
117
|
+
|
118
|
+
@param [Hash] data a hash containing the data describing the results of running
|
119
|
+
the example. This hash must contain the @:type@ key, which tells which kind of
|
120
|
+
event the hash describes. The other entries change depending on the method which
|
121
|
+
will be called, which is determined according to the @:type@ entry:
|
122
|
+
* @:success@: {#display_successful_example}
|
123
|
+
* @:failure@: {#display_failed_example}
|
124
|
+
* @:pending@: {#display_pending_example}
|
125
|
+
* @:new_example@: {#change_current_example}
|
126
|
+
* @:start@: {#set_example_count}
|
127
|
+
* @:summary@: {#display_summary}
|
128
|
+
If the @:type@ entry doesn't have one of the previous values, the hash will be
|
129
|
+
converted to a string and displayed in the widget
|
130
|
+
=end
|
131
|
+
def display_example data
|
132
|
+
unless data.is_a?(Hash)
|
133
|
+
model.insert_lines data.to_s, :output, nil
|
134
|
+
return
|
135
|
+
end
|
136
|
+
case data[:type]
|
137
|
+
when :success then display_successful_example data
|
138
|
+
when :failure then display_failed_example data
|
139
|
+
when :pending then display_pending_example data
|
140
|
+
when :new_example then change_current_example data
|
141
|
+
when :start then set_example_count data
|
142
|
+
when :summary then display_summary data
|
143
|
+
else model.insert_lines data.to_s, :output, nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def load_settings
|
148
|
+
super
|
149
|
+
compute_spanning_cols_size
|
150
|
+
resize_columns
|
151
|
+
end
|
152
|
+
|
153
|
+
=begin rdoc
|
154
|
+
Changes the current example
|
155
|
+
|
156
|
+
Currently, this only affects the tool tip displayed by the progress bar.
|
157
|
+
|
158
|
+
@param [Hash] data the data to use. It must contain the @:description@ entry,
|
159
|
+
which contains the text of the tool tip to use.
|
160
|
+
@return [nil]
|
161
|
+
=end
|
162
|
+
def change_current_example data
|
163
|
+
@progress_bar.tool_tip = data[:description]
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
=begin rdoc
|
168
|
+
Sets the number of examples found by the spec program.
|
169
|
+
|
170
|
+
This is used to set the maximum value of the progress bar.
|
171
|
+
|
172
|
+
@param [Hash] data the data to use. It must contain the @:count@ entry,
|
173
|
+
which contains the number of examples
|
174
|
+
@return [nil]
|
175
|
+
=end
|
176
|
+
def set_example_count data
|
177
|
+
@progress_bar.maximum = data[:count]
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
=begin rdoc
|
183
|
+
Updates the progress bar by incrementing its value by one
|
184
|
+
|
185
|
+
@param [Hash] data the data to use. Currently it's unused
|
186
|
+
@return [nil]
|
187
|
+
=end
|
188
|
+
def display_successful_example data
|
189
|
+
@progress_bar.value += 1
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
|
193
|
+
=begin rdoc
|
194
|
+
Displays information about a failed example in the tool widget.
|
195
|
+
|
196
|
+
@param [Hash] data the data about the example.
|
197
|
+
|
198
|
+
@option data [String] :location the line number where the error occurred
|
199
|
+
@option data [String] :description the name of the failed example
|
200
|
+
@option data [String] :message the explaination of why the example failed
|
201
|
+
@option data [String] :exception the content of the exception
|
202
|
+
@option data [String] :backtrace the backtrace of the exception (a single new-line separated string)
|
203
|
+
@return [nil]
|
204
|
+
=end
|
205
|
+
def display_failed_example data
|
206
|
+
@progress_bar.value += 1
|
207
|
+
top = model.insert("[FAILURE] #{data[:description]}", :error, nil).first
|
208
|
+
model.insert ['From:', data[:location]], :message, nil, :parent => top
|
209
|
+
ex_label = model.insert('Exception:', :message, nil, :parent => top).first
|
210
|
+
exception_body = "#{data[:message]} (#{data[:exception]})".split_lines.delete_if{|l| l.strip.empty?}
|
211
|
+
#exception_body may contain more than one line and some of them may be empty
|
212
|
+
model.set exception_body.shift, :message, ex_label.row, :col => 1, :parent => top
|
213
|
+
exception_body.each do |l|
|
214
|
+
unless l.strip.empty?
|
215
|
+
model.set l, :message, top.row_count, :col => 1, :parent => top
|
216
|
+
end
|
217
|
+
end
|
218
|
+
backtrace = data[:backtrace].split_lines
|
219
|
+
back_label, back = model.insert(['Backtrace:', backtrace.shift], :message, nil, :parent => top)
|
220
|
+
backtrace.each do |l|
|
221
|
+
model.insert [nil, l], :message, nil, :parent => back_label
|
222
|
+
end
|
223
|
+
top_index = filter.map_from_source(top.index)
|
224
|
+
view.collapse top_index
|
225
|
+
view.set_first_column_spanned top_index.row, Qt::ModelIndex.new, true
|
226
|
+
view.expand filter.map_from_source(back_label.index)
|
227
|
+
nil
|
228
|
+
end
|
229
|
+
|
230
|
+
=begin rdoc
|
231
|
+
Displays information about a pending example in the tool widget
|
232
|
+
|
233
|
+
@param [Hash] data
|
234
|
+
@option data [String] :location the line number where the error occurred
|
235
|
+
@option data [String] :description the name of the failed example
|
236
|
+
@option data [String] :message the explaination of why the example failed
|
237
|
+
@return [nil]
|
238
|
+
=end
|
239
|
+
def display_pending_example data
|
240
|
+
@progress_bar.value += 1
|
241
|
+
top = model.insert("[PENDING] #{data[:description]}", :warning, nil)[0]
|
242
|
+
model.insert ['From:', data[:location]], :message, nil, :parent => top
|
243
|
+
model.insert ['Message: ', "#{data[:message]} (#{data[:exception]})"], :message, nil, :parent => top
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
|
247
|
+
=begin rdoc
|
248
|
+
Displays a summary of the spec run in the tool widget
|
249
|
+
|
250
|
+
The summary is a single title line which contains the number or successful, pending
|
251
|
+
and failed example.
|
252
|
+
|
253
|
+
@param [Hash] data
|
254
|
+
@option data [Integer] :total the number of run examples
|
255
|
+
@option data [Integer] :passed the number of passed examples
|
256
|
+
@option data [Integer] :failed the number of failed examples
|
257
|
+
@option data [Integer] :pending the number of pending examples
|
258
|
+
@return [nil]
|
259
|
+
=end
|
260
|
+
def display_summary data
|
261
|
+
@progress_bar.hide
|
262
|
+
if data[:passed] == data[:total]
|
263
|
+
self.title = "[SUMMARY] All #{data[:total]} examples passed"
|
264
|
+
set_output_type model.index(0,0), :message_good
|
265
|
+
else
|
266
|
+
text = "[SUMMARY] Examples: #{data[:total]}"
|
267
|
+
text << " Failed: #{data[:failure]}" if data[:failure] > 0
|
268
|
+
text << " Pending: #{data[:pending]}" if data[:pending] > 0
|
269
|
+
text << " Passed: #{data[:passed]}"
|
270
|
+
self.title = text
|
271
|
+
type = data[:failure] > 0 ? :message_bad : :message
|
272
|
+
set_output_type model.index(0,0), type
|
273
|
+
end
|
274
|
+
nil
|
275
|
+
end
|
276
|
+
|
277
|
+
=begin rdoc
|
278
|
+
Override of {OutputWidget#title=}
|
279
|
+
|
280
|
+
It's needed to have the title element span all columns
|
281
|
+
|
282
|
+
@param [String] val the new title
|
283
|
+
=end
|
284
|
+
def title= val
|
285
|
+
super
|
286
|
+
model.item(0,0).tool_tip = val
|
287
|
+
view.set_first_column_spanned 0, Qt::ModelIndex.new, true
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
=begin rdoc
|
293
|
+
Resets the tool widget and sets the cursor to busy
|
294
|
+
@return [nil]
|
295
|
+
=end
|
296
|
+
def spec_started
|
297
|
+
@progress_bar.maximum = 0
|
298
|
+
@progress_bar.value = 0
|
299
|
+
@progress_bar.show
|
300
|
+
@progress_bar.tool_tip = ''
|
301
|
+
actions['show_stderr'].checked = false
|
302
|
+
self.cursor = Qt::Cursor.new(Qt::BusyCursor)
|
303
|
+
nil
|
304
|
+
end
|
305
|
+
|
306
|
+
=begin rdoc
|
307
|
+
Does the necessary cleanup for when spec finishes running
|
308
|
+
|
309
|
+
It hides the progress widget and restores the default cursor.
|
310
|
+
|
311
|
+
@param [Integer] code the exit code
|
312
|
+
@param [String] reason why the program exited
|
313
|
+
@return [nil]
|
314
|
+
=end
|
315
|
+
def spec_finished code, reason
|
316
|
+
@progress_bar.hide
|
317
|
+
@progress_bar.value = 0
|
318
|
+
@progress_bar.maximum = 100
|
319
|
+
self.set_focus
|
320
|
+
unset_cursor
|
321
|
+
unless reason == 'killed'
|
322
|
+
non_stderr_types = %w[message message_good message_bad warning error]
|
323
|
+
only_stderr = !model.item(0,0).text.match(/^\[SUMMARY\]/)
|
324
|
+
if only_stderr
|
325
|
+
1.upto(model.row_count - 1) do |i|
|
326
|
+
if non_stderr_types.include? model.item(i,0).data(OutputWidget::OutputTypeRole).to_string
|
327
|
+
only_stderr = false
|
328
|
+
break
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
if only_stderr
|
333
|
+
actions['show_stderr'].checked = true
|
334
|
+
model.insert "spec wasn't able to run the examples", :message_bad, nil
|
335
|
+
end
|
336
|
+
end
|
337
|
+
compute_spanning_cols_size
|
338
|
+
auto_expand_items
|
339
|
+
nil
|
340
|
+
end
|
341
|
+
|
342
|
+
=begin rdoc
|
343
|
+
Expands items according to the @rspec/auto_expand@ option
|
344
|
+
|
345
|
+
If the option is @:expand_first@, the first failed example is expanded; if the
|
346
|
+
option is @:expand_all@, all failed or pending examples are expanded. If the option
|
347
|
+
is @:expand_none@, nothing is done
|
348
|
+
@return [nil]
|
349
|
+
=end
|
350
|
+
def auto_expand_items
|
351
|
+
if model.row_count > 1
|
352
|
+
case Ruber[:config][:rspec, :auto_expand]
|
353
|
+
when :expand_first
|
354
|
+
item = model.each_row.find{|items| items[0].has_children}
|
355
|
+
view.expand filter_model.map_from_source(item[0].index) if item
|
356
|
+
when :expand_all
|
357
|
+
without_resizing_columns do
|
358
|
+
model.each_row do |items|
|
359
|
+
view.expand filter_model.map_from_source(items[0].index)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
resize_columns
|
363
|
+
end
|
364
|
+
end
|
365
|
+
nil
|
366
|
+
end
|
367
|
+
|
368
|
+
def compute_spanning_cols_size
|
369
|
+
metrics = view.font_metrics
|
370
|
+
@toplevel_width = source_model.each_row.map{|r| metrics.bounding_rect(r[0].text).width}.max || 0
|
371
|
+
end
|
372
|
+
|
373
|
+
def resize_columns
|
374
|
+
view.resize_column_to_contents 0
|
375
|
+
view.resize_column_to_contents 1
|
376
|
+
min_width = @toplevel_width - view.column_width(0) + 30
|
377
|
+
view.set_column_width 1, min_width if view.column_width(1) < min_width
|
378
|
+
end
|
379
|
+
slots :resize_columns
|
380
|
+
|
381
|
+
def without_resizing_columns
|
382
|
+
disconnect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
|
383
|
+
begin yield
|
384
|
+
ensure connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
=begin rdoc
|
389
|
+
Creates the additional actions.
|
390
|
+
|
391
|
+
It adds a single action, which allows the user to chose whether messages from
|
392
|
+
standard error should be displayed or not.
|
393
|
+
|
394
|
+
@return [nil]
|
395
|
+
=end
|
396
|
+
def setup_actions
|
397
|
+
action_list << nil << 'show_stderr'
|
398
|
+
a = KDE::ToggleAction.new 'S&how Standard Error', self
|
399
|
+
actions['show_stderr'] = a
|
400
|
+
a.checked = false
|
401
|
+
connect a, SIGNAL('toggled(bool)'), filter, SLOT('toggle_display_stderr(bool)')
|
402
|
+
end
|
403
|
+
|
404
|
+
=begin rdoc
|
405
|
+
Override of {OutputWidget#find_filename_in_index}
|
406
|
+
|
407
|
+
It works as the base class method, but, if it doesn't find a result in _idx_,
|
408
|
+
it looks for it in the parent indexes
|
409
|
+
|
410
|
+
@param [Qt::ModelIndex] idx the index where to look for a file name
|
411
|
+
@return [Array<String,Integer>,String,nil] see {OutputWidget#find_filename_in_index}
|
412
|
+
=end
|
413
|
+
def find_filename_in_index idx
|
414
|
+
res = super
|
415
|
+
unless res
|
416
|
+
idx = idx.parent while idx.parent.valid?
|
417
|
+
idx = idx.child(0,1)
|
418
|
+
res = super idx if idx.valid?
|
419
|
+
end
|
420
|
+
res
|
421
|
+
end
|
422
|
+
|
423
|
+
=begin rdoc
|
424
|
+
Override of {OutputWidget#text_for_clipboard}
|
425
|
+
|
426
|
+
@param [<Qt::ModelIndex>] idxs the selected indexes
|
427
|
+
@return [QString] the text to copy to the clipboard
|
428
|
+
=end
|
429
|
+
def text_for_clipboard idxs
|
430
|
+
order = {}
|
431
|
+
idxs.each do |i|
|
432
|
+
val = []
|
433
|
+
parent = i
|
434
|
+
while parent.parent.valid?
|
435
|
+
parent = parent.parent
|
436
|
+
val.unshift parent.row
|
437
|
+
end
|
438
|
+
val << [i.row, i.column]
|
439
|
+
order[val] = i
|
440
|
+
end
|
441
|
+
order = order.sort do |a, b|
|
442
|
+
a, b = a[0], b[0]
|
443
|
+
res = a[0..-2] <=> b[0..-2]
|
444
|
+
if res == 0 then a[-1] <=> b[-1]
|
445
|
+
else res
|
446
|
+
end
|
447
|
+
end
|
448
|
+
prev = order.shift[1]
|
449
|
+
text = prev.data.valid? ? prev.data.to_string : ''
|
450
|
+
order.each do |_, v|
|
451
|
+
text << ( (prev.parent == v.parent and prev.row == v.row) ? "\t" : "\n")
|
452
|
+
text << (v.data.valid? ? v.data.to_string : '')
|
453
|
+
prev = v
|
454
|
+
end
|
455
|
+
text
|
456
|
+
end
|
457
|
+
|
458
|
+
end
|
459
|
+
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|