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,82 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2010 by Stefano Crocco
|
|
3
|
+
stefano.crocco@alice.it
|
|
4
|
+
|
|
5
|
+
This program is free software; you can redistribute it andor modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program; if not, write to the
|
|
17
|
+
Free Software Foundation, Inc.,
|
|
18
|
+
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
19
|
+
=end
|
|
20
|
+
|
|
21
|
+
require 'ruber/plugin_like'
|
|
22
|
+
require 'ruber/settings_container'
|
|
23
|
+
require 'ruber/yaml_option_backend'
|
|
24
|
+
require 'ruber/kde_config_option_backend'
|
|
25
|
+
|
|
26
|
+
module Ruber
|
|
27
|
+
|
|
28
|
+
=begin rdoc
|
|
29
|
+
Class which provides easy access to the KDE::Config for the application using the
|
|
30
|
+
SettingsContainer module and the KDEConfigSettingsBackend classes.
|
|
31
|
+
|
|
32
|
+
Almost all the functionality of this class comes is provided by the SettingsContainer
|
|
33
|
+
module, so see its documentation for more information.
|
|
34
|
+
|
|
35
|
+
===Signals
|
|
36
|
+
<tt>settings_changed</tt>::
|
|
37
|
+
signal emitted whenever the settings changed (actually, this signal is currently
|
|
38
|
+
emitted whenever the +write+ method is called. Since this usually happens when
|
|
39
|
+
the settings have changed, there's not a big difference).
|
|
40
|
+
=end
|
|
41
|
+
class ConfigManager < Qt::Object
|
|
42
|
+
|
|
43
|
+
include PluginLike
|
|
44
|
+
|
|
45
|
+
include SettingsContainer
|
|
46
|
+
|
|
47
|
+
slots :load_settings
|
|
48
|
+
|
|
49
|
+
signals :settings_changed
|
|
50
|
+
|
|
51
|
+
=begin rdoc
|
|
52
|
+
Creates a new +ConfigManager+. <i>_manager</i> is the component manager
|
|
53
|
+
(it is unused, but it's required by the plugin loading system). _pdf_ is the
|
|
54
|
+
PluginSpecification related to this component
|
|
55
|
+
=end
|
|
56
|
+
def initialize _manager, pdf
|
|
57
|
+
super()
|
|
58
|
+
initialize_plugin pdf
|
|
59
|
+
setup_container KDEConfigSettingsBackend.new
|
|
60
|
+
self.dialog_title = 'Configure Ruber'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
=begin rdoc
|
|
64
|
+
Override of SettingsContainer#write which emits the <tt>settings_changed</tt> signal
|
|
65
|
+
after writing back the settings.
|
|
66
|
+
=end
|
|
67
|
+
def write
|
|
68
|
+
super
|
|
69
|
+
emit settings_changed
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
=begin rdoc
|
|
73
|
+
Returns the configuration object. In theory, this shouldn't been needed, but it's
|
|
74
|
+
provided for those few cases when it's needed.
|
|
75
|
+
=end
|
|
76
|
+
def kconfig
|
|
77
|
+
@backend.instance_variable_get :@config
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
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/hash/keys'
|
|
22
|
+
require 'fileutils'
|
|
23
|
+
|
|
24
|
+
begin
|
|
25
|
+
require 'md5'
|
|
26
|
+
rescue LoadError
|
|
27
|
+
require 'digest/md5'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require 'ruber/yaml_option_backend'
|
|
31
|
+
require 'ruber/project'
|
|
32
|
+
|
|
33
|
+
module Ruber
|
|
34
|
+
|
|
35
|
+
class DocumentProject < AbstractProject
|
|
36
|
+
|
|
37
|
+
=begin rdoc
|
|
38
|
+
Backend for SettingsContainer used in particular for ProjectDocuments. It mostly
|
|
39
|
+
works as YamlSettingsBackend, with the following differences:
|
|
40
|
+
* it doesn't create the file if the only option to be written (that is, the only
|
|
41
|
+
one different from its default value) is the +project_name+. In that case, if
|
|
42
|
+
the file already exists, it is deleted
|
|
43
|
+
* it automatically determines the name of the associated file from the name of the
|
|
44
|
+
document
|
|
45
|
+
=end
|
|
46
|
+
class Backend < YamlSettingsBackend
|
|
47
|
+
|
|
48
|
+
=begin rdoc
|
|
49
|
+
Creates a new DocumentProject::Backend. _file_ is the path of the file associated
|
|
50
|
+
with the backend.
|
|
51
|
+
|
|
52
|
+
If _file_ is an invalid project file, the behaviour will be the same as the file
|
|
53
|
+
didn't exist. This means that it will be overwritten when the project is saved.
|
|
54
|
+
The reason for this behaviour is that there should be no user file in the directory
|
|
55
|
+
where document projects are saved.
|
|
56
|
+
=end
|
|
57
|
+
def initialize file
|
|
58
|
+
@old_files = []
|
|
59
|
+
begin super file_for(file)
|
|
60
|
+
rescue InvalidSettingsFile
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
=begin rdoc
|
|
65
|
+
Works mostly as <tt>YamlSettingsBackend#write</tt>. If the only option to be written
|
|
66
|
+
is the project name, the file isn't created, if it doesn't exist, and is deleted
|
|
67
|
+
if it does exist. Also, if there are any obsolete files (see <tt>document_path=</tt>),
|
|
68
|
+
they are deleted, too.
|
|
69
|
+
|
|
70
|
+
If no file name is associated with the backend (that is, if +file+ returns an empty string),
|
|
71
|
+
a +SystemCall+ error (most likely, <tt>Errno::ENOENT</tt>) will be raised
|
|
72
|
+
=end
|
|
73
|
+
def write opts
|
|
74
|
+
new_data = compute_data opts
|
|
75
|
+
if new_data.has_only_keys?(:general) and new_data[:general].has_only_keys?(:project_name)
|
|
76
|
+
FileUtils.rm_f @filename
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
File.open(@filename, 'w'){|f| f.write YAML.dump(new_data)}
|
|
80
|
+
@old_files.each{|f| FileUtils.rm_f f}
|
|
81
|
+
@old_files.clear
|
|
82
|
+
@data = new_data
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
=begin rdoc
|
|
86
|
+
Changes the project name and the file name so that they match a document path of
|
|
87
|
+
_value_. This means:
|
|
88
|
+
* setting the project name to _value_
|
|
89
|
+
* changing the file associated with the backend to an encoded version of _value_
|
|
90
|
+
* adding the old associated file to a list of obsolete files, which will be deleted
|
|
91
|
+
at the next write
|
|
92
|
+
=end
|
|
93
|
+
def document_path= value
|
|
94
|
+
@data[:general] ||= {}
|
|
95
|
+
@data[:general][:project_name] = value
|
|
96
|
+
@old_files << @filename unless @filename.empty?
|
|
97
|
+
@filename = file_for(value)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
=begin rdoc
|
|
103
|
+
Returns the file where the data for the document path _path_ should be stored (an
|
|
104
|
+
empty string if _path_ is empty).
|
|
105
|
+
=end
|
|
106
|
+
def file_for path
|
|
107
|
+
return '' if path.empty?
|
|
108
|
+
dir = KDE::Global.dirs.locate_local('appdata', 'documents/')
|
|
109
|
+
md5 = Digest::MD5.new
|
|
110
|
+
md5 << path
|
|
111
|
+
File.join dir, md5.hexdigest
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
slots :change_file
|
|
117
|
+
|
|
118
|
+
=begin rdoc
|
|
119
|
+
The document associated with the project
|
|
120
|
+
=end
|
|
121
|
+
attr_reader :document
|
|
122
|
+
|
|
123
|
+
=begin rdoc
|
|
124
|
+
Creates a new DocumentProject. _doc_ is the document the project refers to. Note
|
|
125
|
+
that, until _doc_ becomes associated with a file, attempting to save the project
|
|
126
|
+
will fail with an +ArgumentError+.
|
|
127
|
+
|
|
128
|
+
If the path of the file associated with the document changes (usually because of
|
|
129
|
+
a "Save As" action), the file associated with the backend is changed automatically
|
|
130
|
+
=end
|
|
131
|
+
def initialize doc
|
|
132
|
+
@document = doc
|
|
133
|
+
path = doc.path
|
|
134
|
+
back = Backend.new path
|
|
135
|
+
back.instance_variable_get(:@data).empty? ? super(doc, back, doc.path) : super(doc, back)
|
|
136
|
+
connect doc, SIGNAL('document_url_changed(QObject*)'), self, SLOT(:change_file)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
=begin rdoc
|
|
140
|
+
Override of <tt>AbstractProject#scope</tt> which returns +:document+
|
|
141
|
+
=end
|
|
142
|
+
def scope
|
|
143
|
+
:document
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
=begin rdoc
|
|
147
|
+
Override of AbstractProject#match_rule? which also takes into account the mimetype
|
|
148
|
+
and the file extension of the document and compares them with those in the rule.
|
|
149
|
+
The comparison is made using <tt>Document#file_type_match?</tt>. This method returns
|
|
150
|
+
*true* only if the <tt>Document#file_type_match?</tt> returns *true* and the
|
|
151
|
+
rule's scope includes +:document+
|
|
152
|
+
=end
|
|
153
|
+
def match_rule? obj
|
|
154
|
+
if !super then false
|
|
155
|
+
elsif !@document.file_type_match? obj.mimetype, obj.file_extension then false
|
|
156
|
+
else true
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
=begin rdoc
|
|
161
|
+
Override of <tt>AbstractProject#project_directory</tt> which returns the current
|
|
162
|
+
directory if the document isn't associated with a file.
|
|
163
|
+
=end
|
|
164
|
+
def project_directory
|
|
165
|
+
path = @document.path
|
|
166
|
+
path.empty? ? Dir.pwd : File.dirname(path)
|
|
167
|
+
end
|
|
168
|
+
alias_method :project_dir, :project_directory
|
|
169
|
+
|
|
170
|
+
=begin rdoc
|
|
171
|
+
Override of <tt>AbstractProject#write</tt> which prevents a Errno::ENOENT exception
|
|
172
|
+
to be raised by the backend if the document isn't associated with a file. If the
|
|
173
|
+
docuement is associated with a file, however, the exception will be raised as usual.
|
|
174
|
+
|
|
175
|
+
The reason for this kind of behaviour is that the backend is expected to raise
|
|
176
|
+
the exception when the document isn't associated with a file: it simply means that
|
|
177
|
+
it doesn't know where to write the data. If the document is associated with a file,
|
|
178
|
+
however, this shouldn't happen and the exception is then propagated because it
|
|
179
|
+
truly means something is wrong.
|
|
180
|
+
=end
|
|
181
|
+
def write
|
|
182
|
+
begin super
|
|
183
|
+
rescue Errno::ENOENT
|
|
184
|
+
raise unless @document.path.empty?
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
=begin rdoc
|
|
189
|
+
Override of AbstractProject#files which returns an array with the path of the
|
|
190
|
+
associated document, if it corresponds to a file, and an empty array otherwise
|
|
191
|
+
=end
|
|
192
|
+
def files
|
|
193
|
+
path = @document.path
|
|
194
|
+
path.empty? ? [] : [path]
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
private
|
|
198
|
+
|
|
199
|
+
=begin rdoc
|
|
200
|
+
Updates the backend so that the associated file reflects the file associated with
|
|
201
|
+
the document.
|
|
202
|
+
=end
|
|
203
|
+
def change_file
|
|
204
|
+
@backend.document_path = @document.path
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
end
|
|
@@ -0,0 +1,416 @@
|
|
|
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 'forwardable'
|
|
22
|
+
require 'pathname'
|
|
23
|
+
require 'facets/array/only'
|
|
24
|
+
|
|
25
|
+
require 'ruber/editor/document'
|
|
26
|
+
require 'ruber/plugin_like'
|
|
27
|
+
|
|
28
|
+
module Ruber
|
|
29
|
+
|
|
30
|
+
=begin rdoc
|
|
31
|
+
List of all open documents
|
|
32
|
+
|
|
33
|
+
It contains convenience methods to iterate on the open documents and to create
|
|
34
|
+
them. Whenever possible, you should use them. In particular, when you need a document
|
|
35
|
+
associated with a given file or URL, you should always use {#document}, so that
|
|
36
|
+
if a document for that file is already installed, no new document will be created.
|
|
37
|
+
|
|
38
|
+
If, for any reason, you need to create a document using {Document.new}, please
|
|
39
|
+
don't forget to add the document to the list using {#add_document}.
|
|
40
|
+
=end
|
|
41
|
+
class DocumentList < Qt::Object
|
|
42
|
+
|
|
43
|
+
include PluginLike
|
|
44
|
+
|
|
45
|
+
include Enumerable
|
|
46
|
+
|
|
47
|
+
=begin rdoc
|
|
48
|
+
Signal emitted when a new document is created
|
|
49
|
+
|
|
50
|
+
@param [Document] doc the new document
|
|
51
|
+
=end
|
|
52
|
+
signals 'document_created(QObject*)'
|
|
53
|
+
|
|
54
|
+
=begin rdoc
|
|
55
|
+
Signal emitted before a document is closed
|
|
56
|
+
|
|
57
|
+
@param [Document] doc the document which is being closed
|
|
58
|
+
=end
|
|
59
|
+
signals 'closing_document(QObject*)'
|
|
60
|
+
|
|
61
|
+
slots 'close_document(QObject*)', 'load_settings()'
|
|
62
|
+
|
|
63
|
+
=begin rdoc
|
|
64
|
+
@param [ComponentManager] _manager the component manager (unused)
|
|
65
|
+
@param [PluginSpecification] psf the plugin specification object
|
|
66
|
+
=end
|
|
67
|
+
def initialize _manager, psf
|
|
68
|
+
super Ruber[:app]
|
|
69
|
+
initialize_plugin psf
|
|
70
|
+
@docs = []
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#DOCUMENT CREATION
|
|
74
|
+
|
|
75
|
+
=begin rdoc
|
|
76
|
+
Creates a new empty document
|
|
77
|
+
|
|
78
|
+
The document is automatically added to the list and the {#document_created} signal
|
|
79
|
+
is emitted
|
|
80
|
+
@return [Ruber::Document] the created document
|
|
81
|
+
=end
|
|
82
|
+
def new_document
|
|
83
|
+
doc = Document.new Ruber[:main_window]
|
|
84
|
+
add_document doc
|
|
85
|
+
emit document_created(doc)
|
|
86
|
+
doc
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
=begin rdoc
|
|
90
|
+
The document for a given file or url
|
|
91
|
+
|
|
92
|
+
If there's no open document associated with the given file or url, depending on
|
|
93
|
+
the value of _create_if_needed_ a new document associated with the file or url
|
|
94
|
+
will be created. In this case, the {#document_created} signal will be emitted.
|
|
95
|
+
|
|
96
|
+
@param [String, KDE::Url] file the file name or URL associated with the document.
|
|
97
|
+
A relative file name will be expanded with respect to the current directory. If
|
|
98
|
+
it is a string, it will _always_ be interpreted as a filename. If you want it
|
|
99
|
+
to be considered an URL, you need to create a @KDE::Url@ for it
|
|
100
|
+
@param [Boolean] create_if_needed whether or not to create a document associated
|
|
101
|
+
with _file_ if there isn't one
|
|
102
|
+
@return [Document,nil] the document associated with _file_. If no such document
|
|
103
|
+
exists and _create_if_needed_ is *false*, *nil* will be returned
|
|
104
|
+
@raise [ArgumentError] if _file_ is a local file, there's
|
|
105
|
+
no document for it, it doesn't exist and _create_if_needed_ is *true*. Note that
|
|
106
|
+
this won't happen if _file_ is a remote file, even if it doesn't exist
|
|
107
|
+
=end
|
|
108
|
+
def document file, create_if_needed = true
|
|
109
|
+
if file.is_a? String
|
|
110
|
+
file = File.expand_path(file)
|
|
111
|
+
doc = document_for_file file
|
|
112
|
+
return doc if doc or !create_if_needed
|
|
113
|
+
elsif file.is_a? KDE::Url
|
|
114
|
+
doc = document_for_url file
|
|
115
|
+
return doc if doc or !create_if_needed
|
|
116
|
+
end
|
|
117
|
+
if !doc and create_if_needed
|
|
118
|
+
url = KDE::Url.new file
|
|
119
|
+
if url.local_file?
|
|
120
|
+
raise ArgumentError, "File #{url.path} doesn't exist" unless File.exist?(url.path)
|
|
121
|
+
end
|
|
122
|
+
doc = Document.new Ruber[:main_window], file
|
|
123
|
+
begin @docs[0].close if @docs.only.pristine?
|
|
124
|
+
rescue IndexError
|
|
125
|
+
end
|
|
126
|
+
add_document doc
|
|
127
|
+
emit document_created(doc)
|
|
128
|
+
end
|
|
129
|
+
doc
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
=begin rdoc
|
|
133
|
+
@return [Array<Document>] a list of open documents
|
|
134
|
+
=end
|
|
135
|
+
def documents
|
|
136
|
+
@docs.dup
|
|
137
|
+
end
|
|
138
|
+
alias :to_a :documents
|
|
139
|
+
|
|
140
|
+
=begin rdoc
|
|
141
|
+
@return [Boolean] whether the document list is empty or not
|
|
142
|
+
=end
|
|
143
|
+
def empty?
|
|
144
|
+
@docs.empty?
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
=begin rdoc
|
|
148
|
+
@return [Integer] the number of documents in the list
|
|
149
|
+
=end
|
|
150
|
+
def size
|
|
151
|
+
@docs.size
|
|
152
|
+
end
|
|
153
|
+
alias :length :size
|
|
154
|
+
|
|
155
|
+
=begin rdoc
|
|
156
|
+
Adds a new document to the list
|
|
157
|
+
|
|
158
|
+
If you use {#new_document} and {#document} to create documents, you don't need to
|
|
159
|
+
call this method.
|
|
160
|
+
|
|
161
|
+
*Note:* this method doesn't check whether the document has already been added to
|
|
162
|
+
the list. If so, the results may cause errors. Please, always make sure the document
|
|
163
|
+
isn't already in the list before calling this.
|
|
164
|
+
|
|
165
|
+
@param [Document, nil] doc the document to add. If *nil*, nothing is done
|
|
166
|
+
@return [Document, nil] _doc_
|
|
167
|
+
=end
|
|
168
|
+
def add_document doc
|
|
169
|
+
if doc
|
|
170
|
+
connect doc, SIGNAL('closing(QObject*)'), self, SLOT('close_document(QObject*)')
|
|
171
|
+
@docs << doc
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
=begin rdoc
|
|
176
|
+
Attempts to save the given documents
|
|
177
|
+
|
|
178
|
+
What happens if a document can't be saved depends on the value of _stop_on_failure_:
|
|
179
|
+
if it's *false*, documents which can't be saved are skipped, while if it's true,
|
|
180
|
+
this method will return as soon as one document fails to save.
|
|
181
|
+
|
|
182
|
+
*Note:* by can't be saved, we mean that the user chose to save a document but,
|
|
183
|
+
for any reason, it couldn't be saved (for example this can happen if the user
|
|
184
|
+
doesn't have write permission on the file, or if the disk is full). If the user
|
|
185
|
+
decides not to save the file, instead, it is considered a success.
|
|
186
|
+
|
|
187
|
+
@param [Array<Document>] docs an array with the documents to save
|
|
188
|
+
@param [Boolean] stop_on_failure what to do when a document fails to save. If *true*,
|
|
189
|
+
return immediately; if *false*, attempt to save the remaining documents
|
|
190
|
+
@return [Array<Document>] an array with the documents which couldn't be saved. If
|
|
191
|
+
_stop_on_failure_ is *false*, it contains only the documents for which saving failed;
|
|
192
|
+
if _stop_on_failure_ is *true* it also contains the documents for which saving
|
|
193
|
+
wasn't even attempted. If all documents were saved successfully, the array will
|
|
194
|
+
be empty
|
|
195
|
+
=end
|
|
196
|
+
def save_documents docs, stop_on_failure = false
|
|
197
|
+
failed = []
|
|
198
|
+
docs.each_with_index do |d, i|
|
|
199
|
+
success = d.save
|
|
200
|
+
failed << d unless success
|
|
201
|
+
if !success and stop_on_failure
|
|
202
|
+
failed += docs[(i+1)..-1]
|
|
203
|
+
break
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
failed
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
=begin rdoc
|
|
210
|
+
Saves the settings for all open documents
|
|
211
|
+
|
|
212
|
+
@return [nil]
|
|
213
|
+
=end
|
|
214
|
+
def save_settings
|
|
215
|
+
@docs.each{|d| d.save_settings}
|
|
216
|
+
nil
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
#CLOSING DOCUMENTS
|
|
220
|
+
|
|
221
|
+
=begin rdoc
|
|
222
|
+
Removes a document from the list
|
|
223
|
+
|
|
224
|
+
The {#closing_document} signal is emitted before removing the document.
|
|
225
|
+
@param [Document] doc the document to remove. It must have been added to the list
|
|
226
|
+
using {#add_document} (which is automatically called by {#document} and {#new_document})
|
|
227
|
+
@return [nil]
|
|
228
|
+
=end
|
|
229
|
+
def close_document doc
|
|
230
|
+
emit closing_document(doc)
|
|
231
|
+
@docs.delete doc
|
|
232
|
+
nil
|
|
233
|
+
end
|
|
234
|
+
private :close_document
|
|
235
|
+
|
|
236
|
+
=begin rdoc
|
|
237
|
+
Closes all the documents
|
|
238
|
+
|
|
239
|
+
If there are modified files and _ask_ is *true*, the user will be asked whether
|
|
240
|
+
he wants to save them (see {MainWindow#save_documents}). If he chooses to abort
|
|
241
|
+
closing, nothing will be done
|
|
242
|
+
|
|
243
|
+
@param [Boolean] ask if *true*, in case some files are modified, the user will
|
|
244
|
+
be asked whether to save them. If *false*, no file will be saved
|
|
245
|
+
@return [Boolean] *true* if the documents were closed and *false* otherwise
|
|
246
|
+
=end
|
|
247
|
+
def close_all ask = true
|
|
248
|
+
docs = @docs.dup
|
|
249
|
+
if !ask or Ruber[:main_window].save_documents docs
|
|
250
|
+
docs.each {|d| d.close false}
|
|
251
|
+
true
|
|
252
|
+
else false
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
#DOCUMENT ACCESS
|
|
257
|
+
|
|
258
|
+
=begin rdoc
|
|
259
|
+
The document corresponding to the given key
|
|
260
|
+
|
|
261
|
+
How _key_ is interpreted depends on its class:
|
|
262
|
+
* if it's an @Integer@, the document in the corresponding position in the list will
|
|
263
|
+
be returned
|
|
264
|
+
* if it's a @KDE::Url@, then the document associated with that url will be returned
|
|
265
|
+
* if it's a @String@ starting with a @/@ (that is, an absolute path) then the
|
|
266
|
+
document associated with that file will be returned
|
|
267
|
+
* if it's a string not startng with a @/@, then the document with that
|
|
268
|
+
@document_name@ will be returned
|
|
269
|
+
@param [String,Integer,KDE::Url] key the key for the document
|
|
270
|
+
@return [Document,nil] the document corresponding to _key_ or *nil* if no document
|
|
271
|
+
corresponds to it
|
|
272
|
+
@raise [TypeError] if _key_ is not a @String@, @Integer@ or @KDE::Url@
|
|
273
|
+
=end
|
|
274
|
+
def [] key
|
|
275
|
+
case key
|
|
276
|
+
when String
|
|
277
|
+
if Pathname.new(key).absolute? then @docs.find{|d| d.path == key}
|
|
278
|
+
else @docs.find{|d| d.document_name == key}
|
|
279
|
+
end
|
|
280
|
+
when KDE::Url
|
|
281
|
+
@docs.find{|d| d.url == key}
|
|
282
|
+
when Integer then @docs[key]
|
|
283
|
+
else raise TypeError
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
=begin rdoc
|
|
288
|
+
Calls the block for each document
|
|
289
|
+
@yield [Document] each document in turn
|
|
290
|
+
@return [DocumentList,Enumerator] @self@ if called with a block; an @Enumerable@
|
|
291
|
+
otherwise
|
|
292
|
+
=end
|
|
293
|
+
def each_document
|
|
294
|
+
if block_given?
|
|
295
|
+
@docs.each{|d| yield d}
|
|
296
|
+
self
|
|
297
|
+
else self.to_enum
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
alias_method :each, :each_document
|
|
301
|
+
|
|
302
|
+
=begin rdoc
|
|
303
|
+
The document associated with a given file
|
|
304
|
+
|
|
305
|
+
@param [String] file the name of the file. If it's relative, it will be considered
|
|
306
|
+
relative to the current directory
|
|
307
|
+
@return [Document,nil] the document associated with _file_ or *nil* if no such
|
|
308
|
+
document exists
|
|
309
|
+
=end
|
|
310
|
+
def document_for_file file
|
|
311
|
+
file = File.expand_path file
|
|
312
|
+
@docs.find{|d| d.path == file}
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
=begin rdoc
|
|
316
|
+
The document associated with a given URL
|
|
317
|
+
|
|
318
|
+
@param [KDE::Url] url the url
|
|
319
|
+
@return [Document,nil] the document associated with _url_ or *nil* if no such
|
|
320
|
+
document exists
|
|
321
|
+
=end
|
|
322
|
+
def document_for_url url
|
|
323
|
+
@docs.find{|d| d.url == url}
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
=begin rdoc
|
|
327
|
+
The document with a given name
|
|
328
|
+
|
|
329
|
+
@param [String] name the name of the document
|
|
330
|
+
@return [Document,nil] the document with @document_name@ _name_ or *nil* if no
|
|
331
|
+
document with that name exists
|
|
332
|
+
=end
|
|
333
|
+
def document_with_name name
|
|
334
|
+
@docs.find{|d| d.document_name == name}
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
=begin rdoc
|
|
338
|
+
The documents which are associated with a file
|
|
339
|
+
|
|
340
|
+
_which_ can be used to restrict the list of documents to only those associated
|
|
341
|
+
with local or remote files:
|
|
342
|
+
* if _which_ is @:local@ only documents associated with local files will be returned;
|
|
343
|
+
* if _which_ is @:remote@ only documents associated with remoted files will be returned;
|
|
344
|
+
* if _which_ has any other value, both documents associated with local and with
|
|
345
|
+
remote files will be returned
|
|
346
|
+
@param [Object] which which kind of documents should be included in the list
|
|
347
|
+
@return [Array<Document>] a list of documents associated with files, and restricted
|
|
348
|
+
according to the value of _which_
|
|
349
|
+
=end
|
|
350
|
+
def documents_with_file which = :any
|
|
351
|
+
@docs.select do |d|
|
|
352
|
+
if d.has_file?
|
|
353
|
+
case which
|
|
354
|
+
when :local then d.url.local_file?
|
|
355
|
+
when :remote then !d.url.local_file?
|
|
356
|
+
else true
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
#DOCUMENT QUERIES
|
|
363
|
+
|
|
364
|
+
=begin rdoc
|
|
365
|
+
Whether there's a document associated with a given file
|
|
366
|
+
|
|
367
|
+
@param [String] file the name of the file (absolute or relative to the current
|
|
368
|
+
directory)
|
|
369
|
+
@return [Boolean] *true* if there's a document associated with _file_ and *false*
|
|
370
|
+
otherwise
|
|
371
|
+
=end
|
|
372
|
+
def document_for_file? file
|
|
373
|
+
file = File.expand_path file
|
|
374
|
+
@docs.any?{|d| d.path == file}
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
=begin rdoc
|
|
378
|
+
Whether there's a document associated with a given URL
|
|
379
|
+
|
|
380
|
+
@param [@KDE::Url@] url the url
|
|
381
|
+
@return [Boolean] *true* if there's a document associated with _url_ and *false*
|
|
382
|
+
otherwise
|
|
383
|
+
=end
|
|
384
|
+
def document_for_url? url
|
|
385
|
+
@docs.any?{|d| d.url == url}
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
=begin rdoc
|
|
389
|
+
Whether there's a document with a given name
|
|
390
|
+
|
|
391
|
+
@param [String] name of the document
|
|
392
|
+
@return [Boolean] *true* if there's a document associated with _name_ and *false*
|
|
393
|
+
otherwise
|
|
394
|
+
=end
|
|
395
|
+
def document_with_name? name
|
|
396
|
+
@docs.any?{|d| d.document_name == name}
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
=begin rdoc
|
|
400
|
+
Override of {PluginLike#query_close}
|
|
401
|
+
|
|
402
|
+
It first calls the {DocumentProject#query_close query_close} of each document's
|
|
403
|
+
own project, returning *false* as soon as one of them returns *false*, then
|
|
404
|
+
attempts to save each document
|
|
405
|
+
|
|
406
|
+
@return [Boolean] *true* if it is all right to go on closing Ruber and *false*
|
|
407
|
+
otherwise
|
|
408
|
+
=end
|
|
409
|
+
def query_close
|
|
410
|
+
@docs.each{|d| return false unless d.own_project.query_close}
|
|
411
|
+
Ruber[:main_window].save_documents
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
end
|