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