ruber 0.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,411 @@
|
|
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_relative 'ui/find_in_files_widget'
|
22
|
+
|
23
|
+
module Ruber
|
24
|
+
|
25
|
+
module FindInFiles
|
26
|
+
|
27
|
+
=begin rdoc
|
28
|
+
Dialog to set options for search/replace in files.
|
29
|
+
|
30
|
+
A single dialog is used for both search and replace. The action performed depends on whether the user clicks the Find or the Replace button.
|
31
|
+
This dialog can be used either as a modal or modeless dialog: if it is modal, use the value returned by #action to see whether the user chose find or replace; in modeless mode rely on the #find and #replace signals.
|
32
|
+
=end
|
33
|
+
class FindReplaceInFilesDlg < KDE::Dialog
|
34
|
+
|
35
|
+
=begin rdoc
|
36
|
+
Signal emitted when the user presses the Find button.
|
37
|
+
=end
|
38
|
+
signals :find
|
39
|
+
|
40
|
+
=begin rdoc
|
41
|
+
Signal emitted when the user presses the Replace button.
|
42
|
+
=end
|
43
|
+
signals :replace
|
44
|
+
|
45
|
+
=begin rdoc
|
46
|
+
A list of possible matching modes
|
47
|
+
=end
|
48
|
+
MODES = [:regexp, :plain]
|
49
|
+
|
50
|
+
=begin rdoc
|
51
|
+
A list of possible files where to search files
|
52
|
+
=end
|
53
|
+
PLACES = [:project_files, :project_dir, :open_files, :custom_dir]
|
54
|
+
|
55
|
+
=begin rdoc
|
56
|
+
A map between the text shown in the file type widget and rak options
|
57
|
+
=end
|
58
|
+
FILE_TYPES = {
|
59
|
+
'C++ files' => :cpp,
|
60
|
+
'C files' => :c,
|
61
|
+
'C# files' => :csharp,
|
62
|
+
'CSS files' => :css,
|
63
|
+
'Elisp files' => :elisp,
|
64
|
+
'Erlang files' => :erlang,
|
65
|
+
'Fortran files' => :fortran,
|
66
|
+
'Haskell files' => :haskell,
|
67
|
+
'hh files' => :hh,
|
68
|
+
'HTML files' => :html,
|
69
|
+
'Java files' => :java,
|
70
|
+
'Javascript file' => :js,
|
71
|
+
'jsp files' => :jsp,
|
72
|
+
'Lisp files' => :lisp,
|
73
|
+
'Makefiles' => :make,
|
74
|
+
'Mason files' => :mason,
|
75
|
+
'OCaml files' => :ocaml,
|
76
|
+
'Parrot files' => :parrot,
|
77
|
+
'Perl files' => :perl,
|
78
|
+
'PHP files' => :php,
|
79
|
+
'Prolog files' => :prolog,
|
80
|
+
'Python files' => :python,
|
81
|
+
'Ruby files' => :ruby,
|
82
|
+
'Scheme files' => :scheme,
|
83
|
+
'Shell files' => :shell,
|
84
|
+
'SQL files' => :sql,
|
85
|
+
'TCL files' => :tcl,
|
86
|
+
'TeX files' => :tex,
|
87
|
+
'Text files' => :text,
|
88
|
+
'tt files' => :tt,
|
89
|
+
'Visual Basic files' => :vb,
|
90
|
+
'Vim files' => :vim,
|
91
|
+
'XML files' => :xml,
|
92
|
+
'YAML files' => :yaml
|
93
|
+
}
|
94
|
+
|
95
|
+
=begin rdoc
|
96
|
+
A specialized completer for use with the line edits in the dialog.
|
97
|
+
|
98
|
+
The only difference from the standard @Qt::Completer@ is that it creates its model by itself
|
99
|
+
=end
|
100
|
+
class Completer < Qt::Completer
|
101
|
+
|
102
|
+
=begin rdoc
|
103
|
+
@param [Qt::Widget, nil] parent the completer's parent object
|
104
|
+
=end
|
105
|
+
def initialize parent = nil
|
106
|
+
super
|
107
|
+
self.model = Qt::StringListModel.new self
|
108
|
+
end
|
109
|
+
|
110
|
+
=begin rdoc
|
111
|
+
Adds a new string to the completer
|
112
|
+
|
113
|
+
@param [String] str the string to add
|
114
|
+
@return [nil]
|
115
|
+
=end
|
116
|
+
def add_entry str
|
117
|
+
row = model.row_count
|
118
|
+
model.insert_rows row, 1
|
119
|
+
model.set_data model.index(row), Qt::Variant.new(str), Qt::DisplayRole
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
=begin rdoc
|
125
|
+
The action chosen by the user when closing the dialog
|
126
|
+
@return [Symbol, nil] @:find@ if the user pressed the Find button, @:replace@ if
|
127
|
+
he chose the Replace button and *nil* if he pressed the Cancel button or if the
|
128
|
+
dialog hasn’t been closed as yet
|
129
|
+
=end
|
130
|
+
attr_reader :action
|
131
|
+
|
132
|
+
=begin rdoc
|
133
|
+
@param [Qt::Widget, nil] parent the parent widget
|
134
|
+
=end
|
135
|
+
def initialize parent = Ruber[:main_window]
|
136
|
+
@operation = nil
|
137
|
+
super
|
138
|
+
set_buttons User1|User2|Cancel
|
139
|
+
set_button_text User1, KDE.i18n('Replace')
|
140
|
+
set_button_text User2, KDE.i18n('Find')
|
141
|
+
set_default_button User2
|
142
|
+
enable_button User1, false
|
143
|
+
enable_button User2, false
|
144
|
+
|
145
|
+
@ui = ::Ui::FindReplaceInFilesWidget.new
|
146
|
+
@ui.setupUi main_widget
|
147
|
+
|
148
|
+
@ui.find_text.completer = Completer.new @ui.find_text
|
149
|
+
@ui.replace_text.completer = Completer.new @ui.replace_text
|
150
|
+
@ui.custom_filter.completer = Completer.new @ui.custom_filter
|
151
|
+
|
152
|
+
@ui.directory.mode = KDE::File::Directory
|
153
|
+
|
154
|
+
|
155
|
+
@ui.find_text.connect SIGNAL('textChanged(QString)') do
|
156
|
+
enable = !@ui.find_text.text.empty?
|
157
|
+
enable_button User1, enable
|
158
|
+
enable_button User2, enable
|
159
|
+
end
|
160
|
+
|
161
|
+
@ui.replace_text.connect(SIGNAL('textChanged(QString)')) do
|
162
|
+
self.default_button = @ui.replace_text.text.empty? ? User2 : User1
|
163
|
+
end
|
164
|
+
|
165
|
+
@ui.places.connect(SIGNAL('currentIndexChanged(int)')) do |i|
|
166
|
+
@ui.directory.enabled = (i == @ui.places.count - 1)
|
167
|
+
end
|
168
|
+
|
169
|
+
button(User1).connect SIGNAL(:clicked) do
|
170
|
+
@action = :replace
|
171
|
+
add_completions
|
172
|
+
accept
|
173
|
+
emit replace
|
174
|
+
end
|
175
|
+
|
176
|
+
button(User2).connect SIGNAL(:clicked) do
|
177
|
+
@action = :find
|
178
|
+
add_completions
|
179
|
+
accept
|
180
|
+
emit find
|
181
|
+
end
|
182
|
+
|
183
|
+
@ui.use_predefined_filters.connect SIGNAL('toggled(bool)') do |b|
|
184
|
+
@ui.types.enabled = b
|
185
|
+
end
|
186
|
+
|
187
|
+
@ui.all_files.connect SIGNAL('toggled(bool)') do |b|
|
188
|
+
@ui.types.enabled = !b
|
189
|
+
end
|
190
|
+
|
191
|
+
@ui.types.line_edit.read_only = true
|
192
|
+
@ui.types.view.install_event_filter Filter.new(self)
|
193
|
+
@ui.types.view.viewport.install_event_filter Filter.new(self)
|
194
|
+
@ui.types.add_items FILE_TYPES.keys.sort
|
195
|
+
@ui.types.model.each do |i|
|
196
|
+
i.checkable = true
|
197
|
+
i.checked = (i.text == 'Ruby files' || i.text == 'YAML files')
|
198
|
+
end
|
199
|
+
create_filter_text
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
=begin rdoc
|
204
|
+
Whether the "Project files" and "Project directory" entries should be shown
|
205
|
+
in the _Search in_ widget or not.
|
206
|
+
@param [Boolean] val whether to show the entries or not
|
207
|
+
@return [Boolean] _val_
|
208
|
+
=end
|
209
|
+
def allow_project= val
|
210
|
+
if @ui.places.count == 4 and !val
|
211
|
+
2.times{@ui.places.remove_item 0}
|
212
|
+
elsif @ui.places.count == 2 and val
|
213
|
+
@ui.places.insert_items 0, ['Project files', 'Project directory']
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
=begin rdoc
|
218
|
+
The text in the Find widget
|
219
|
+
@return [String] the text in the Find widget
|
220
|
+
=end
|
221
|
+
def find_text
|
222
|
+
@ui.find_text.text
|
223
|
+
end
|
224
|
+
|
225
|
+
=begin rdoc
|
226
|
+
The text in the Replace widget
|
227
|
+
@return [String] the text in the Replace widget
|
228
|
+
=end
|
229
|
+
def replacement_text
|
230
|
+
@ui.replace_text.text
|
231
|
+
end
|
232
|
+
|
233
|
+
=begin rdoc
|
234
|
+
The mode chosen by the user.
|
235
|
+
@return [Symbol] the mode chosen by the user. It can be either @:regexp@ or @:plain@
|
236
|
+
=end
|
237
|
+
def mode
|
238
|
+
MODES[@ui.mode.current_index]
|
239
|
+
end
|
240
|
+
|
241
|
+
=begin rdoc
|
242
|
+
Whether the search should be performed only in whole words or not
|
243
|
+
|
244
|
+
@return [Boolean] whether the user chose to perform a search only on whole words
|
245
|
+
or also in the middle of a word
|
246
|
+
=end
|
247
|
+
def whole_words?
|
248
|
+
@ui.whole_words.checked?
|
249
|
+
end
|
250
|
+
|
251
|
+
=begin rdoc
|
252
|
+
Whether the search should be case sensitive or not
|
253
|
+
|
254
|
+
@return [Boolean] whether or not the user chose to perform a case sensitive search
|
255
|
+
=end
|
256
|
+
def case_sensitive?
|
257
|
+
@ui.case_sensitive.checked?
|
258
|
+
end
|
259
|
+
|
260
|
+
=begin rdoc
|
261
|
+
The file types the search should be restricted to
|
262
|
+
@return [<Symbol>, nil] an array containing the file types the user chose in the
|
263
|
+
types combo box (converted so they match the name of the options rak accepts) or
|
264
|
+
nil if the user checked the _All files_ radio button
|
265
|
+
=end
|
266
|
+
def filters
|
267
|
+
if @ui.use_predefined_filters.checked?
|
268
|
+
@ui.types.model.map{|i| i.checked? ? FILE_TYPES[i.text] : nil}.compact
|
269
|
+
else nil
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
=begin rdoc
|
274
|
+
The regexp to pass to rak -g option
|
275
|
+
|
276
|
+
@return [String, nil] the source of the regexp or *nil* if the user didn’t fill
|
277
|
+
the _Custom filter_ widget
|
278
|
+
=end
|
279
|
+
def custom_filter
|
280
|
+
text = @ui.custom_filter.text
|
281
|
+
text.empty? ? nil : text
|
282
|
+
end
|
283
|
+
|
284
|
+
=begin rdoc
|
285
|
+
Whether the search should be made on all files or only on some file types
|
286
|
+
|
287
|
+
@return [Boolean] whether the search should be performed on all files or only in
|
288
|
+
those with file type matching the entries selected in the File type combo box
|
289
|
+
=end
|
290
|
+
def all_files?
|
291
|
+
@ui.all_files.checked?
|
292
|
+
end
|
293
|
+
|
294
|
+
=begin rdoc
|
295
|
+
Where to find the files to search:
|
296
|
+
|
297
|
+
@return [Symbol] one of the following symbols, according to what the user chose
|
298
|
+
in the _Search in_ combo box:
|
299
|
+
* @:project_files@ perform the search only among the files belonging to the current project
|
300
|
+
* @:project_directory@ perform the search among all the files in the current proejct’s directory
|
301
|
+
* @:open_files@ perform the search only in files corresponding to open documents (note that the search will be performed in the files, not in the text in the documents)
|
302
|
+
* @:custom_dir@ perform the search among all the files in the directory selected by the user in the Directory widget
|
303
|
+
=end
|
304
|
+
def places
|
305
|
+
idx = @ui.places.current_index
|
306
|
+
idx +=2 if @ui.places.count == 2
|
307
|
+
PLACES[idx]
|
308
|
+
end
|
309
|
+
|
310
|
+
=begin rdoc
|
311
|
+
The contents of the Directory widget
|
312
|
+
@return [String, nil] the contents of the Directory widget or nil if the wigdet
|
313
|
+
is disabled (because the user chose something else than _Custom directory_ in the
|
314
|
+
_Search in_ widget)
|
315
|
+
=end
|
316
|
+
def directory
|
317
|
+
@ui.directory.enabled? ? @ui.directory.text : nil
|
318
|
+
end
|
319
|
+
|
320
|
+
=begin rdoc
|
321
|
+
Sets the contents of the dialog’s widgets to their default values
|
322
|
+
|
323
|
+
This method doesn't erase the completers and is usually called before showing the dialog.
|
324
|
+
*Note:* this also sets allow_project to true
|
325
|
+
=end
|
326
|
+
def clear
|
327
|
+
self.allow_project = true
|
328
|
+
@action = nil
|
329
|
+
@ui.find_text.text=''
|
330
|
+
@ui.replace_text.clear
|
331
|
+
@ui.mode.current_index = 0
|
332
|
+
@ui.whole_words.checked = false
|
333
|
+
@ui.case_sensitive.checked = true
|
334
|
+
@ui.use_predefined_filters.checked = true
|
335
|
+
@ui.custom_filter.clear
|
336
|
+
@ui.places.current_index = 0
|
337
|
+
@ui.find_text.set_focus
|
338
|
+
@ui.directory.enabled = false
|
339
|
+
end
|
340
|
+
|
341
|
+
=begin rdoc
|
342
|
+
Event filter to make the Predefined filters combo box be checkable.
|
343
|
+
|
344
|
+
@return [Boolean] *true* if the event should be blocked and *false* if it should be propagated
|
345
|
+
=end
|
346
|
+
def eventFilter obj, e
|
347
|
+
if e.type == Qt::Event::MouseButtonRelease
|
348
|
+
obj=obj.parent unless obj.is_a?(Qt::ListView)
|
349
|
+
idx = obj.index_at e.pos
|
350
|
+
if idx.valid?
|
351
|
+
op = Qt::StyleOption.new
|
352
|
+
op.initFrom obj
|
353
|
+
op.rect = obj.visual_rect(idx)
|
354
|
+
r = obj.style.sub_element_rect(Qt::Style::SE_ViewItemCheckIndicator, op)
|
355
|
+
if r.contains(e.pos)
|
356
|
+
it = @ui.types.model.item_from_index idx
|
357
|
+
it.checked = !it.checked?
|
358
|
+
create_filter_text
|
359
|
+
return true
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
false
|
364
|
+
end
|
365
|
+
|
366
|
+
private
|
367
|
+
|
368
|
+
=begin rdoc
|
369
|
+
Adds the values in the various line edit widgets to the respective completers
|
370
|
+
|
371
|
+
@return [nil]
|
372
|
+
=end
|
373
|
+
def add_completions
|
374
|
+
@ui.find_text.completer.add_entry @ui.find_text.text
|
375
|
+
@ui.replace_text.completer.add_entry @ui.replace_text.text unless @ui.replace_text.text.empty?
|
376
|
+
@ui.custom_filter.completer.add_entry @ui.custom_filter.text unless @ui.custom_filter.text.empty?
|
377
|
+
end
|
378
|
+
|
379
|
+
=begin rdoc
|
380
|
+
Fills the text of the File type widget with a string according to the selected entries
|
381
|
+
|
382
|
+
@return [nil]
|
383
|
+
=end
|
384
|
+
def create_filter_text
|
385
|
+
text = @ui.types.model.select{|i| i.checked?}.map{|i| i.text}.join '; '
|
386
|
+
text = 'All files' if text.empty?
|
387
|
+
@ui.types.edit_text = text
|
388
|
+
end
|
389
|
+
|
390
|
+
=begin rdoc
|
391
|
+
@private
|
392
|
+
|
393
|
+
Helper class whose only task is to have an eventFilter method which calls its parent’s eventFilter.
|
394
|
+
|
395
|
+
It’s needed because setting the dialog as event filter object doesn’t seem to work
|
396
|
+
=end
|
397
|
+
class Filter < Qt::Object
|
398
|
+
=begin rdoc
|
399
|
+
Calls the parent object's @eventFilter@ method
|
400
|
+
@return [Boolean] what the parent object's @eventFilter@ method returned
|
401
|
+
=end
|
402
|
+
def eventFilter o, e
|
403
|
+
parent.eventFilter o, e
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE kpartgui SYSTEM 'kpartgui.dtd'>
|
2
|
+
<kpartplugin version="1" name="ruber-find_in_files" >
|
3
|
+
<MenuBar>
|
4
|
+
<Menu name="edit" >
|
5
|
+
<text>&Edit</text>
|
6
|
+
<Action group="edit_find_plugins" name="find_in_files-find_replace" />
|
7
|
+
<Separator group="edit_find_plugins" />
|
8
|
+
</Menu>
|
9
|
+
</MenuBar>
|
10
|
+
<ActionProperties/>
|
11
|
+
</kpartplugin>
|
@@ -0,0 +1,485 @@
|
|
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 'tempfile'
|
22
|
+
|
23
|
+
require 'ruber/filtered_output_widget'
|
24
|
+
|
25
|
+
require_relative 'ui/config_widget'
|
26
|
+
|
27
|
+
module Ruber
|
28
|
+
|
29
|
+
module FindInFiles
|
30
|
+
|
31
|
+
=begin rdoc
|
32
|
+
Tool widget to display the output of a search.
|
33
|
+
|
34
|
+
It adds the "Filter on file names" toggle action to the RBM menu: when its on,
|
35
|
+
any filter will be applied to the rows containing the file names; when it's off
|
36
|
+
(the default) the filter will only be applied to rows containing the found text.
|
37
|
+
=end
|
38
|
+
class FindWidget < FilteredOutputWidget
|
39
|
+
|
40
|
+
slots 'filter_on_filename_changed(bool)'
|
41
|
+
|
42
|
+
=begin rdoc
|
43
|
+
@private
|
44
|
+
The number of the role used to store the kind of find information stored in an
|
45
|
+
index
|
46
|
+
=end
|
47
|
+
FIND_ROLE = IsTitleRole + 1
|
48
|
+
|
49
|
+
=begin rdoc
|
50
|
+
Creates a new instance
|
51
|
+
@param [Qt::Widget, nil] parent the parent widget
|
52
|
+
=end
|
53
|
+
def initialize parent = nil
|
54
|
+
super parent, :view => :tree, :filter => Filter.new, :use_default_font => true
|
55
|
+
filter_model.filter_key_column = 1
|
56
|
+
filter_model.exclude = :toplevel
|
57
|
+
model.append_column []
|
58
|
+
@current_file_item = Qt::StandardItem.new
|
59
|
+
filter_model.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
|
60
|
+
if !par.valid?
|
61
|
+
st.upto(en) do |i|
|
62
|
+
view.set_first_column_spanned i, par, true
|
63
|
+
view.expand filter_model.index(i, 0, par)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
self.connect(SIGNAL(:about_to_fill_menu)) do
|
68
|
+
actions.delete 'copy'
|
69
|
+
actions.delete 'copy_selected'
|
70
|
+
action_list.delete 'copy'
|
71
|
+
action_list.delete 'copy_selected'
|
72
|
+
end
|
73
|
+
view.all_columns_show_focus = true
|
74
|
+
view.header_hidden = true
|
75
|
+
setup_actions
|
76
|
+
end
|
77
|
+
|
78
|
+
=begin rdoc
|
79
|
+
Displays the output of rak in the widget
|
80
|
+
|
81
|
+
Results in the same file are put under a single parent in the tree
|
82
|
+
|
83
|
+
@param [<String>] lines the output from rak, divided into lines. Each line should
|
84
|
+
have the format @filename line|text@. Lines which don't have this format are ignored
|
85
|
+
@return [nil]
|
86
|
+
=end
|
87
|
+
def display_output lines
|
88
|
+
lines.each do |l|
|
89
|
+
match = l.match(/^(.+)\s+(\d+)\|(.*)$/)
|
90
|
+
next unless match
|
91
|
+
file, line, text = match.to_a[1..-1].map{|i| i.strip}
|
92
|
+
if @current_file_item.text != file
|
93
|
+
@current_file_item = model.insert(file, :message, nil)[0]
|
94
|
+
@current_file_item.set_data Qt::Variant.new('file'), FIND_ROLE
|
95
|
+
end
|
96
|
+
it_line, it_text = model.insert [line.to_s, text], [:output1, :output],
|
97
|
+
nil, :parent => @current_file_item
|
98
|
+
it_line.set_data Qt::Variant.new('line'), FIND_ROLE
|
99
|
+
it_text.set_data Qt::Variant.new('text'), FIND_ROLE
|
100
|
+
end
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
=begin rdoc
|
105
|
+
Remove the contents from the widget
|
106
|
+
|
107
|
+
@return *nil*
|
108
|
+
=end
|
109
|
+
def clear_output
|
110
|
+
@current_file_item = Qt::StandardItem.new
|
111
|
+
super
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
=begin rdoc
|
118
|
+
Adds the custom actions to the RMB menu
|
119
|
+
|
120
|
+
@return [nil]
|
121
|
+
=end
|
122
|
+
def setup_actions
|
123
|
+
a = KDE::ToggleAction.new 'Filter on File Names', self
|
124
|
+
actions['find_in_files-filter_on_files'] = a
|
125
|
+
action_list.insert_after 'clear_filter', nil, 'find_in_files-filter_on_files'
|
126
|
+
connect a, SIGNAL('toggled(bool)'), self, SLOT('filter_on_filename_changed(bool)')
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
=begin rdoc
|
131
|
+
Override of {Ruber::OutputWidget#find_filename_in_index}
|
132
|
+
|
133
|
+
If the index corresponds to a file name, retrieves the line from the
|
134
|
+
first child, while if it corresponds to a another entry, retrieves the file name
|
135
|
+
from its parent and the line from the appropriate column on the same line
|
136
|
+
|
137
|
+
@return [String, Integer] see {Ruber::OutputWidget#find_filename_in_index} for
|
138
|
+
more information
|
139
|
+
=end
|
140
|
+
def find_filename_in_index idx
|
141
|
+
it = model.item_from_index idx
|
142
|
+
if it.data(FIND_ROLE).to_string == 'file'
|
143
|
+
line = it.row_count > 0 ? it.child(0,0).text.to_i : 0
|
144
|
+
[it.text, line]
|
145
|
+
else
|
146
|
+
file = it.parent.text
|
147
|
+
line = (it.data(FIND_ROLE).to_string == 'line' ? it : it.parent.child(it.row, 0)).text.to_i
|
148
|
+
[file, line]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
=begin rdoc
|
153
|
+
Slot called when the user toggles the "Filter on file names" action
|
154
|
+
|
155
|
+
@param [Boolean] on whether the user switched the action on or off
|
156
|
+
=end
|
157
|
+
def filter_on_filename_changed b
|
158
|
+
filter_model.filter_key_column = b ? 0 : 1
|
159
|
+
filter_model.exclude = b ? :children : :toplevel
|
160
|
+
end
|
161
|
+
|
162
|
+
=begin rdoc
|
163
|
+
@private
|
164
|
+
Filter model used by the view in FindWidget
|
165
|
+
=end
|
166
|
+
class Filter < FilterModel
|
167
|
+
|
168
|
+
=begin rdoc
|
169
|
+
Filters a row
|
170
|
+
|
171
|
+
If the filter column is the first, always returns *true* for child rows, while
|
172
|
+
always returns *true* for top level rows for all other values of the filter column
|
173
|
+
|
174
|
+
@return [Boolean]
|
175
|
+
=end
|
176
|
+
def filterAcceptsRow row, parent
|
177
|
+
if filter_key_column == 0
|
178
|
+
parent.valid? ? true : super
|
179
|
+
else parent.valid? ? super : true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
=begin rdoc
|
188
|
+
Tool widget which displays the results of a replace operation
|
189
|
+
|
190
|
+
The widget consists of a checkable tree view with two columns. The first column
|
191
|
+
contains the text which will be replaced, while the second contains the text
|
192
|
+
after the replacement. The user can uncheck the replacements he doesn't want,
|
193
|
+
both linewise or filewise. The replacement is only carried out when the user
|
194
|
+
presses the Replace button in the tool widget. A Clear button empties the tool
|
195
|
+
widget.
|
196
|
+
=end
|
197
|
+
class ReplaceWidget < OutputWidget
|
198
|
+
|
199
|
+
=begin rdoc
|
200
|
+
@private
|
201
|
+
|
202
|
+
Model used in the ReplaceWidget
|
203
|
+
|
204
|
+
It only differs from #{OutputWidget::Model} in the flags it gives to items
|
205
|
+
=end
|
206
|
+
class Model < OutputWidget::Model
|
207
|
+
|
208
|
+
def flags idx
|
209
|
+
default_flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled
|
210
|
+
if !idx.parent.valid? or idx.column == 0
|
211
|
+
default_flags | Qt::ItemIsUserCheckable
|
212
|
+
else default_flags
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
=begin rdoc
|
220
|
+
Signal emitted when a new file is added to the model.
|
221
|
+
|
222
|
+
@param [String] str the name of the file
|
223
|
+
=end
|
224
|
+
signals 'file_added(QString)'
|
225
|
+
|
226
|
+
slots :replace
|
227
|
+
|
228
|
+
slots 'file_modified(QString)'
|
229
|
+
|
230
|
+
=begin rdoc
|
231
|
+
Creates a new instance
|
232
|
+
|
233
|
+
@param [Qt::Object, nil] parent the parent object
|
234
|
+
=end
|
235
|
+
def initialize parent = nil
|
236
|
+
super parent, :view => :tree, :use_default_font => true
|
237
|
+
self.auto_scroll = false
|
238
|
+
model.global_flags |= Qt::ItemIsUserCheckable.to_i
|
239
|
+
def model.flags idx
|
240
|
+
if idx.column == 0 then super idx
|
241
|
+
else (Qt::ItemIsEnabled | Qt::ItemIsSelectable).to_i
|
242
|
+
end
|
243
|
+
end
|
244
|
+
@replace_button = Qt::PushButton.new( 'Replace', self){self.enabled = false}
|
245
|
+
@clear_button = Qt::PushButton.new('Clear', self){self.enabled = false}
|
246
|
+
layout.remove_widget view
|
247
|
+
layout.add_widget view, 0,0,1,0
|
248
|
+
layout.add_widget @replace_button, 1, 0
|
249
|
+
layout.add_widget @clear_button, 1, 1
|
250
|
+
model.horizontal_header_labels = ['Line', 'Original text', 'Replacement text']
|
251
|
+
@file_items = {}
|
252
|
+
@watcher = KDE::DirWatch.new self
|
253
|
+
connect @watcher, SIGNAL('dirty(QString)'), self, SLOT('file_modified(QString)')
|
254
|
+
connect @replace_button, SIGNAL(:clicked), self, SLOT(:replace)
|
255
|
+
connect @clear_button, SIGNAL(:clicked) , self, SLOT(:clear_output)
|
256
|
+
self.connect(SIGNAL(:about_to_fill_menu)) do
|
257
|
+
actions.delete 'copy'
|
258
|
+
actions.delete 'copy_selected'
|
259
|
+
action_list.delete 'copy'
|
260
|
+
action_list.delete 'copy_selected'
|
261
|
+
end
|
262
|
+
model.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
|
263
|
+
if !par.valid?
|
264
|
+
st.upto(en) do |i|
|
265
|
+
view.set_first_column_spanned i, par, true
|
266
|
+
view.expand model.index(i, 0, par)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
Ruber[:find_in_files].connect SIGNAL(:replace_search_started) do
|
271
|
+
@replace_button.enabled = false
|
272
|
+
@clear_button.enabled = false
|
273
|
+
view.header.resize_mode = Qt::HeaderView::Fixed
|
274
|
+
self.cursor = Qt::Cursor.new Qt::WaitCursor
|
275
|
+
end
|
276
|
+
Ruber[:find_in_files].connect SIGNAL(:replace_search_finished) do
|
277
|
+
@watcher.start_scan
|
278
|
+
@replace_button.enabled = true
|
279
|
+
@clear_button.enabled = true
|
280
|
+
h = view.header
|
281
|
+
view.resize_column_to_contents 0
|
282
|
+
view.header.resize_mode = Qt::HeaderView::Fixed
|
283
|
+
av_size = h.rect.width - h.section_size( 0)
|
284
|
+
view.set_column_width 1, av_size / 2.0
|
285
|
+
view.set_column_width 2, av_size / 2.0
|
286
|
+
unset_cursor
|
287
|
+
end
|
288
|
+
view.all_columns_show_focus = true
|
289
|
+
end
|
290
|
+
|
291
|
+
=begin rdoc
|
292
|
+
Inserts the name of the files in the output widget
|
293
|
+
|
294
|
+
Each file is added to the file watcher, so that replacing in it can be disabled
|
295
|
+
if it changes.
|
296
|
+
|
297
|
+
@param [<String>] lines an array containing the name of the files
|
298
|
+
@return [nil]
|
299
|
+
=end
|
300
|
+
def display_output lines
|
301
|
+
lines.each do |l|
|
302
|
+
it = model.insert([l, nil, nil], :message, nil)[0]
|
303
|
+
it.checked = true
|
304
|
+
@watcher.add_file l
|
305
|
+
@watcher.stop_scan
|
306
|
+
@file_items[l] = it
|
307
|
+
emit file_added(l)
|
308
|
+
end
|
309
|
+
nil
|
310
|
+
end
|
311
|
+
|
312
|
+
=begin rdoc
|
313
|
+
Adds a replacement line to the widget
|
314
|
+
|
315
|
+
A replacement line is made of three columns: the line number in the file,
|
316
|
+
the original text and the text after the replacement.
|
317
|
+
|
318
|
+
@param [String] file the file where the line is
|
319
|
+
@param [Integer] line the line number (0 based)
|
320
|
+
@param [String] orig the original text of the line
|
321
|
+
@param [String] repl the text of the line after the replacement
|
322
|
+
@return [nil]
|
323
|
+
=end
|
324
|
+
def add_line file, line, orig, repl
|
325
|
+
parent = @file_items[file]
|
326
|
+
row = model.insert [(line+1).to_s, orig, repl], [:output1, :output, :output], nil, :parent => parent
|
327
|
+
row[0].checked = true
|
328
|
+
view.expand parent.index
|
329
|
+
nil
|
330
|
+
end
|
331
|
+
|
332
|
+
=begin rdoc
|
333
|
+
Empties the widget
|
334
|
+
|
335
|
+
@return [nil]
|
336
|
+
=end
|
337
|
+
def clear_output
|
338
|
+
@file_items.clear
|
339
|
+
@file_items.each_key{|k| @watcher.remove_file k}
|
340
|
+
@replace_button.enabled = false
|
341
|
+
@clear_button.enabled = false
|
342
|
+
super
|
343
|
+
end
|
344
|
+
|
345
|
+
private
|
346
|
+
|
347
|
+
=begin rdoc
|
348
|
+
Performs the replacements chosen by the user
|
349
|
+
|
350
|
+
Calling this method applies replaces the original text with the replacement
|
351
|
+
texts for all the lines chosen by the user (that is, the checked lines which
|
352
|
+
belong to a checked file). A message box is shown if some replacements cannot be
|
353
|
+
carrried out.
|
354
|
+
|
355
|
+
Items corresponding to successful replacements are removed from the view.
|
356
|
+
|
357
|
+
@return [nil]
|
358
|
+
=end
|
359
|
+
def replace
|
360
|
+
failed = {}
|
361
|
+
success = []
|
362
|
+
docs = Ruber[:docs].documents_with_file.map{|d| [d.path, d]}.to_h
|
363
|
+
model.each_row.each_with_index do |r, i|
|
364
|
+
if r[0].checked?
|
365
|
+
res = replace_file r[0], docs[r[0].text]
|
366
|
+
if res then failed[r[0].text] = res
|
367
|
+
else success << r[0]
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
success.reverse_each do |i|
|
372
|
+
@file_items.delete i.text
|
373
|
+
model.remove_row i.row
|
374
|
+
end
|
375
|
+
create_error_message = Proc.new do |f, err|
|
376
|
+
if err == :doc_modified then "#{f}: modified in editor"
|
377
|
+
else "#{f}: #{err.message}"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
unless failed.empty?
|
381
|
+
failed_text = failed.map{|f, err| create_error_message.call f, err}.join "\n"
|
382
|
+
KDE::MessageBox.sorry Ruber[:main_window], "The following files couldn't be modified:\n#{failed_text}"
|
383
|
+
end
|
384
|
+
nil
|
385
|
+
end
|
386
|
+
|
387
|
+
=begin rdoc
|
388
|
+
Carries out the replacements for a file
|
389
|
+
|
390
|
+
If the file is associated with a document and the document isn't modified, the
|
391
|
+
text in the editor is changed to reflect the modifications in the file. If the
|
392
|
+
document is modified (which means its contents differ from the contents of the
|
393
|
+
file), instead, nothing will be done.
|
394
|
+
|
395
|
+
@param [Qt::StandardItem] it the item corresponding to the file in the model
|
396
|
+
@param [Document, nil] doc the document associated with the file, if any
|
397
|
+
@return [Symbol, SystemCallError, nil] *nil* if the replacement was carried out
|
398
|
+
correctly; an exception derived from @SystemCallError@ if it wasn't possible to
|
399
|
+
write the file and the symbol @:doc_modified@ if the replacement wasn't attempted
|
400
|
+
because the document corresponding to the file was modified
|
401
|
+
=end
|
402
|
+
def replace_file it, doc
|
403
|
+
file = it.text
|
404
|
+
lines_to_replace = {}
|
405
|
+
it.each_row do |line, _, repl|
|
406
|
+
lines_to_replace[line.text.to_i] = repl.text if line.checked?
|
407
|
+
end
|
408
|
+
# TODO see what the line below did. In my opinion, it is the remainder of some line
|
409
|
+
# I added for testing and forgot to remove
|
410
|
+
# path = file.sub( '/home/stefano/tmp/ruber', '').gsub('/', '_')
|
411
|
+
lines = File.readlines(file)
|
412
|
+
lines_to_replace.each_pair{|idx, text| lines[idx - 1] = text + "\n"}
|
413
|
+
new_text = lines.join ''
|
414
|
+
if doc
|
415
|
+
pos = doc.view.cursor_position if doc.view
|
416
|
+
return :doc_modified if doc.modified?
|
417
|
+
text = nil
|
418
|
+
doc.editing do
|
419
|
+
text = doc.text
|
420
|
+
doc.clear
|
421
|
+
doc.text = new_text
|
422
|
+
end
|
423
|
+
doc.save
|
424
|
+
doc.view.go_to pos.line, pos.column if pos
|
425
|
+
else
|
426
|
+
Tempfile.open(File.basename(file)) do |f|
|
427
|
+
f.write new_text
|
428
|
+
f.flush
|
429
|
+
begin
|
430
|
+
FileUtils.cp f.path, file
|
431
|
+
rescue SystemCallError => e
|
432
|
+
return e
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
nil
|
437
|
+
end
|
438
|
+
|
439
|
+
=begin rdoc
|
440
|
+
Slot called when a file among those listed for replacement is modified on disk
|
441
|
+
|
442
|
+
When this happens, the file is marked as modified in the view and it is no longer
|
443
|
+
checkable (the same happens for its children)
|
444
|
+
|
445
|
+
@return [nil]
|
446
|
+
=end
|
447
|
+
def file_modified file
|
448
|
+
@watcher.remove_file file
|
449
|
+
it = @file_items[file]
|
450
|
+
if it
|
451
|
+
it.text = it.text + "\t [MODIFIED]"
|
452
|
+
it.checked = false
|
453
|
+
view.collapse it.index
|
454
|
+
model.set_data it.index, Qt::Variant.new, Qt::ForegroundRole
|
455
|
+
it.flags = Qt::ItemIsSelectable
|
456
|
+
it.each_row do |r|
|
457
|
+
r[0].checked = false
|
458
|
+
r.each{|i| i.flags = Qt::ItemIsSelectable}
|
459
|
+
end
|
460
|
+
end
|
461
|
+
nil
|
462
|
+
end
|
463
|
+
|
464
|
+
end
|
465
|
+
|
466
|
+
=begin rdoc
|
467
|
+
The configuration widget for the plugin
|
468
|
+
=end
|
469
|
+
class ConfigWidget < Qt::Widget
|
470
|
+
|
471
|
+
=begin rdoc
|
472
|
+
@param [Qt::Widget, nil] parent the parent widget
|
473
|
+
=end
|
474
|
+
def initialize parent = nil
|
475
|
+
super
|
476
|
+
@ui = ::Ui::FindInFilesConfigWidget.new
|
477
|
+
@ui.setupUi self
|
478
|
+
end
|
479
|
+
|
480
|
+
end
|
481
|
+
|
482
|
+
|
483
|
+
end
|
484
|
+
|
485
|
+
end
|