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,353 @@
|
|
|
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 'facets/kernel/require_relative'
|
|
22
|
+
require_relative 'ui/choose_plugins_widget'
|
|
23
|
+
|
|
24
|
+
module Ruber
|
|
25
|
+
|
|
26
|
+
=begin rdoc
|
|
27
|
+
Dialog where the user can choose the plugins to load and the directories where
|
|
28
|
+
to look for plugins.
|
|
29
|
+
|
|
30
|
+
The main functionality is provided by the main widget, of class ChoosePluginsWidget.
|
|
31
|
+
=end
|
|
32
|
+
class ChoosePluginsDlg < KDE::Dialog
|
|
33
|
+
|
|
34
|
+
slots :write_settings
|
|
35
|
+
|
|
36
|
+
=begin rdoc
|
|
37
|
+
Creates a new +ChoosePluginsDlg+ and initializes it using both the settings
|
|
38
|
+
in the configuration file and the loaded plugins.
|
|
39
|
+
=end
|
|
40
|
+
def initialize parent = nil
|
|
41
|
+
super
|
|
42
|
+
self.caption = "Choose plugins"
|
|
43
|
+
self.buttons = Ok | Cancel | Apply | Default | Reset
|
|
44
|
+
self.main_widget = ChoosePluginsWidget.new
|
|
45
|
+
enable_button_apply false
|
|
46
|
+
main_widget.connect(SIGNAL('plugins_changed()')){enable_button_apply true}
|
|
47
|
+
main_widget.connect(SIGNAL('directories_changed()')){enable_button_apply true}
|
|
48
|
+
connect self, SIGNAL(:applyClicked), self, SLOT(:write_settings)
|
|
49
|
+
connect self, SIGNAL(:okClicked), self, SLOT(:write_settings)
|
|
50
|
+
connect self, SIGNAL(:defaultClicked), main_widget, SLOT(:apply_defaults)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# See ChoosePluginsWidget#plugins
|
|
54
|
+
def plugins
|
|
55
|
+
main_widget.plugins
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
=begin rdoc
|
|
61
|
+
Writes the settings to the configuration file and disables the Apply button
|
|
62
|
+
=end
|
|
63
|
+
def write_settings
|
|
64
|
+
main_widget.write_settings
|
|
65
|
+
enable_button_apply false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
=begin rdoc
|
|
69
|
+
Override the default behaviour when the user presses the Ok or Apply buttons and
|
|
70
|
+
there are problems with dependencies (unresolved dependencies or circular dependencies).
|
|
71
|
+
In this case, it displays a message box where the user can choose whether he
|
|
72
|
+
truly wants to save the settings or not. If he chooses to write the settings,
|
|
73
|
+
the usual behaviour is followed. Otherwise, the method does nothing.
|
|
74
|
+
=end
|
|
75
|
+
def slotButtonClicked btn
|
|
76
|
+
if btn == Ok || btn == Apply and !main_widget.deps_satisfied?
|
|
77
|
+
msg = "There are dependencies problems among plugins. Are you sure you want to accept these settings?"
|
|
78
|
+
if KDE::MessageBox.question_yes_no(nil, msg) == KDE::MessageBox::Yes
|
|
79
|
+
super
|
|
80
|
+
else return
|
|
81
|
+
end
|
|
82
|
+
else super
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
=begin rdoc
|
|
89
|
+
Widget which implements most of the functionality of the ChoosePluginsDlg class.
|
|
90
|
+
|
|
91
|
+
It contains a list of plugins in the current search path, where the user can choose
|
|
92
|
+
the plugins to load (using checkboxes), and a list of directories where the user
|
|
93
|
+
can choose where to look for plugins.
|
|
94
|
+
|
|
95
|
+
In the plugin list, chosen plugins are shown with a selected mark, while plugins
|
|
96
|
+
which will be loaded to satisfy the dependencies of chosen plugins will be shown
|
|
97
|
+
with a partial mark.
|
|
98
|
+
|
|
99
|
+
Whenever the user changes the chosen plugins, the dependencies are re-computed.
|
|
100
|
+
If there's a problem, the user is warned with a message box.
|
|
101
|
+
=end
|
|
102
|
+
class ChoosePluginsWidget < Qt::Widget
|
|
103
|
+
|
|
104
|
+
signals :directories_changed, :plugins_changed
|
|
105
|
+
|
|
106
|
+
slots :add_directory, :remove_directory, :write_settings, :apply_defaults,
|
|
107
|
+
'plugin_toggled(QStandardItem*)'
|
|
108
|
+
|
|
109
|
+
=begin rdoc
|
|
110
|
+
Creates a new ChoosePluginsWidget.
|
|
111
|
+
|
|
112
|
+
The list of directories where to look for plugins is read from the configuration
|
|
113
|
+
file. The chosen plugins are read from the configuration file, but excluding all
|
|
114
|
+
those which aren't currently loaded (the reason to do so is that a chosen plugin
|
|
115
|
+
might have failed to load and thus it should not appear in the chosen list). Also,
|
|
116
|
+
any plugin which is included in the chosen list but whose PDF can't be found is
|
|
117
|
+
excluded.
|
|
118
|
+
|
|
119
|
+
Dependencies are then computed, and dependencies of the chosen plugins are marked
|
|
120
|
+
as such. If a dependency problem occurs, the user is warned and all plugins are
|
|
121
|
+
deselected.
|
|
122
|
+
=end
|
|
123
|
+
def initialize parent = nil
|
|
124
|
+
super
|
|
125
|
+
@ui = Ui::ChoosePluginsWidget.new
|
|
126
|
+
@ui.setupUi self
|
|
127
|
+
|
|
128
|
+
dirs = Ruber[:config][:general].plugin_dirs
|
|
129
|
+
|
|
130
|
+
@chosen_plugins = Ruber[:config][:general, :plugins].map(&:to_sym)
|
|
131
|
+
loaded = Ruber[:components].plugins.map(&:plugin_name)
|
|
132
|
+
@chosen_plugins.delete_if{|i| !loaded.include? i}
|
|
133
|
+
|
|
134
|
+
read_plugins dirs
|
|
135
|
+
res = find_deps(:warning) do |e|
|
|
136
|
+
"There were problems making dependencies. #{create_failure_message e}\nAll plugins will be deselected"
|
|
137
|
+
end
|
|
138
|
+
if res
|
|
139
|
+
@chosen_plugins.clear
|
|
140
|
+
@needed_plugins = []
|
|
141
|
+
end
|
|
142
|
+
m = Qt::StandardItemModel.new @ui.plugins
|
|
143
|
+
@ui.plugins.model = m
|
|
144
|
+
|
|
145
|
+
connect m, SIGNAL('itemChanged(QStandardItem*)'), self, SLOT('plugin_toggled(QStandardItem*)')
|
|
146
|
+
|
|
147
|
+
def m.flags idx
|
|
148
|
+
Qt::ItemIsSelectable|Qt::ItemIsEnabled| Qt::ItemIsUserCheckable
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
@url = KDE::UrlRequester.new self
|
|
152
|
+
@ui.directories.custom_editor = @url.custom_editor
|
|
153
|
+
@url.mode = KDE::File::Directory | KDE::File::LocalOnly
|
|
154
|
+
connect @ui.directories, SIGNAL(:changed), self, SLOT(:slot_directories_changed)
|
|
155
|
+
@ui.directories.items = dirs
|
|
156
|
+
|
|
157
|
+
fill_plugin_list
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def sizeHint #:nodoc:
|
|
162
|
+
Qt::Size.new 600, 550
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
=begin rdoc
|
|
166
|
+
Writes the settings to the configuration file. The directories listed in the
|
|
167
|
+
directory widget are stored in the <i>general/plugin_dirs</i> entry, while
|
|
168
|
+
the chosen plugins are stored in the <i>general/plugins</i> entry. Plugins
|
|
169
|
+
which haven't been chosen but are dependencies of the chosen ones aren't stored.
|
|
170
|
+
=end
|
|
171
|
+
def write_settings
|
|
172
|
+
dirs = @ui.directories.items
|
|
173
|
+
Ruber[:config][:general,:plugin_dirs] = dirs
|
|
174
|
+
plugins = []
|
|
175
|
+
@ui.plugins.model.each_row do |r|
|
|
176
|
+
plugins << r[0].data.to_string if r[0].fully_checked?
|
|
177
|
+
end
|
|
178
|
+
Ruber[:config][:general, :plugins] = plugins
|
|
179
|
+
Ruber[:config].write
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
=begin rdoc
|
|
183
|
+
Sets both the chosen plugins and the plugin directories to their default values
|
|
184
|
+
(see Appplication::DEFAULT_PLUGIN_PATHS and Application::DEFAULT_PLUGINS). If a
|
|
185
|
+
dependency problem occurs, the user is warned and all plugins are deselected
|
|
186
|
+
=end
|
|
187
|
+
def apply_defaults
|
|
188
|
+
dirs = Ruber[:config].default :general, :plugin_dirs
|
|
189
|
+
@chosen_plugins = Ruber[:config].default( :general, :plugins).split(',').map{|i| i.to_sym}
|
|
190
|
+
read_plugins dirs
|
|
191
|
+
res = find_deps(:warning) do |e|
|
|
192
|
+
"There were problems making dependencies. #{create_failure_message e}\nAll plugins will be deselected"
|
|
193
|
+
end
|
|
194
|
+
if res
|
|
195
|
+
@chosen_plugins.clear
|
|
196
|
+
@needed_plugins = []
|
|
197
|
+
end
|
|
198
|
+
@ui.directories.clear
|
|
199
|
+
@ui.directories.items = dirs
|
|
200
|
+
|
|
201
|
+
fill_plugin_list
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
=begin rdoc
|
|
205
|
+
Returns *false* if there's a dependency problem among the chosen plugins and
|
|
206
|
+
*true* otherwise.
|
|
207
|
+
=end
|
|
208
|
+
def deps_satisfied?
|
|
209
|
+
begin
|
|
210
|
+
find_deps
|
|
211
|
+
true
|
|
212
|
+
rescue ComponentManager::UnresolvedDep, ComponentManager::CircularDep
|
|
213
|
+
false
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
=begin rdoc
|
|
218
|
+
Returns a hash containing both the chosen plugins and their dependencies. The
|
|
219
|
+
keys are the plugin names, while the values are the directories of the plugins.
|
|
220
|
+
=end
|
|
221
|
+
def plugins
|
|
222
|
+
@ui.plugins.model.enum_for(:each_row).map do |name, _, dir|
|
|
223
|
+
[name.data.to_string.to_sym, dir.text] if name.checked?
|
|
224
|
+
end.compact.to_h
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
private
|
|
228
|
+
|
|
229
|
+
=begin rdoc
|
|
230
|
+
Finds all the plugins in subdirectories of directories in the _dir_ array,
|
|
231
|
+
reads their PDFs and stores the data in the <tt>@plugins_files</tt> and
|
|
232
|
+
<tt>@plugin_data</tt> instance variables. Also removes from the <tt>@chosen</tt>
|
|
233
|
+
instance variable the plugins whose PDF wasn't found.
|
|
234
|
+
=end
|
|
235
|
+
def read_plugins dirs
|
|
236
|
+
@plugins_files = ComponentManager.find_plugins dirs, true
|
|
237
|
+
@plugin_data = @plugins_files.map{|_, v| [v.name, v]}.to_h
|
|
238
|
+
@chosen_plugins.delete_if{|i| !@plugin_data[i]}
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
=begin rdoc
|
|
242
|
+
Finds the dependencies of the chosen plugins and stores them in the
|
|
243
|
+
<tt>@needed_plugins</tt> instance variable. If a dependency error occurs, if a
|
|
244
|
+
block was passed, a message box of type _type_ is displayed. The text of the
|
|
245
|
+
message box is obtained by calling the block with the exception as argument. If
|
|
246
|
+
an error occurs and no block is passed, the exception is passed on.
|
|
247
|
+
|
|
248
|
+
This method returns *nil* if no error occurs and the value returned by the
|
|
249
|
+
message box otherwise.
|
|
250
|
+
=end
|
|
251
|
+
def find_deps msg_type = :warning
|
|
252
|
+
chosen_data = @chosen_plugins.map{|i| @plugin_data[i]}
|
|
253
|
+
begin @needed_plugins = ComponentManager.fill_dependencies chosen_data, @plugin_data.values
|
|
254
|
+
rescue ComponentManager::UnresolvedDep, ComponentManager::CircularDep => e
|
|
255
|
+
if block_given? then KDE::MessageBox.send(msg_type, yield(e))
|
|
256
|
+
else raise
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
nil
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
=begin rdoc
|
|
263
|
+
Fills the list of plugins with the names, descriptions and paths of all plugins
|
|
264
|
+
found and marks each one according to whether it is among the chosen plugins,
|
|
265
|
+
the needed plugins or neither.
|
|
266
|
+
|
|
267
|
+
It also resizes the columns of the plugin list widget so that they match the
|
|
268
|
+
size of the contents.
|
|
269
|
+
=end
|
|
270
|
+
def fill_plugin_list
|
|
271
|
+
m = @ui.plugins.model
|
|
272
|
+
m.clear
|
|
273
|
+
m.horizontal_header_labels = %w[Name Description Directory]
|
|
274
|
+
@plugins_files.each do |k, v|
|
|
275
|
+
name = Qt::StandardItem.new v.about.human_name
|
|
276
|
+
name.data = Qt::Variant.new(k.to_s)
|
|
277
|
+
desc = Qt::StandardItem.new v.about.description
|
|
278
|
+
dir = Qt::StandardItem.new v.directory
|
|
279
|
+
m.append_row [name, desc, dir]
|
|
280
|
+
end
|
|
281
|
+
update_plugin_status
|
|
282
|
+
3.times{|i| @ui.plugins.resize_column_to_contents i}
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
=begin rdoc
|
|
286
|
+
Changes the contents of the <tt>@chosen_plugins</tt> and <tt>@needed_plugins</tt>
|
|
287
|
+
instance variable to reflect the checked status of the plugins in the plugin list
|
|
288
|
+
widget. Emits the <tt>plugins_changed</tt> signal.
|
|
289
|
+
=end
|
|
290
|
+
def update_plugin_status
|
|
291
|
+
@ui.plugins.model.each_row do |name, desc, dir|
|
|
292
|
+
plug_name = name.data.to_string.to_sym
|
|
293
|
+
state = if @chosen_plugins.include? plug_name then Qt::Checked
|
|
294
|
+
elsif @needed_plugins.include? plug_name then Qt::PartiallyChecked
|
|
295
|
+
else Qt::Unchecked
|
|
296
|
+
end
|
|
297
|
+
name.check_state = state
|
|
298
|
+
end
|
|
299
|
+
emit plugins_changed
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
=begin rdoc
|
|
303
|
+
Updates the plugin status to reflect the changes made to the plugin corresponding
|
|
304
|
+
to the item _it_.
|
|
305
|
+
=end
|
|
306
|
+
def plugin_toggled it
|
|
307
|
+
name = it.data.to_string
|
|
308
|
+
if it.check_state == Qt::Checked then @chosen_plugins << name.to_sym
|
|
309
|
+
else @chosen_plugins.delete name.to_sym
|
|
310
|
+
end
|
|
311
|
+
find_deps{|e| create_failure_message( e) + "\nPlease, be sure to correct the problem before accepting changes" }
|
|
312
|
+
update_plugin_status
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
=begin rdoc
|
|
316
|
+
Updates the plugin widgets and emits the {#directories_changed signal}
|
|
317
|
+
|
|
318
|
+
If the dependencies aren't respected, the user is warned with a message box.
|
|
319
|
+
@return [nil]
|
|
320
|
+
=end
|
|
321
|
+
def slot_directories_changed
|
|
322
|
+
new_dirs = @ui.directories.items
|
|
323
|
+
find_deps{|e| create_failure_message( e) + "\nPlease, be sure to correct the problem before accepting changes" }
|
|
324
|
+
fill_plugin_list
|
|
325
|
+
emit directories_changed
|
|
326
|
+
nil
|
|
327
|
+
end
|
|
328
|
+
slots :slot_directories_changed
|
|
329
|
+
|
|
330
|
+
=begin rdoc
|
|
331
|
+
Creates an appropriate failure message for the exception _e_, which should be
|
|
332
|
+
an instance of ComponentManager::DependencyError. It is meant to generate consistent
|
|
333
|
+
error messages for all the places in the widget where a dependency error can
|
|
334
|
+
happen.
|
|
335
|
+
=end
|
|
336
|
+
def create_failure_message e
|
|
337
|
+
case e
|
|
338
|
+
when ComponentManager::UnresolvedDep
|
|
339
|
+
deps = e.missing.map do |p1, p2|
|
|
340
|
+
"#{d}, needed by #{pl.join ', '}"
|
|
341
|
+
end
|
|
342
|
+
"Some dependencies couldn't be satisifed:\n#{deps.join "\n"}"
|
|
343
|
+
when ComponentManager::CircularDep
|
|
344
|
+
deps = e.missing.map do |p1, p2|
|
|
345
|
+
"#{p1} and #{p2}"
|
|
346
|
+
end
|
|
347
|
+
"There were circular dependencies between the following plugins:\n#{deps.join "\n"}"
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
end
|
|
@@ -0,0 +1,524 @@
|
|
|
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
|
+
# Special comments used here to mark things to do:
|
|
22
|
+
# OBSOLETE: method to remove (or likely so)
|
|
23
|
+
# MOVE: method which should be moved somewhere else (to another class)
|
|
24
|
+
|
|
25
|
+
require 'forwardable'
|
|
26
|
+
|
|
27
|
+
require 'ruber/plugin_like'
|
|
28
|
+
require 'ruber/gui_states_handler'
|
|
29
|
+
|
|
30
|
+
require 'ruber/main_window/main_window_internal'
|
|
31
|
+
require 'ruber/main_window/main_window_actions'
|
|
32
|
+
|
|
33
|
+
require 'ruber/main_window/status_bar'
|
|
34
|
+
require 'ruber/main_window/workspace'
|
|
35
|
+
|
|
36
|
+
module Ruber
|
|
37
|
+
|
|
38
|
+
=begin rdoc
|
|
39
|
+
The application's main window. It is made of a menu bar, a tool bar, a workspace
|
|
40
|
+
and a status bar. The workspace (see Workspace) is the main window's central widget
|
|
41
|
+
and where most of the user interaction happens. It contains the editors and the
|
|
42
|
+
tool widgets.
|
|
43
|
+
=end
|
|
44
|
+
class MainWindow < KParts::MainWindow
|
|
45
|
+
|
|
46
|
+
include PluginLike
|
|
47
|
+
|
|
48
|
+
include GuiStatesHandler
|
|
49
|
+
|
|
50
|
+
extend Forwardable
|
|
51
|
+
##
|
|
52
|
+
# :method: current_document_changed(QObject* obj) [SIGNAL]
|
|
53
|
+
# Signal emitted whenever the current document changes. _obj_ is the new current
|
|
54
|
+
# document and will be <tt>Qt::NilObject</tt> if there's no current document.
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# :method: active_editor_changed(QObject* obj) [SIGNAL]
|
|
58
|
+
# Signal emitted whenever the active editor changes _obj_ is the new active editor
|
|
59
|
+
# and will be <tt>Qt::NilObject</tt> if there's no active editor
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
signals 'current_document_changed(QObject*)', 'active_editor_changed(QObject*)'
|
|
63
|
+
|
|
64
|
+
slots :load_settings
|
|
65
|
+
|
|
66
|
+
=begin rdoc
|
|
67
|
+
The widget which contains the tool widgets.
|
|
68
|
+
|
|
69
|
+
The primary use of this method is to connect to the signals emitted from the workspace
|
|
70
|
+
when a tool widget is raised, shown or hidden. All of its other methods are also
|
|
71
|
+
provided by the MainWindow, so you shouldn't need to access the workspace to use
|
|
72
|
+
them.
|
|
73
|
+
=end
|
|
74
|
+
attr_reader :workspace
|
|
75
|
+
|
|
76
|
+
=begin rdoc
|
|
77
|
+
A hash with the data stored in the session manager by plugins. The hash is only
|
|
78
|
+
availlable after the <tt>restore</tt> method has been called (which means that it
|
|
79
|
+
will always be unavaillable if ruber wasn't started by the session manager). If
|
|
80
|
+
the hash isn't availlable, *nil* is returned
|
|
81
|
+
|
|
82
|
+
<b>NOTE:</b> only for use by Application when restoring the session
|
|
83
|
+
=end
|
|
84
|
+
attr_reader :last_session_data
|
|
85
|
+
|
|
86
|
+
=begin rdoc
|
|
87
|
+
Creates a new MainWindow. <i>_manager</i> is the component manager, while _pdf_
|
|
88
|
+
is the plugin description for this object.
|
|
89
|
+
=end
|
|
90
|
+
def initialize _manager, pdf
|
|
91
|
+
super nil, 0
|
|
92
|
+
initialize_plugin pdf
|
|
93
|
+
initialize_states_handler
|
|
94
|
+
self.central_widget = Workspace.new self
|
|
95
|
+
# We need the instance variable to use it with Forwardable
|
|
96
|
+
@workspace = central_widget
|
|
97
|
+
@views = central_widget.instance_variable_get :@views
|
|
98
|
+
@current_view = nil
|
|
99
|
+
@active_editor = nil
|
|
100
|
+
@auto_activate_editors = true
|
|
101
|
+
@editors_mapper = Qt::SignalMapper.new self
|
|
102
|
+
@ui_states = {}
|
|
103
|
+
@actions_state_handlers = Hash.new{|h, k| h[k] = []}
|
|
104
|
+
@about_plugin_actions = []
|
|
105
|
+
@last_session_data = nil
|
|
106
|
+
self.status_bar = StatusBar.new self
|
|
107
|
+
self.connect(SIGNAL('current_document_changed(QObject*)')) do |doc|
|
|
108
|
+
change_state 'current_document', !doc.nil_object?
|
|
109
|
+
end
|
|
110
|
+
connect Ruber[:components], SIGNAL('component_loaded(QObject*)'), self, SLOT('add_about_plugin_action(QObject*)')
|
|
111
|
+
connect Ruber[:components], SIGNAL('unloading_component(QObject*)'), self, SLOT('remove_about_plugin_action(QObject*)')
|
|
112
|
+
connect Ruber[:components], SIGNAL('unloading_component(QObject*)'), self, SLOT('remove_plugin_ui_actions(QObject*)')
|
|
113
|
+
connect @editors_mapper, SIGNAL('mapped(QWidget*)'), self, SLOT('remove_view(QWidget*)')
|
|
114
|
+
setup_actions action_collection
|
|
115
|
+
@views.connect(SIGNAL('currentChanged(int)')) do |idx|
|
|
116
|
+
if @auto_activate_editors then activate_editor idx
|
|
117
|
+
else activate_editor nil
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
Ruber[:projects].connect( SIGNAL('current_project_changed(QObject*)') ) do |prj|
|
|
121
|
+
change_state "active_project_exists", !prj.nil?
|
|
122
|
+
make_title
|
|
123
|
+
end
|
|
124
|
+
connect Ruber[:projects], SIGNAL('closing_project(QObject*)'), self, SLOT('close_project_files(QObject*)')
|
|
125
|
+
|
|
126
|
+
setup_GUI
|
|
127
|
+
create_shell_GUI true
|
|
128
|
+
|
|
129
|
+
config_obj = Ruber[:config].kconfig
|
|
130
|
+
apply_main_window_settings KDE::ConfigGroup.new( config_obj, 'MainWindow')
|
|
131
|
+
recent_files = KDE::ConfigGroup.new config_obj, 'Recent files'
|
|
132
|
+
action_collection.action("file_open_recent").load_entries recent_files
|
|
133
|
+
recent_projects = KDE::ConfigGroup.new config_obj, 'Recent projects'
|
|
134
|
+
action_collection.action("project-open_recent").load_entries recent_projects
|
|
135
|
+
status_bar.show
|
|
136
|
+
setup_initial_states
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
# :method: add_tool
|
|
141
|
+
# Adds a tool widget to the main window. See Workspace#add_tool_widget for more information.
|
|
142
|
+
def_delegator :@workspace, :add_tool_widget, :add_tool
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# :method: remove_tool
|
|
146
|
+
# Removes a tool widget from the main window. See Workspace#remove_tool_widget for more information.
|
|
147
|
+
def_delegator :@workspace, :remove_tool_widget, :remove_tool
|
|
148
|
+
|
|
149
|
+
##
|
|
150
|
+
# :method: toggle_tool
|
|
151
|
+
# Activates a tool widget if it was hidden and hides it if it was active.
|
|
152
|
+
# See Workspace#toggle_tool for more information.
|
|
153
|
+
def_delegators :@workspace, :toggle_tool
|
|
154
|
+
|
|
155
|
+
##
|
|
156
|
+
# :method: raise_tool
|
|
157
|
+
# Activates a tool widget. See Workspace#raise_tool for more information.
|
|
158
|
+
def_delegators :@workspace, :raise_tool
|
|
159
|
+
|
|
160
|
+
##
|
|
161
|
+
# :method: show_tool
|
|
162
|
+
# Displays a tool widget. See Workspace#show_tool for more information.
|
|
163
|
+
def_delegators :@workspace, :show_tool
|
|
164
|
+
|
|
165
|
+
##
|
|
166
|
+
# :method: activate_tool
|
|
167
|
+
# Shows and gives focus to a tool. See Workspace#activate_tool for more information.
|
|
168
|
+
def_delegators :@workspace, :activate_tool
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# :method: hide_tool
|
|
172
|
+
# Hides a tool widget. See Workspace#hide_tool for more information.
|
|
173
|
+
def_delegators :@workspace, :hide_tool
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
# :method: tool_widgets
|
|
177
|
+
# Returns a hash having the tool widgets as keys and their positions as values.
|
|
178
|
+
# See Workspace#tool_widgets for more information.
|
|
179
|
+
def_delegators :@workspace, :tool_widgets
|
|
180
|
+
|
|
181
|
+
=begin rdoc
|
|
182
|
+
Returns the editor view for the given document, creating it if needed
|
|
183
|
+
|
|
184
|
+
@param [Document, String, KDE::Url] doc the document. If it is a string representing
|
|
185
|
+
an absolute path, the document will be obtained using {DocumentList#document},
|
|
186
|
+
while for other strings it will be obtained using {DocumentList#document_with_name}
|
|
187
|
+
@return [EditorView,nil] an editor associated with the document or *nil* if _doc_
|
|
188
|
+
is interpreted as document name but no documents with that name exists
|
|
189
|
+
@raise [ArgumentError] if _doc_ is an absolute path or a @KDE::Url@ but the file
|
|
190
|
+
doesn't exist
|
|
191
|
+
=end
|
|
192
|
+
def editor_for! doc
|
|
193
|
+
doc = unless doc.is_a? Document
|
|
194
|
+
if doc.is_a? KDE::Url or doc.start_with? '/' then Ruber[:documents].document doc
|
|
195
|
+
else Ruber[:documents].document_with_name doc
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
return unless doc
|
|
199
|
+
create_editor_if_needed doc
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
=begin rdoc
|
|
203
|
+
Similar to <tt>editor_for!</tt> but it doesn't create the document or the editor
|
|
204
|
+
if they don't exist. If a Document for the string _doc_ doesn't exist, or if it
|
|
205
|
+
doesn't have an editor, returns *nil*.
|
|
206
|
+
=end
|
|
207
|
+
def editor_for doc
|
|
208
|
+
doc = Ruber[:documents][doc] if doc.is_a? String
|
|
209
|
+
return unless doc
|
|
210
|
+
doc.view
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
=begin rdoc
|
|
214
|
+
Returns the active editor, or *nil* if there's no active editor.
|
|
215
|
+
|
|
216
|
+
<b>Note:</b> strictly speaking, this is not the same as <tt>tab_widget.current_widget</tt>.
|
|
217
|
+
For an editor to be active, it's not enough to be in the current tab, but it also
|
|
218
|
+
need to having been its gui merged with the main window gui.
|
|
219
|
+
|
|
220
|
+
TODO: in all places this is called, change the name from <tt>current_view</tt> to
|
|
221
|
+
<tt>active_editor</tt>.
|
|
222
|
+
=end
|
|
223
|
+
def active_editor
|
|
224
|
+
@active_editor
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
=begin rdoc
|
|
228
|
+
Returns the editor in the current tab, or *nil* if there's no tab. Note that this
|
|
229
|
+
may not be the active editor.
|
|
230
|
+
=end
|
|
231
|
+
def current_editor
|
|
232
|
+
@views.current_widget
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
=begin rdoc
|
|
236
|
+
Activates an editor. _arg_ can be either the index of a widget in the tab widget
|
|
237
|
+
(for internal uses only) or the editor to activate, or *nil*. If the editor to
|
|
238
|
+
activate is not in the current tab, the tab which contains it will become the current
|
|
239
|
+
one. Activating an editor deactivates the previously active one.
|
|
240
|
+
|
|
241
|
+
Activating an editor means merging its GUI with the main window's GUI, changing
|
|
242
|
+
the title of the main window accordingly and telling the status bar to refer to
|
|
243
|
+
that view. Also, the <tt>current_document_changed</tt> and <tt>active_editor_changed</tt>
|
|
244
|
+
signals are emitted.
|
|
245
|
+
=end
|
|
246
|
+
def activate_editor arg
|
|
247
|
+
view = arg.is_a?(Integer) ? @views.widget( arg ) : arg
|
|
248
|
+
@views.current_widget = view if view and @views.current_widget != view
|
|
249
|
+
deactivate_editor @active_editor if @active_editor != view
|
|
250
|
+
@active_editor = view
|
|
251
|
+
if @active_editor
|
|
252
|
+
gui_factory.add_client @active_editor.doc.view.send(:internal)
|
|
253
|
+
@active_editor.document.activate
|
|
254
|
+
end
|
|
255
|
+
make_title
|
|
256
|
+
status_bar.view = @active_editor
|
|
257
|
+
emit current_document_changed @active_editor ? @active_editor.document : Qt::NilObject
|
|
258
|
+
emit active_editor_changed @active_editor || Qt::NilObject
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
=begin rdoc
|
|
262
|
+
Returns the document associated with the active editor or *nil* if there's no
|
|
263
|
+
current editor.
|
|
264
|
+
|
|
265
|
+
It's almost the same as <tt>active_editor.doc</tt>, but already takes care of
|
|
266
|
+
the case when <tt>active_editor</tt> is *nil*.
|
|
267
|
+
=end
|
|
268
|
+
def current_document
|
|
269
|
+
view = @views.current_widget
|
|
270
|
+
view ? view.doc : nil
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
=begin rdoc
|
|
274
|
+
Similar to <tt>editor_for!</tt> but, after having retrieved/created the editor
|
|
275
|
+
view, it activates and gives focus to it and moves the cursor to the line _line_
|
|
276
|
+
and column _col_ (both of them are 0-based indexes).
|
|
277
|
+
=end
|
|
278
|
+
def display_doc doc, line = nil, col = 0
|
|
279
|
+
ed = editor_for! doc
|
|
280
|
+
return unless ed
|
|
281
|
+
activate_editor ed
|
|
282
|
+
ed.go_to line, col if line and col
|
|
283
|
+
ed.set_focus
|
|
284
|
+
end
|
|
285
|
+
alias display_document display_doc
|
|
286
|
+
|
|
287
|
+
=begin rdoc
|
|
288
|
+
Executes the contents of the block with automatical editor activation disabled.
|
|
289
|
+
This should be used, for example, when more than one editor should be opened at
|
|
290
|
+
once. Without this, every new editor would become (for a little time) the active
|
|
291
|
+
one, with its gui merged with the main window and so on. This slows things down
|
|
292
|
+
and should be avoided. To do so, you use this method:
|
|
293
|
+
Ruber[:main_window].without_activating do
|
|
294
|
+
ed = nil
|
|
295
|
+
files.each do |f|
|
|
296
|
+
ed = Ruber[:main_window].editor_for! f
|
|
297
|
+
end
|
|
298
|
+
Ruber[:main_window].activate_editor ed
|
|
299
|
+
end
|
|
300
|
+
After the block has been called, if there is no editor, or if the current widget
|
|
301
|
+
in the tab widget is different from the active editor, the current widget will
|
|
302
|
+
be activated.
|
|
303
|
+
<b>Note:</b> automatical editor activation will be restored at the end of this
|
|
304
|
+
method (even if exceptions occur).
|
|
305
|
+
=end
|
|
306
|
+
def without_activating
|
|
307
|
+
begin
|
|
308
|
+
@auto_activate_editors = false
|
|
309
|
+
yield
|
|
310
|
+
ensure
|
|
311
|
+
@auto_activate_editors = true
|
|
312
|
+
if @views.current_index < 0 then activate_editor nil
|
|
313
|
+
elsif @views.current_widget != @active_editor
|
|
314
|
+
activate_editor @views.current_widget
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
=begin rdoc
|
|
320
|
+
Closes the editor _ed_, deleting its tab and closing the corresponding document
|
|
321
|
+
and activating the next tab if auto activating is on. If _ask_ is *true*, the document
|
|
322
|
+
will ask whether to save modifications, otherwise it won't
|
|
323
|
+
=end
|
|
324
|
+
def close_editor ed, ask = true
|
|
325
|
+
ed.document.close_view ed, ask
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
=begin rdoc
|
|
329
|
+
This method is meant to be called in situation where the user may want to save
|
|
330
|
+
a number of documents, for example when the application is quitting, as it avoids
|
|
331
|
+
displaying a dialog box for each modified document.
|
|
332
|
+
|
|
333
|
+
_docs_ can be either an array containing the documents which can be saved (documents
|
|
334
|
+
in it which aren't modified will be ignored) or *nil*. In this case, all the
|
|
335
|
+
open documents (with or without an open editor) will be taken into account.
|
|
336
|
+
|
|
337
|
+
It displays a dialog where the user can choose, among the documents passed as
|
|
338
|
+
first argument, which ones he wants to save. The user has three choiches:
|
|
339
|
+
* save some (or all) the files, then proceed with the operation which has caused
|
|
340
|
+
the dialog to be shown (for example, quitting the application)
|
|
341
|
+
* don't save any file and go on with the operation
|
|
342
|
+
* abort the operation.
|
|
343
|
+
|
|
344
|
+
In the first case, this method attempts to perform save the selected files. If
|
|
345
|
+
any of them can't be saved, the dialog to choose the files to save will be
|
|
346
|
+
displayed again, with only those files which couldn't be saved (after informing
|
|
347
|
+
the user of the failure). The user can again chose which of those files this method
|
|
348
|
+
should attempt to save again, or whether to abort the operation or skip saving.
|
|
349
|
+
This will be repeated until all files have been saved or the user gives up
|
|
350
|
+
|
|
351
|
+
In the second and third cases, the method simply returns respectively +true+ or
|
|
352
|
+
*false*.
|
|
353
|
+
|
|
354
|
+
The value returned by this method is *false* if the user choose to abort the
|
|
355
|
+
operation and *true* otherwise. Calling methods should act appropriately (for
|
|
356
|
+
example, if this is called from a method which closes all documents and returns
|
|
357
|
+
*false*, the documents should't be closed. If it returns true, instead, they
|
|
358
|
+
should be closed, without asking again to save them).
|
|
359
|
+
|
|
360
|
+
<b>Note:</b> if _docs_ only contains non-modified documents, this method will
|
|
361
|
+
do nothing and immediately return *true*.
|
|
362
|
+
=end
|
|
363
|
+
def save_documents docs = nil
|
|
364
|
+
docs ||= Ruber[:docs]
|
|
365
|
+
to_save = docs.select{|d| d.modified?}
|
|
366
|
+
until to_save.empty?
|
|
367
|
+
dlg = SaveModifiedFilesDlg.new to_save, self
|
|
368
|
+
case dlg.exec
|
|
369
|
+
when KDE::Dialog::Yes
|
|
370
|
+
to_save = Ruber[:docs].save_documents dlg.to_save
|
|
371
|
+
unless to_save.empty?
|
|
372
|
+
msg = "The following documents couldn't be saved: #{to_save.join "\n"}\nPlease, choose how to proceed"
|
|
373
|
+
KDE::MessageBox.sorry nil, KDE.i18n(msg)
|
|
374
|
+
end
|
|
375
|
+
when KDE::Dialog::No then to_save.clear
|
|
376
|
+
when Qt::Dialog::Rejected then return false
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
true
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
=begin rdoc
|
|
383
|
+
Asks the user whether to save the modified documents and saves the chosen ones.
|
|
384
|
+
Returns *true* all the selected documents where saved and *false* if some of the
|
|
385
|
+
document couldn't be saved.
|
|
386
|
+
MOVE: this should be moved to DocumentList, as there might be documents without
|
|
387
|
+
a window
|
|
388
|
+
=end
|
|
389
|
+
def query_close
|
|
390
|
+
if Ruber[:app].session_saving
|
|
391
|
+
@session_data = Ruber[:components].session_data
|
|
392
|
+
end
|
|
393
|
+
true
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
=begin rdoc
|
|
397
|
+
Provides a standard interface to creating a project from a project file named _file_, automatically
|
|
398
|
+
handling the possible exceptions. In particular, a message box will be displayed
|
|
399
|
+
if the project file doesn't exist or if it exists but it's not a valid project file.
|
|
400
|
+
A message box is also displayed if <i>allow_reuse</i> is *false* and the project
|
|
401
|
+
list already contains a project corresponding to _file_. In all cases in which a
|
|
402
|
+
message box is displayed *nil* is returned. Otherwise, the +Project+ object
|
|
403
|
+
corresponding to +file+ is returned.
|
|
404
|
+
|
|
405
|
+
If a project was created from the project file, it will be made active and the
|
|
406
|
+
old active project (if any) will be closed.
|
|
407
|
+
|
|
408
|
+
<b>Note:</b> _file_ must be an absolute path.
|
|
409
|
+
=end
|
|
410
|
+
def safe_open_project file, allow_reuse = false
|
|
411
|
+
prj = Ruber[:projects][file]
|
|
412
|
+
if !allow_reuse and prj
|
|
413
|
+
text = "A project corresponding to the file #{file} is already open. Please, close it before attempting to open it again"
|
|
414
|
+
KDE::MessageBox.sorry self, KDE.i18n(text)
|
|
415
|
+
return nil
|
|
416
|
+
elsif prj then return prj
|
|
417
|
+
end
|
|
418
|
+
begin prj = Ruber[:projects].project file
|
|
419
|
+
rescue Project::InvalidProjectFile => ex
|
|
420
|
+
text = <<-EOS
|
|
421
|
+
#{file} isn't a valid project file. The error reported was:
|
|
422
|
+
#{ex.message}
|
|
423
|
+
EOS
|
|
424
|
+
KDE::MessageBox.sorry self, KDE.i18n(text)
|
|
425
|
+
return nil
|
|
426
|
+
rescue LoadError
|
|
427
|
+
KDE::MessageBox.sorry self, KDE.i18n(ex.message)
|
|
428
|
+
return nil
|
|
429
|
+
end
|
|
430
|
+
# The following two lines should be removed when we'll allow more than one project
|
|
431
|
+
# open at the same time
|
|
432
|
+
Ruber[:projects].current_project.close if Ruber[:projects].current_project
|
|
433
|
+
Ruber[:projects].current_project = prj
|
|
434
|
+
prj
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
=begin rdoc
|
|
438
|
+
Saves recent files and projects, the position of the splitters and the size of
|
|
439
|
+
the window.
|
|
440
|
+
|
|
441
|
+
TODO: since restoring window position seems to work correctly in Kate (even if
|
|
442
|
+
there's still an open bug, it seems to work, at least for me) see whether it's
|
|
443
|
+
still necessary to store the window size.
|
|
444
|
+
=end
|
|
445
|
+
def save_settings
|
|
446
|
+
@workspace.store_sizes
|
|
447
|
+
# TODO use Ruber[:config] as soon as it works
|
|
448
|
+
# config = Ruber[:config].kconfig
|
|
449
|
+
config = KDE::Global.config
|
|
450
|
+
recent_files = KDE::ConfigGroup.new config, 'Recent files'
|
|
451
|
+
action_collection.action("file_open_recent").save_entries recent_files
|
|
452
|
+
recent_projects = KDE::ConfigGroup.new config, 'Recent projects'
|
|
453
|
+
action_collection.action("project-open_recent").save_entries recent_projects
|
|
454
|
+
config.sync
|
|
455
|
+
c = Ruber[:config][:main_window]
|
|
456
|
+
c.window_size = rect.size
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
=begin rdoc
|
|
460
|
+
Loads the settings (in particular, the default script directory and the
|
|
461
|
+
default project directory)
|
|
462
|
+
=end
|
|
463
|
+
def load_settings
|
|
464
|
+
c = Ruber[:config][:general]
|
|
465
|
+
@default_script_dir = KDE::Url.from_path c.default_script_directory
|
|
466
|
+
@default_project_dir = KDE::Url.from_path c.default_project_directory
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
=begin rdoc
|
|
470
|
+
Gives the focus to the current editor view. _ed_ can be:
|
|
471
|
+
* an EditorView
|
|
472
|
+
* any argument acceptable by <tt>editor_for!</tt>
|
|
473
|
+
* *nil*
|
|
474
|
+
In the first two cases, the editor corresponding to _ed_ is activated and given
|
|
475
|
+
focus; in the last case the active editor is given focus.
|
|
476
|
+
=end
|
|
477
|
+
def focus_on_editor ed = nil
|
|
478
|
+
if ed
|
|
479
|
+
ed = editor_for! ed unless ed.is_a? EditorView
|
|
480
|
+
activate_editor ed if ed
|
|
481
|
+
end
|
|
482
|
+
@active_editor.set_focus if @active_editor
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
=begin rdoc
|
|
486
|
+
The directory where to save files which don't belong to a project
|
|
487
|
+
=end
|
|
488
|
+
# def scripts_directory
|
|
489
|
+
# @default_script_dir
|
|
490
|
+
# end
|
|
491
|
+
|
|
492
|
+
=begin rdoc
|
|
493
|
+
The directory where to create new projects by default
|
|
494
|
+
=end
|
|
495
|
+
def projects_directory
|
|
496
|
+
@default_project_dir
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
=begin rdoc
|
|
500
|
+
Executes the action with name _action_ contained in the main window's action collection.
|
|
501
|
+
|
|
502
|
+
See <tt>GuiPlugin#execute_action</tt> for more details
|
|
503
|
+
=end
|
|
504
|
+
def execute_action name, *args
|
|
505
|
+
data = plugin_description.actions[name.to_s]
|
|
506
|
+
if data
|
|
507
|
+
slot = data.slot.sub(/\(.*/, '')
|
|
508
|
+
instance_eval(data.receiver).send slot, *args
|
|
509
|
+
true
|
|
510
|
+
elsif (action = action_collection.action(name))
|
|
511
|
+
if action.class == KDE::ToggleAction then KDE::ToggleAction
|
|
512
|
+
action.instance_eval{emit toggled(*args)}
|
|
513
|
+
elsif action.class == KDE::Action
|
|
514
|
+
action.instance_eval{emit triggered()}
|
|
515
|
+
else action.instance_eval{emit triggered(*args)}
|
|
516
|
+
end
|
|
517
|
+
true
|
|
518
|
+
else false
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
end
|