ruber 0.0.1.1
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/COPYING +339 -0
- data/INSTALL +137 -0
- data/LICENSE +8 -0
- data/bin/ruber +65 -0
- data/data/share/apps/ruber/core_components.yaml +31 -0
- data/data/share/apps/ruber/ruberui.rc +109 -0
- data/data/share/icons/ruber.png +0 -0
- data/data/share/pixmaps/ruby.png +0 -0
- data/icons/ruber-16.png +0 -0
- data/icons/ruber-32.png +0 -0
- data/icons/ruber-48.png +0 -0
- data/icons/ruber-8.png +0 -0
- data/lib/ruber/application/application.rb +288 -0
- data/lib/ruber/application/plugin.yaml +11 -0
- data/lib/ruber/component_manager.rb +899 -0
- data/lib/ruber/config/config.rb +82 -0
- data/lib/ruber/config/plugin.yaml +3 -0
- data/lib/ruber/document_project.rb +209 -0
- data/lib/ruber/documents/document_list.rb +416 -0
- data/lib/ruber/documents/plugin.yaml +4 -0
- data/lib/ruber/editor/document.rb +506 -0
- data/lib/ruber/editor/editor_view.rb +167 -0
- data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
- data/lib/ruber/exception_widgets.rb +245 -0
- data/lib/ruber/external_program_plugin.rb +397 -0
- data/lib/ruber/filtered_output_widget.rb +342 -0
- data/lib/ruber/gui_states_handler.rb +231 -0
- data/lib/ruber/kde_config_option_backend.rb +167 -0
- data/lib/ruber/kde_sugar.rb +249 -0
- data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
- data/lib/ruber/main_window/main_window.rb +524 -0
- data/lib/ruber/main_window/main_window_actions.rb +537 -0
- data/lib/ruber/main_window/main_window_internal.rb +239 -0
- data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
- data/lib/ruber/main_window/output_color_widget.rb +35 -0
- data/lib/ruber/main_window/plugin.yaml +58 -0
- data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
- data/lib/ruber/main_window/status_bar.rb +156 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
- data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
- data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
- data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
- data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
- data/lib/ruber/main_window/workspace.rb +442 -0
- data/lib/ruber/output_widget.rb +1093 -0
- data/lib/ruber/plugin.rb +264 -0
- data/lib/ruber/plugin_like.rb +589 -0
- data/lib/ruber/plugin_specification.rb +106 -0
- data/lib/ruber/plugin_specification_reader.rb +451 -0
- data/lib/ruber/project.rb +493 -0
- data/lib/ruber/project_backend.rb +105 -0
- data/lib/ruber/projects/plugin.yaml +11 -0
- data/lib/ruber/projects/project_files_list.rb +314 -0
- data/lib/ruber/projects/project_files_widget.rb +301 -0
- data/lib/ruber/projects/project_list.rb +314 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
- data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
- data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
- data/lib/ruber/qt_sugar.rb +673 -0
- data/lib/ruber/settings_container.rb +515 -0
- data/lib/ruber/settings_dialog.rb +244 -0
- data/lib/ruber/settings_dialog_manager.rb +503 -0
- data/lib/ruber/utils.rb +414 -0
- data/lib/ruber/yaml_option_backend.rb +159 -0
- data/outsider_files +15 -0
- data/plugins/autosave/autosave.rb +404 -0
- data/plugins/autosave/plugin.yaml +16 -0
- data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
- data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
- data/plugins/command/command.png +0 -0
- data/plugins/command/command.rb +74 -0
- data/plugins/command/plugin.yaml +11 -0
- data/plugins/find_in_files/find_in_files.rb +337 -0
- data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
- data/plugins/find_in_files/find_in_files_ui.rc +11 -0
- data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
- data/plugins/find_in_files/plugin.yaml +23 -0
- data/plugins/find_in_files/ui/config_widget.rb +58 -0
- data/plugins/find_in_files/ui/config_widget.ui +41 -0
- data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
- data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
- data/plugins/project_browser/plugin.yaml +10 -0
- data/plugins/project_browser/project_browser.rb +245 -0
- data/plugins/rake/plugin.yaml +39 -0
- data/plugins/rake/rake.png +0 -0
- data/plugins/rake/rake.rb +567 -0
- data/plugins/rake/rake_extension.rb +153 -0
- data/plugins/rake/rake_widgets.rb +615 -0
- data/plugins/rake/rakeui.rc +27 -0
- data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
- data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
- data/plugins/rake/ui/choose_task_widget.rb +77 -0
- data/plugins/rake/ui/choose_task_widget.ui +72 -0
- data/plugins/rake/ui/config_widget.rb +127 -0
- data/plugins/rake/ui/config_widget.ui +123 -0
- data/plugins/rake/ui/project_widget.rb +217 -0
- data/plugins/rake/ui/project_widget.ui +246 -0
- data/plugins/rspec/plugin.yaml +30 -0
- data/plugins/rspec/rspec.png +0 -0
- data/plugins/rspec/rspec.rb +945 -0
- data/plugins/rspec/rspec.svg +90 -0
- data/plugins/rspec/rspecui.rc +20 -0
- data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
- data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
- data/plugins/ruby_development/plugin.yaml +27 -0
- data/plugins/ruby_development/ruby_development.png +0 -0
- data/plugins/ruby_development/ruby_development.rb +453 -0
- data/plugins/ruby_development/ruby_developmentui.rc +19 -0
- data/plugins/ruby_development/ui/project_widget.rb +112 -0
- data/plugins/ruby_development/ui/project_widget.ui +108 -0
- data/plugins/ruby_runner/config_widget.rb +116 -0
- data/plugins/ruby_runner/plugin.yaml +26 -0
- data/plugins/ruby_runner/project_widget.rb +62 -0
- data/plugins/ruby_runner/ruby.png +0 -0
- data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
- data/plugins/ruby_runner/ruby_runner.rb +411 -0
- data/plugins/ruby_runner/ui/config_widget.rb +92 -0
- data/plugins/ruby_runner/ui/config_widget.ui +91 -0
- data/plugins/ruby_runner/ui/project_widget.rb +60 -0
- data/plugins/ruby_runner/ui/project_widget.ui +48 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
- data/plugins/state/plugin.yaml +28 -0
- data/plugins/state/state.rb +520 -0
- data/plugins/state/ui/config_widget.rb +92 -0
- data/plugins/state/ui/config_widget.ui +89 -0
- data/plugins/syntax_checker/plugin.yaml +18 -0
- data/plugins/syntax_checker/syntax_checker.rb +662 -0
- data/ruber.desktop +10 -0
- data/spec/annotation_model_spec.rb +174 -0
- data/spec/common.rb +119 -0
- data/spec/component_manager_spec.rb +1259 -0
- data/spec/document_list_spec.rb +626 -0
- data/spec/document_project_spec.rb +373 -0
- data/spec/document_spec.rb +779 -0
- data/spec/editor_view_spec.rb +167 -0
- data/spec/external_program_plugin_spec.rb +676 -0
- data/spec/filtered_output_widget_spec.rb +642 -0
- data/spec/gui_states_handler_spec.rb +304 -0
- data/spec/kde_config_option_backend_spec.rb +214 -0
- data/spec/kde_sugar_spec.rb +101 -0
- data/spec/ktexteditor_wrapper_spec.rb +305 -0
- data/spec/output_widget_spec.rb +1703 -0
- data/spec/plugin_spec.rb +1393 -0
- data/spec/plugin_specification_reader_spec.rb +1765 -0
- data/spec/plugin_specification_spec.rb +401 -0
- data/spec/project_backend_spec.rb +172 -0
- data/spec/project_files_list_spec.rb +401 -0
- data/spec/project_list_spec.rb +511 -0
- data/spec/project_spec.rb +990 -0
- data/spec/qt_sugar_spec.rb +328 -0
- data/spec/settings_container_spec.rb +617 -0
- data/spec/settings_dialog_manager_spec.rb +773 -0
- data/spec/settings_dialog_spec.rb +419 -0
- data/spec/state_spec.rb +991 -0
- data/spec/utils_spec.rb +406 -0
- data/spec/workspace_spec.rb +869 -0
- data/spec/yaml_option_backend_spec.rb +246 -0
- metadata +284 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2010 by Stefano Crocco
|
|
3
|
+
stefano.crocco@alice.it
|
|
4
|
+
|
|
5
|
+
This program is free software; you can redistribute it andor modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program; if not, write to the
|
|
17
|
+
Free Software Foundation, Inc.,
|
|
18
|
+
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
19
|
+
=end
|
|
20
|
+
|
|
21
|
+
require 'ruber/plugin'
|
|
22
|
+
|
|
23
|
+
module Ruber
|
|
24
|
+
|
|
25
|
+
=begin rdoc
|
|
26
|
+
Base class for plugins whose main task is to run an external program and maybe
|
|
27
|
+
(not necessarily) to display the output in a tool widget.
|
|
28
|
+
|
|
29
|
+
Basically, this class is a wrapper for <tt>KDE::Process</tt> providing a more
|
|
30
|
+
integrated API for the most common functions. In particular, it provides the
|
|
31
|
+
following functionality:
|
|
32
|
+
* automatic creation of the process
|
|
33
|
+
* automatic cleanup at shutdown
|
|
34
|
+
* automatic managing of buffered output
|
|
35
|
+
* nicer API to read from standard output and standard error
|
|
36
|
+
* simplified API to start the process
|
|
37
|
+
* automatic display of standard output and standard error in a tool widget (if required)
|
|
38
|
+
* display of the command line and of the process status in a tool widget (if required)
|
|
39
|
+
|
|
40
|
+
To start the process, you simply call the <tt>run_process</tt> method, passing it
|
|
41
|
+
the name of the program to run, the working directory and the arguments.
|
|
42
|
+
|
|
43
|
+
When the process emits the <tt>readyReadStandardOutput()</tt> or the
|
|
44
|
+
<tt>readyReadStandardError()</tt>, the contents of the appropriate stream are read
|
|
45
|
+
and split into lines. The resulting array are passed to the <tt>process_standard_output</tt>
|
|
46
|
+
or <tt>process_standard_error</tt> method. Derived classes can override these methods
|
|
47
|
+
to do what they want with the output.
|
|
48
|
+
|
|
49
|
+
In general, you can't be sure whether the data contained read from standard output
|
|
50
|
+
or error contains complete lines. To deal with this issue, whenob reading from a
|
|
51
|
+
stream, only full lines (that is, lines which end in "\n") are passed to
|
|
52
|
+
<tt>process_standard_output</tt> or <tt>process_standard_error</tt>. If the last
|
|
53
|
+
line isn't complete, it is stored in a buffer. The next time characters are read
|
|
54
|
+
from the process, if they came from the same channel, the buffer is added at the
|
|
55
|
+
beginning of the new stream; if they came from the other channel, they're passed
|
|
56
|
+
to the appropriate <tt>process_standard_*</tt> method. This behaviour can be
|
|
57
|
+
changed by passing the appropriate arguments to the constructor.
|
|
58
|
+
|
|
59
|
+
Some methods in this class have the ability to insert data in a OutputWidget. They
|
|
60
|
+
will do so if the <tt>@output_widget</tt> instance variable (which is created in
|
|
61
|
+
the constructor, if it doesn't already exist) is not *nil*. Note that those methods
|
|
62
|
+
don't check if <tt>@output_widget</tt> actually is an OutputWidget or not. If it
|
|
63
|
+
is something else, you'll get errors. In all the following documentation it is
|
|
64
|
+
assumed that:
|
|
65
|
+
* the expression <i>the output widget</i> refers to the object the <tt>@output_widget</tt>
|
|
66
|
+
instance variable refers to, unless it's *nil*
|
|
67
|
+
* everything concerning the output widget will be ignored (without giving any error)
|
|
68
|
+
if the output widget doesn't exist
|
|
69
|
+
|
|
70
|
+
===Signals
|
|
71
|
+
=====<tt>process_finished(int code, QString reason)</tt>
|
|
72
|
+
Signal emitted when the process finishes. _code_ is the exit code of the process,
|
|
73
|
+
while _reason_ is a string which can have one of the values "killed", "crash" or
|
|
74
|
+
be empty. If it's empty, it means that the program finished normally; "killed"
|
|
75
|
+
means that it was killed by the user and "crash" means that the program crashed.
|
|
76
|
+
=====<tt>process_started()</tt>
|
|
77
|
+
Signal emitted when the process has started
|
|
78
|
+
=====<tt>process_failed_to_start()</tt>
|
|
79
|
+
Signal emitted if the process couldn't be started (for example, because the given
|
|
80
|
+
program doesn't exist)
|
|
81
|
+
===Slots
|
|
82
|
+
* <tt>slot_process_finished(int, QProcess::ExitStatus)</tt>
|
|
83
|
+
* <tt>stop_process()</tt>
|
|
84
|
+
=end
|
|
85
|
+
class ExternalProgramPlugin < GuiPlugin
|
|
86
|
+
|
|
87
|
+
slots 'slot_process_finished(int, QProcess::ExitStatus)', 'display_exit_message(int, QString)',
|
|
88
|
+
:stop_process
|
|
89
|
+
|
|
90
|
+
signals 'process_finished(int, QString)', :process_started, :process_failed_to_start
|
|
91
|
+
|
|
92
|
+
=begin rdoc
|
|
93
|
+
The <tt>KDE::Process</tt> used by the plugin
|
|
94
|
+
=end
|
|
95
|
+
attr_reader :process
|
|
96
|
+
|
|
97
|
+
=begin rdoc
|
|
98
|
+
Creates a new ExternalProgramPlugin.
|
|
99
|
+
|
|
100
|
+
_pdf_ is the plugin info object for the plugin. If <i>line_buffered</i> is *false*,
|
|
101
|
+
buffering won't be used (all the characters read from the process will be passed
|
|
102
|
+
to <tt>process_standard_output</tt> or <tt>process_standard_error</tt> even if they
|
|
103
|
+
don't end in a newline).
|
|
104
|
+
|
|
105
|
+
<b>Note:</b> the process' channel mode will be set to <tt>Qt::Process::SeparateChannels</tt>.
|
|
106
|
+
You can set it to any value you want later
|
|
107
|
+
=end
|
|
108
|
+
def initialize pdf, line_buffered = true
|
|
109
|
+
super pdf
|
|
110
|
+
@buffer = nil
|
|
111
|
+
@buffer_content_channel = nil
|
|
112
|
+
@line_buffered = line_buffered
|
|
113
|
+
@output_widget = nil unless defined? @output_widget
|
|
114
|
+
@process = KDE::Process.new self
|
|
115
|
+
@process.process_channel_mode = Qt::Process::SeparateChannels
|
|
116
|
+
@process.output_channel_mode = KDE::Process::SeparateChannels
|
|
117
|
+
@process.connect SIGNAL(:readyReadStandardOutput) do
|
|
118
|
+
do_stdout @process.read_all_standard_output.to_s
|
|
119
|
+
end
|
|
120
|
+
@process.connect SIGNAL(:readyReadStandardError) do
|
|
121
|
+
do_stderr @process.read_all_standard_error.to_s
|
|
122
|
+
end
|
|
123
|
+
connect @process, SIGNAL('finished(int, QProcess::ExitStatus)'), self, SLOT('slot_process_finished(int, QProcess::ExitStatus)')
|
|
124
|
+
connect self, SIGNAL('process_finished(int, QString)'), self, SLOT('display_exit_message(int, QString)')
|
|
125
|
+
@process.connect SIGNAL('error(QProcess::ProcessError)') do |e|
|
|
126
|
+
failed_to_start if e == Qt::Process::FailedToStart
|
|
127
|
+
end
|
|
128
|
+
connect @process, SIGNAL('started()'), self, SIGNAL('process_started()')
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
=begin rdoc
|
|
132
|
+
Starts the program.
|
|
133
|
+
|
|
134
|
+
_prog_ is the name of the program (you don't need to specify the absolute path
|
|
135
|
+
if it's in PATH). _args_ is an array containing the arguments. _dir_ is the working
|
|
136
|
+
directory.
|
|
137
|
+
|
|
138
|
+
_title_ is the string to display in the output widget. If it is an empty string, the name
|
|
139
|
+
of the program followed by its arguments will be used. If it is *nil* or *false*,
|
|
140
|
+
the title won't be set.
|
|
141
|
+
=end
|
|
142
|
+
def run_process prog, dir, args, title = ''
|
|
143
|
+
@buffer = nil
|
|
144
|
+
@buffer_content_channel = nil
|
|
145
|
+
@process.clear_program
|
|
146
|
+
@process.working_directory = dir
|
|
147
|
+
program = [prog] + args
|
|
148
|
+
@process.program = program
|
|
149
|
+
if @output_widget and title
|
|
150
|
+
title = program.join ' ' if title.empty?
|
|
151
|
+
@output_widget.title = title
|
|
152
|
+
end
|
|
153
|
+
@process.start
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
=begin rdoc
|
|
157
|
+
Stops the process.
|
|
158
|
+
|
|
159
|
+
It's a shortcut for <tt>process.kill</tt>
|
|
160
|
+
=end
|
|
161
|
+
def stop_process
|
|
162
|
+
@process.kill
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
=begin rdoc
|
|
166
|
+
Prepares the plugin to be unloaded by killing the process (no signal will be emitted
|
|
167
|
+
from the process or the plugin from now on).
|
|
168
|
+
|
|
169
|
+
If you reimplement this method, don't forget to call *super*. If you don't you
|
|
170
|
+
might cause a crash when Ruber is closed
|
|
171
|
+
=end
|
|
172
|
+
def shutdown
|
|
173
|
+
@process.block_signals true
|
|
174
|
+
@process.kill
|
|
175
|
+
super
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
=begin rdoc
|
|
181
|
+
Pre-processes the string _str_ then passes the resulting array to <tt>process_standard_output</tt>.
|
|
182
|
+
|
|
183
|
+
Pre-processing the string means:
|
|
184
|
+
* splitting it into lines
|
|
185
|
+
* emptying the buffer (by passing its contents to <tt>process_standard_error</tt>
|
|
186
|
+
if it refers to standard error or prepending it to _str_ if it refers to standard
|
|
187
|
+
output)
|
|
188
|
+
* putting the last line in the buffer if it doesn't end in a newline.
|
|
189
|
+
|
|
190
|
+
If the plugin is not buffered, then only the first step is done.
|
|
191
|
+
|
|
192
|
+
<b>Note:</b> if _str_ is empty, nothing will happen. If it consists only of newlines,
|
|
193
|
+
it will cause the buffer to be emptied (as described above) and nothing else.
|
|
194
|
+
<b>Note:</b> consecutive newlines will be treated as a single newline
|
|
195
|
+
=end
|
|
196
|
+
def do_stdout str
|
|
197
|
+
return if str.empty?
|
|
198
|
+
if @line_buffered and @buffer
|
|
199
|
+
buffer = @buffer
|
|
200
|
+
channel = @buffer_content_channel
|
|
201
|
+
@buffer = nil
|
|
202
|
+
@buffer_content_channel = nil
|
|
203
|
+
if channel == :stdout
|
|
204
|
+
str = buffer + str
|
|
205
|
+
return do_stdout str
|
|
206
|
+
else process_standard_error [buffer]
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
lines = str.split_lines
|
|
210
|
+
if @line_buffered and !str.end_with? "\n"
|
|
211
|
+
@buffer = lines.pop
|
|
212
|
+
@buffer_content_channel = :stdout
|
|
213
|
+
end
|
|
214
|
+
return if lines.empty?
|
|
215
|
+
process_standard_output lines
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
=begin rdoc
|
|
219
|
+
Pre-processes the string _str_ then passes the resulting array to <tt>process_standard_error</tt>.
|
|
220
|
+
|
|
221
|
+
Pre-processing the string means:
|
|
222
|
+
* splitting it into lines
|
|
223
|
+
* emptying the buffer (by passing its contents to <tt>process_standard_output</tt>
|
|
224
|
+
if it refers to standard output or prepending it to _str_ if it refers to standard
|
|
225
|
+
error)
|
|
226
|
+
* putting the last line in the buffer if it doesn't end in a newline.
|
|
227
|
+
|
|
228
|
+
If the plugin is not buffered, then only the first step is done.
|
|
229
|
+
|
|
230
|
+
<b>Note:</b> if _str_ is empty, nothing will happen. If it consists only of newlines,
|
|
231
|
+
it will cause the buffer to be emptied (as described above) and nothing else.
|
|
232
|
+
<b>Note:</b> consecutive newlines will be treated as a single newline
|
|
233
|
+
=end
|
|
234
|
+
def do_stderr str
|
|
235
|
+
return if str.empty?
|
|
236
|
+
if @line_buffered and @buffer
|
|
237
|
+
buffer = @buffer
|
|
238
|
+
channel = @buffer_content_channel
|
|
239
|
+
@buffer = nil
|
|
240
|
+
@buffer_content_channel = nil
|
|
241
|
+
if channel == :stderr
|
|
242
|
+
str = buffer + str
|
|
243
|
+
return do_stderr str
|
|
244
|
+
else process_standard_output [buffer]
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
lines = str.split_lines
|
|
248
|
+
if @line_buffered and !str.end_with? "\n"
|
|
249
|
+
@buffer = lines.pop
|
|
250
|
+
@buffer_content_channel = :stderr
|
|
251
|
+
end
|
|
252
|
+
return if lines.empty?
|
|
253
|
+
process_standard_error lines
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
=begin rdoc
|
|
257
|
+
Does something with the text written to standard output by the program.
|
|
258
|
+
|
|
259
|
+
The base class implementation of this method inserts the text at the end of the
|
|
260
|
+
output widget in the first column (one item per line) and sets the output type
|
|
261
|
+
to +:output+. Nothing is done if the output widget doesn't exist. Subclasses
|
|
262
|
+
can reimplement this method to do something else (in this case, you don't usually
|
|
263
|
+
want to call *super*)
|
|
264
|
+
|
|
265
|
+
_lines_ is an array where each entry corresponds to a line of output from the
|
|
266
|
+
program. If buffering is on, each entry is a complete line (or should be considered
|
|
267
|
+
such). If buffering is off, you'll have to take care of newlines by yourself.
|
|
268
|
+
=end
|
|
269
|
+
def process_standard_output lines
|
|
270
|
+
return unless @output_widget
|
|
271
|
+
mod = @output_widget.model
|
|
272
|
+
rc = mod.row_count
|
|
273
|
+
mod.insert_rows rc, lines.size
|
|
274
|
+
lines.each_with_index do |l, i|
|
|
275
|
+
idx = mod.index(i + rc, 0)
|
|
276
|
+
mod.set_data idx, Qt::Variant.new(l)
|
|
277
|
+
@output_widget.set_output_type idx, :output
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
=begin rdoc
|
|
282
|
+
Does something with the text written to standard error by the program.
|
|
283
|
+
|
|
284
|
+
The base class implementation of this method inserts the text at the end of the
|
|
285
|
+
output widget in the first column (one item per line) and sets the output type
|
|
286
|
+
to +:output+. Nothing is done if the output widget doesn't exist. Subclasses
|
|
287
|
+
can reimplement this method to do something else (in this case, you don't usually
|
|
288
|
+
want to call *super*)
|
|
289
|
+
|
|
290
|
+
_lines_ is an array where each entry corresponds to a line of output from the
|
|
291
|
+
program. If buffering is on, each entry is a complete line (or should be considered
|
|
292
|
+
such). If buffering is off, you'll have to take care of newlines by yourself.
|
|
293
|
+
=end
|
|
294
|
+
def process_standard_error lines
|
|
295
|
+
return unless @output_widget
|
|
296
|
+
mod = @output_widget.model
|
|
297
|
+
rc = mod.row_count
|
|
298
|
+
mod.insert_rows rc, lines.size
|
|
299
|
+
lines.each_with_index do |l, i|
|
|
300
|
+
idx = mod.index(i + rc, 0)
|
|
301
|
+
mod.set_data idx, Qt::Variant.new(l)
|
|
302
|
+
@output_widget.set_output_type idx, :error
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
=begin rdoc
|
|
307
|
+
Method called if the program fails to start (in response, but not connected to,
|
|
308
|
+
the process <tt>error(QProcess::ProcessError)</tt> signal if the argument is
|
|
309
|
+
<tt>Qt::Process::FailedToStart</tt>).
|
|
310
|
+
|
|
311
|
+
It emits the <tt>process_failed_to_start()</tt> signal and displays an appropriate
|
|
312
|
+
message to the output widget (using the <tt>:error1</tt> output type).
|
|
313
|
+
|
|
314
|
+
If <tt>@output_widget</tt> is not *nil* but you don't want the message to be
|
|
315
|
+
generated, you'll need to override this method. If you do so, don't forget to
|
|
316
|
+
emit the <tt>failed_to_start()</tt> signal.
|
|
317
|
+
=end
|
|
318
|
+
def failed_to_start
|
|
319
|
+
emit process_failed_to_start
|
|
320
|
+
if @output_widget
|
|
321
|
+
mod = @output_widget.model
|
|
322
|
+
rc = mod.row_count
|
|
323
|
+
mod.insert_row rc
|
|
324
|
+
cmd = @process.program
|
|
325
|
+
cmd_line = cmd.join " "
|
|
326
|
+
prog = cmd.shift
|
|
327
|
+
idx = mod.index(rc, 0)
|
|
328
|
+
mod.set_data idx, Qt::Variant.new("#{prog} failed to start. The command line was #{cmd_line}")
|
|
329
|
+
@output_widget.set_output_type idx, :error1
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
=begin rdoc
|
|
334
|
+
Slot called in response to the process' <tt>finished(int, QProcess::ExitStatus)</tt>
|
|
335
|
+
signal.
|
|
336
|
+
|
|
337
|
+
It emits the <tt>process_finished(int, QString)</tt> signal
|
|
338
|
+
=end
|
|
339
|
+
def slot_process_finished code, status
|
|
340
|
+
str = @process.read_all_standard_output.to_s
|
|
341
|
+
str << "\n" unless str.end_with?("\n")
|
|
342
|
+
do_stdout str
|
|
343
|
+
str = @process.read_all_standard_error.to_s
|
|
344
|
+
str << "\n" unless str.end_with?("\n")
|
|
345
|
+
do_stderr str
|
|
346
|
+
reason = ''
|
|
347
|
+
if status == Qt::Process::CrashExit
|
|
348
|
+
reason = code == 0 ? 'killed' : 'crash'
|
|
349
|
+
end
|
|
350
|
+
emit process_finished code, reason
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
=begin rdoc
|
|
354
|
+
Displays a message in the output widget describing the exit status of the program.
|
|
355
|
+
|
|
356
|
+
The message (output type message) has the format <i>program_name</i> <i>message</i>,
|
|
357
|
+
where message is:
|
|
358
|
+
|
|
359
|
+
* <tt>exited normally</tt> if _reason_ is an empty string
|
|
360
|
+
* <tt>was killed</tt> if _reason_ is 'killed'
|
|
361
|
+
* <tt>exited with code</tt> _code_ if _reason_ is 'crash'
|
|
362
|
+
|
|
363
|
+
This method is meant to be connected to the <tt>process_finished(int, QString)</tt>
|
|
364
|
+
signal. Its arguments match those of the signal.
|
|
365
|
+
|
|
366
|
+
If you want to change the message, override this method. If you don't want any
|
|
367
|
+
message and the <tt>@output_widget</tt> instance variable is not *nil*, you can
|
|
368
|
+
either disconnect this slot from the <tt>process_finished(int, QString)</tt>
|
|
369
|
+
signal or override this method without calling *super*
|
|
370
|
+
=end
|
|
371
|
+
def display_exit_message code, reason
|
|
372
|
+
return unless @output_widget
|
|
373
|
+
mod = @output_widget.model
|
|
374
|
+
rc = mod.row_count
|
|
375
|
+
mod.insert_row rc
|
|
376
|
+
idx = mod.index rc, 0
|
|
377
|
+
type = :message
|
|
378
|
+
text = "Process "
|
|
379
|
+
case reason
|
|
380
|
+
when ''
|
|
381
|
+
if code == 0 then text << 'exited normally'
|
|
382
|
+
else
|
|
383
|
+
text << "exited with code #{code}"
|
|
384
|
+
type = :message_bad
|
|
385
|
+
end
|
|
386
|
+
when 'killed' then text << 'killed'
|
|
387
|
+
when 'crash'
|
|
388
|
+
text << "crashed with code #{code}"
|
|
389
|
+
type = :message_bad
|
|
390
|
+
end
|
|
391
|
+
mod.set_data idx, Qt::Variant.new(text)
|
|
392
|
+
@output_widget.set_output_type idx, type
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
end
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2010 by Stefano Crocco
|
|
3
|
+
stefano.crocco@alice.it
|
|
4
|
+
|
|
5
|
+
This program is free software; you can redistribute it andor modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program; if not, write to the
|
|
17
|
+
Free Software Foundation, Inc.,
|
|
18
|
+
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
19
|
+
=end
|
|
20
|
+
|
|
21
|
+
require 'ruber/output_widget'
|
|
22
|
+
|
|
23
|
+
module Ruber
|
|
24
|
+
|
|
25
|
+
=begin rdoc
|
|
26
|
+
OutputWidget which allows the user to filter the contents, displaying only the
|
|
27
|
+
items which match a given regexp.
|
|
28
|
+
|
|
29
|
+
This widget provides a line edit to enter the regexp, which is shown using a
|
|
30
|
+
'Create filter' action from the context menu. When the user presses the Return
|
|
31
|
+
key from within the line edit, a filter is created from the current text and applied
|
|
32
|
+
(if the line edit is empty, any existing filter is removed). If the user doesn't
|
|
33
|
+
want to create the filter, the line edit is hidden by pressing ESC while within it.
|
|
34
|
+
|
|
35
|
+
The filter is implemented using a FilteredOutputWidget::FilterModel, which is a
|
|
36
|
+
slightly modified <tt>Qt::SortFilterProxyModel</tt>. Most of the times, however,
|
|
37
|
+
you don't need to worry about this, as all the methods provided by this class
|
|
38
|
+
still use indexes referred to the source model. This means that, most of the times,
|
|
39
|
+
adding filtering capability to an output widget is as simple as having it inherit
|
|
40
|
+
from FilteredOutputWidget rather than from OutputWidget.
|
|
41
|
+
|
|
42
|
+
Besides the 'Create Filter', this class adds two other entries to the context menu:
|
|
43
|
+
'Clear Filter', which removes the existring filter, and a 'Ignore Filter' toggle
|
|
44
|
+
action, which allows to temporarily disable the filter without removing it. Also,
|
|
45
|
+
a new UI state, called 'no_filter' is defined: it's true if no filter is applied
|
|
46
|
+
and false otherwise
|
|
47
|
+
|
|
48
|
+
===Slots
|
|
49
|
+
* <tt>create_filter_from_editor</tt>
|
|
50
|
+
* <tt>clear_filter</tt>
|
|
51
|
+
* <tt>ignore_filter(bool)</tt>
|
|
52
|
+
* <tt>show_editor</tt>
|
|
53
|
+
=end
|
|
54
|
+
class FilteredOutputWidget < OutputWidget
|
|
55
|
+
|
|
56
|
+
=begin rdoc
|
|
57
|
+
The model used to filter the contents of the output widget
|
|
58
|
+
=end
|
|
59
|
+
attr_reader :filter_model
|
|
60
|
+
alias :filter :filter_model
|
|
61
|
+
alias :source_model :model
|
|
62
|
+
|
|
63
|
+
slots :create_filter_from_editor, :clear_filter, 'ignore_filter(bool)',
|
|
64
|
+
:show_editor
|
|
65
|
+
|
|
66
|
+
=begin rdoc
|
|
67
|
+
Creates a new FilteredOutputWidget.
|
|
68
|
+
|
|
69
|
+
The arguments have the same meaning as in <tt>OutputWidget.new</tt>. The only
|
|
70
|
+
difference is that _opts_ can also contain a +:filter+ entry. If given, it is the
|
|
71
|
+
filter model to use (which should be derived from FilteredOutputWidget::FilterModel
|
|
72
|
+
or provide the same api); if this entry is missing, a new FilteredOutputWidget::FilterModel
|
|
73
|
+
will be used
|
|
74
|
+
=end
|
|
75
|
+
def initialize parent = nil, opts = {}
|
|
76
|
+
super parent, opts
|
|
77
|
+
@filter_model = opts[:filter] || FilterModel.new
|
|
78
|
+
@filter_model.parent = self
|
|
79
|
+
@filter_model.dynamic_sort_filter = true
|
|
80
|
+
@filter_model.source_model = model
|
|
81
|
+
view.model = @filter_model
|
|
82
|
+
disconnect @model, SIGNAL('rowsInserted(QModelIndex, int, int)'), self, SLOT('do_auto_scroll(QModelIndex, int, int)')
|
|
83
|
+
connect @filter_model, SIGNAL('rowsInserted(QModelIndex, int, int)'), self, SLOT('do_auto_scroll(QModelIndex, int, int)')
|
|
84
|
+
connect view.selection_model, SIGNAL('selectionChanged(QItemSelection, QItemSelection)'), self, SLOT('selection_changed(QItemSelection, QItemSelection)')
|
|
85
|
+
@editor = KDE::LineEdit.new self
|
|
86
|
+
connect @editor, SIGNAL('returnPressed(QString)'), self, SLOT(:create_filter_from_editor)
|
|
87
|
+
layout.add_widget @editor, 1, 0
|
|
88
|
+
def @editor.keyReleaseEvent e
|
|
89
|
+
super
|
|
90
|
+
hide if e.key == Qt::Key_Escape and e.modifiers == 0
|
|
91
|
+
end
|
|
92
|
+
@editor.hide
|
|
93
|
+
@editor.completion_object = KDE::Completion.new
|
|
94
|
+
@action_list.insert_before 1, nil, 'create_filter', 'ignore_filter', 'clear_filter'
|
|
95
|
+
create_standard_actions
|
|
96
|
+
set_state 'no_filter', true
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
=begin rdoc
|
|
100
|
+
Shows the line edit where the user can enter the filter regexp and gives it focus
|
|
101
|
+
=end
|
|
102
|
+
def show_editor
|
|
103
|
+
@editor.show
|
|
104
|
+
@editor.set_focus
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
=begin rdoc
|
|
108
|
+
Removes the existing filter (if any).
|
|
109
|
+
|
|
110
|
+
This means that, after calling this method, all items will be accepted
|
|
111
|
+
=end
|
|
112
|
+
def clear_filter
|
|
113
|
+
@filter_model.filter_reg_exp = ''
|
|
114
|
+
set_state 'no_filter', true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def scroll_to idx
|
|
118
|
+
case idx
|
|
119
|
+
when Numeric
|
|
120
|
+
rc = @filter_model.row_count
|
|
121
|
+
if idx >= rc then idx = rc -1
|
|
122
|
+
elsif idx < 0 and idx.abs < rc then idx = rc + idx
|
|
123
|
+
elsif idx < 0 then idx = 0
|
|
124
|
+
end
|
|
125
|
+
mod_idx = @filter_model.index idx, 0
|
|
126
|
+
@view.scroll_to mod_idx
|
|
127
|
+
when Qt::ModelIndex
|
|
128
|
+
idx = @filter_model.map_from_source idx unless idx.model == @filter_model
|
|
129
|
+
idx = @filter_model.index(@filter_model.row_count - 1, 0) unless idx.valid?
|
|
130
|
+
@view.scroll_to idx
|
|
131
|
+
when nil
|
|
132
|
+
@view.scroll_to @filter_model.index(@filter_model.row_count - 1, 0)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
=begin rdoc
|
|
139
|
+
Creates the 'Create Filter', 'Ignore Filter' and 'Clear Filter' actions, their
|
|
140
|
+
state handlers and makes the necessary signal-slot connections
|
|
141
|
+
=end
|
|
142
|
+
def create_standard_actions
|
|
143
|
+
super
|
|
144
|
+
acts = []
|
|
145
|
+
acts << KDE::Action.new('Create Filter', self){self.object_name = 'create_filter'}
|
|
146
|
+
acts << KDE::Action.new('Clear Filter', self){self.object_name = 'clear_filter'}
|
|
147
|
+
acts << KDE::ToggleAction.new('Ignore Filter', self){self.object_name = 'ignore_filter'}
|
|
148
|
+
acts.each{|a| actions[a.object_name] = a}
|
|
149
|
+
connect actions['create_filter'], SIGNAL(:triggered), self, SLOT(:show_editor)
|
|
150
|
+
connect actions['clear_filter'], SIGNAL(:triggered), self, SLOT(:clear_filter)
|
|
151
|
+
connect actions['ignore_filter'], SIGNAL('toggled(bool)'), self, SLOT('ignore_filter(bool)')
|
|
152
|
+
register_action_handler actions['clear_filter'], '!no_filter'
|
|
153
|
+
register_action_handler actions['ignore_filter'], '!no_filter'
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
=begin rdoc
|
|
157
|
+
Instructs the filter model to ignore or not the filter according to _val_.
|
|
158
|
+
=end
|
|
159
|
+
def ignore_filter val
|
|
160
|
+
@filter_model.ignore_filter = val
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
=begin rdoc
|
|
164
|
+
Changes the filter accordig to the text in the line edit.
|
|
165
|
+
|
|
166
|
+
If the line edit is empty, the filter will be removed. Otherwise, it will be set
|
|
167
|
+
to the regexp corresponding to the text in the editor
|
|
168
|
+
=end
|
|
169
|
+
def create_filter_from_editor
|
|
170
|
+
text = @editor.text
|
|
171
|
+
if !text.empty?
|
|
172
|
+
mod = @editor.completion_object.add_item text
|
|
173
|
+
@filter_model.filter_reg_exp = text
|
|
174
|
+
set_state 'no_filter', false
|
|
175
|
+
else clear_filter
|
|
176
|
+
end
|
|
177
|
+
@editor.hide
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
=begin rdoc
|
|
181
|
+
Override of OutputWidget#copy which takes into account the filter. This means that
|
|
182
|
+
only the items in the filter model will be taken into account.
|
|
183
|
+
|
|
184
|
+
<b>Note:</b> the indexes passed to <tt>text_for_clipboard</tt> refer to the source
|
|
185
|
+
model, as in OutputWidget, not to the filter model.
|
|
186
|
+
=end
|
|
187
|
+
def copy
|
|
188
|
+
items = []
|
|
189
|
+
stack = []
|
|
190
|
+
@filter_model.row_count.times do |r|
|
|
191
|
+
@filter_model.column_count.times do |c|
|
|
192
|
+
stack << @filter_model.index(r, c)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
until stack.empty?
|
|
196
|
+
it = stack.shift
|
|
197
|
+
items << @filter_model.map_to_source(it)
|
|
198
|
+
(@filter_model.row_count(it)-1).downto(0) do |r|
|
|
199
|
+
(@filter_model.column_count(it)-1).downto(0) do |c|
|
|
200
|
+
stack.unshift it.child(r, c)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
clp = KDE::Application.clipboard
|
|
205
|
+
clp.text = text_for_clipboard items
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
=begin rdoc
|
|
209
|
+
Override of OutputWidget#copy_selected.
|
|
210
|
+
|
|
211
|
+
<b>Note:</b> the indexes passed to <tt>text_for_clipboard</tt> refer to the source
|
|
212
|
+
model, as in OutputWidget, not to the filter model.
|
|
213
|
+
=end
|
|
214
|
+
def copy_selected
|
|
215
|
+
clp = KDE::Application.clipboard
|
|
216
|
+
indexes = @view.selection_model.selected_indexes.map{|i| @filter_model.map_to_source i}
|
|
217
|
+
clp.text = text_for_clipboard indexes
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
=begin rdoc
|
|
221
|
+
Override of OutputWidget#maybe_open_file.
|
|
222
|
+
|
|
223
|
+
It converts the index _idx_ to the source model before passing it to *super*.
|
|
224
|
+
If _idx_ already refers to the source model, it is passed as it is to *super*.
|
|
225
|
+
=end
|
|
226
|
+
def maybe_open_file idx
|
|
227
|
+
idx = @filter_model.map_to_source idx if idx.model.same? @filter_model
|
|
228
|
+
super idx
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
=begin rdoc
|
|
232
|
+
Filter model derived from <tt>Qt::SortFilterProxyModel</tt> which better integrate
|
|
233
|
+
with FilteredOutputWidget.
|
|
234
|
+
|
|
235
|
+
The differences between this class and <tt>Qt::SortFilterProxyModel</tt> are the
|
|
236
|
+
following
|
|
237
|
+
* it has the ability to ignore the filter (see FilteredOutputWidget)
|
|
238
|
+
* it provides an easy way to always accept some kind of items (see +exclude+ and
|
|
239
|
+
<tt>exclude_from_filtering?</tt>)
|
|
240
|
+
* it emits a signal when the filter reg exp is changed
|
|
241
|
+
|
|
242
|
+
<b>Note:</b> this class is meant to be used with a regexp filter, not with a string
|
|
243
|
+
filter.
|
|
244
|
+
|
|
245
|
+
===Signals
|
|
246
|
+
=====<tt>filter_changed(QString reg)</tt>
|
|
247
|
+
Signal emitted when the regexp used for filtering changes (including when the
|
|
248
|
+
filter is removed). _reg_ is a string containing the source of the regexp.
|
|
249
|
+
=end
|
|
250
|
+
class FilterModel < Qt::SortFilterProxyModel
|
|
251
|
+
|
|
252
|
+
signals 'filter_changed(QString)'
|
|
253
|
+
|
|
254
|
+
=begin rdoc
|
|
255
|
+
The kind of items to exclude from filtering. See <tt>exclude_from_filtering?</tt>
|
|
256
|
+
=end
|
|
257
|
+
attr_reader :exclude
|
|
258
|
+
|
|
259
|
+
=begin rdoc
|
|
260
|
+
Creates a new FilterModel.
|
|
261
|
+
|
|
262
|
+
_parent_ is the parent object, while _exclude_ is the initial value of the +exclude+
|
|
263
|
+
attribute (which can be changed later).
|
|
264
|
+
=end
|
|
265
|
+
def initialize parent = nil, exclude = nil
|
|
266
|
+
super parent
|
|
267
|
+
@exclude = exclude
|
|
268
|
+
@ignore_filter = false
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
=begin rdoc
|
|
272
|
+
Tells whether the object has been instructed to ignore the filter
|
|
273
|
+
=end
|
|
274
|
+
def filter_ignored?
|
|
275
|
+
@ignore_filter
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
=begin rdoc
|
|
279
|
+
Instructs the model to ignore or not the filter, according to _val_. This method
|
|
280
|
+
always invalidate the model
|
|
281
|
+
=end
|
|
282
|
+
def ignore_filter= val
|
|
283
|
+
@ignore_filter = val
|
|
284
|
+
invalidate
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
=begin rdoc
|
|
288
|
+
Override of <tt>Qt::SortFilterProxyModel#filter_reg_exp=</tt> which, after changing the regexp (
|
|
289
|
+
and invalidating the model) emits the <tt>filter_changed(QString)</tt> signal
|
|
290
|
+
=end
|
|
291
|
+
def filter_reg_exp= str
|
|
292
|
+
super
|
|
293
|
+
emit filter_changed(str)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def exclude= val
|
|
297
|
+
@exclude = val
|
|
298
|
+
invalidate_filter
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
protected
|
|
302
|
+
|
|
303
|
+
=begin rdoc
|
|
304
|
+
Override of <tt>Qt::SortFilterProxyModel#filterAcceptsRow</tt> which also takes
|
|
305
|
+
into account the setting for <tt>filter_ignored?</tt> and +exclude+. In particular,
|
|
306
|
+
if <tt>filter_ignored?</tt> is *true* or if <tt>exclude_from_filtering?</tt> returns
|
|
307
|
+
*true* for the given row and parent, then it will always return *true*. Otherwise,
|
|
308
|
+
it behaves like <tt>Qt::SortFilterProxyModel#filterAcceptsRow</tt>
|
|
309
|
+
=end
|
|
310
|
+
def filterAcceptsRow r, parent
|
|
311
|
+
return true if @ignore_filter
|
|
312
|
+
return true if exclude_from_filtering? r, parent
|
|
313
|
+
super
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
=begin rdoc
|
|
317
|
+
Tells the filter whether the filter should be applied to the given row and parent
|
|
318
|
+
or whether it should always be accepted, according to the value of +exclude+. In
|
|
319
|
+
particular:
|
|
320
|
+
* if +exclude+ is +:toplevel+, then the filter will be applied only to child items
|
|
321
|
+
(toplevel items will always be accepted)
|
|
322
|
+
* if +exclude+ is +:children+, then the filter will be applied only to toplevel items
|
|
323
|
+
(child items will always be accepted)
|
|
324
|
+
* any other value will cause the filter to be applied to all items
|
|
325
|
+
|
|
326
|
+
Derived classes can modify this behaviour by overriding this method. The arguments
|
|
327
|
+
have the same meaning as sin +filterAcceptsRow+
|
|
328
|
+
=end
|
|
329
|
+
def exclude_from_filtering? r, parent
|
|
330
|
+
case @exclude
|
|
331
|
+
when :toplevel then !parent.valid?
|
|
332
|
+
when :children then parent.valid?
|
|
333
|
+
else false
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
end
|