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.
Files changed (166) hide show
  1. data/COPYING +339 -0
  2. data/INSTALL +137 -0
  3. data/LICENSE +8 -0
  4. data/bin/ruber +65 -0
  5. data/data/share/apps/ruber/core_components.yaml +31 -0
  6. data/data/share/apps/ruber/ruberui.rc +109 -0
  7. data/data/share/icons/ruber.png +0 -0
  8. data/data/share/pixmaps/ruby.png +0 -0
  9. data/icons/ruber-16.png +0 -0
  10. data/icons/ruber-32.png +0 -0
  11. data/icons/ruber-48.png +0 -0
  12. data/icons/ruber-8.png +0 -0
  13. data/lib/ruber/application/application.rb +288 -0
  14. data/lib/ruber/application/plugin.yaml +11 -0
  15. data/lib/ruber/component_manager.rb +899 -0
  16. data/lib/ruber/config/config.rb +82 -0
  17. data/lib/ruber/config/plugin.yaml +3 -0
  18. data/lib/ruber/document_project.rb +209 -0
  19. data/lib/ruber/documents/document_list.rb +416 -0
  20. data/lib/ruber/documents/plugin.yaml +4 -0
  21. data/lib/ruber/editor/document.rb +506 -0
  22. data/lib/ruber/editor/editor_view.rb +167 -0
  23. data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
  24. data/lib/ruber/exception_widgets.rb +245 -0
  25. data/lib/ruber/external_program_plugin.rb +397 -0
  26. data/lib/ruber/filtered_output_widget.rb +342 -0
  27. data/lib/ruber/gui_states_handler.rb +231 -0
  28. data/lib/ruber/kde_config_option_backend.rb +167 -0
  29. data/lib/ruber/kde_sugar.rb +249 -0
  30. data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
  31. data/lib/ruber/main_window/main_window.rb +524 -0
  32. data/lib/ruber/main_window/main_window_actions.rb +537 -0
  33. data/lib/ruber/main_window/main_window_internal.rb +239 -0
  34. data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
  35. data/lib/ruber/main_window/output_color_widget.rb +35 -0
  36. data/lib/ruber/main_window/plugin.yaml +58 -0
  37. data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
  38. data/lib/ruber/main_window/status_bar.rb +156 -0
  39. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
  40. data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
  41. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
  42. data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
  43. data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
  44. data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
  45. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
  46. data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
  47. data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
  48. data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
  49. data/lib/ruber/main_window/workspace.rb +442 -0
  50. data/lib/ruber/output_widget.rb +1093 -0
  51. data/lib/ruber/plugin.rb +264 -0
  52. data/lib/ruber/plugin_like.rb +589 -0
  53. data/lib/ruber/plugin_specification.rb +106 -0
  54. data/lib/ruber/plugin_specification_reader.rb +451 -0
  55. data/lib/ruber/project.rb +493 -0
  56. data/lib/ruber/project_backend.rb +105 -0
  57. data/lib/ruber/projects/plugin.yaml +11 -0
  58. data/lib/ruber/projects/project_files_list.rb +314 -0
  59. data/lib/ruber/projects/project_files_widget.rb +301 -0
  60. data/lib/ruber/projects/project_list.rb +314 -0
  61. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
  62. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
  63. data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
  64. data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
  65. data/lib/ruber/qt_sugar.rb +673 -0
  66. data/lib/ruber/settings_container.rb +515 -0
  67. data/lib/ruber/settings_dialog.rb +244 -0
  68. data/lib/ruber/settings_dialog_manager.rb +503 -0
  69. data/lib/ruber/utils.rb +414 -0
  70. data/lib/ruber/yaml_option_backend.rb +159 -0
  71. data/outsider_files +15 -0
  72. data/plugins/autosave/autosave.rb +404 -0
  73. data/plugins/autosave/plugin.yaml +16 -0
  74. data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
  75. data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
  76. data/plugins/command/command.png +0 -0
  77. data/plugins/command/command.rb +74 -0
  78. data/plugins/command/plugin.yaml +11 -0
  79. data/plugins/find_in_files/find_in_files.rb +337 -0
  80. data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
  81. data/plugins/find_in_files/find_in_files_ui.rc +11 -0
  82. data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
  83. data/plugins/find_in_files/plugin.yaml +23 -0
  84. data/plugins/find_in_files/ui/config_widget.rb +58 -0
  85. data/plugins/find_in_files/ui/config_widget.ui +41 -0
  86. data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
  87. data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
  88. data/plugins/project_browser/plugin.yaml +10 -0
  89. data/plugins/project_browser/project_browser.rb +245 -0
  90. data/plugins/rake/plugin.yaml +39 -0
  91. data/plugins/rake/rake.png +0 -0
  92. data/plugins/rake/rake.rb +567 -0
  93. data/plugins/rake/rake_extension.rb +153 -0
  94. data/plugins/rake/rake_widgets.rb +615 -0
  95. data/plugins/rake/rakeui.rc +27 -0
  96. data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
  97. data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
  98. data/plugins/rake/ui/choose_task_widget.rb +77 -0
  99. data/plugins/rake/ui/choose_task_widget.ui +72 -0
  100. data/plugins/rake/ui/config_widget.rb +127 -0
  101. data/plugins/rake/ui/config_widget.ui +123 -0
  102. data/plugins/rake/ui/project_widget.rb +217 -0
  103. data/plugins/rake/ui/project_widget.ui +246 -0
  104. data/plugins/rspec/plugin.yaml +30 -0
  105. data/plugins/rspec/rspec.png +0 -0
  106. data/plugins/rspec/rspec.rb +945 -0
  107. data/plugins/rspec/rspec.svg +90 -0
  108. data/plugins/rspec/rspecui.rc +20 -0
  109. data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
  110. data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
  111. data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
  112. data/plugins/ruby_development/plugin.yaml +27 -0
  113. data/plugins/ruby_development/ruby_development.png +0 -0
  114. data/plugins/ruby_development/ruby_development.rb +453 -0
  115. data/plugins/ruby_development/ruby_developmentui.rc +19 -0
  116. data/plugins/ruby_development/ui/project_widget.rb +112 -0
  117. data/plugins/ruby_development/ui/project_widget.ui +108 -0
  118. data/plugins/ruby_runner/config_widget.rb +116 -0
  119. data/plugins/ruby_runner/plugin.yaml +26 -0
  120. data/plugins/ruby_runner/project_widget.rb +62 -0
  121. data/plugins/ruby_runner/ruby.png +0 -0
  122. data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
  123. data/plugins/ruby_runner/ruby_runner.rb +411 -0
  124. data/plugins/ruby_runner/ui/config_widget.rb +92 -0
  125. data/plugins/ruby_runner/ui/config_widget.ui +91 -0
  126. data/plugins/ruby_runner/ui/project_widget.rb +60 -0
  127. data/plugins/ruby_runner/ui/project_widget.ui +48 -0
  128. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
  129. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
  130. data/plugins/state/plugin.yaml +28 -0
  131. data/plugins/state/state.rb +520 -0
  132. data/plugins/state/ui/config_widget.rb +92 -0
  133. data/plugins/state/ui/config_widget.ui +89 -0
  134. data/plugins/syntax_checker/plugin.yaml +18 -0
  135. data/plugins/syntax_checker/syntax_checker.rb +662 -0
  136. data/ruber.desktop +10 -0
  137. data/spec/annotation_model_spec.rb +174 -0
  138. data/spec/common.rb +119 -0
  139. data/spec/component_manager_spec.rb +1259 -0
  140. data/spec/document_list_spec.rb +626 -0
  141. data/spec/document_project_spec.rb +373 -0
  142. data/spec/document_spec.rb +779 -0
  143. data/spec/editor_view_spec.rb +167 -0
  144. data/spec/external_program_plugin_spec.rb +676 -0
  145. data/spec/filtered_output_widget_spec.rb +642 -0
  146. data/spec/gui_states_handler_spec.rb +304 -0
  147. data/spec/kde_config_option_backend_spec.rb +214 -0
  148. data/spec/kde_sugar_spec.rb +101 -0
  149. data/spec/ktexteditor_wrapper_spec.rb +305 -0
  150. data/spec/output_widget_spec.rb +1703 -0
  151. data/spec/plugin_spec.rb +1393 -0
  152. data/spec/plugin_specification_reader_spec.rb +1765 -0
  153. data/spec/plugin_specification_spec.rb +401 -0
  154. data/spec/project_backend_spec.rb +172 -0
  155. data/spec/project_files_list_spec.rb +401 -0
  156. data/spec/project_list_spec.rb +511 -0
  157. data/spec/project_spec.rb +990 -0
  158. data/spec/qt_sugar_spec.rb +328 -0
  159. data/spec/settings_container_spec.rb +617 -0
  160. data/spec/settings_dialog_manager_spec.rb +773 -0
  161. data/spec/settings_dialog_spec.rb +419 -0
  162. data/spec/state_spec.rb +991 -0
  163. data/spec/utils_spec.rb +406 -0
  164. data/spec/workspace_spec.rb +869 -0
  165. data/spec/yaml_option_backend_spec.rb +246 -0
  166. 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,3 @@
1
+ name: config
2
+ require: config
3
+ class: Ruber::ConfigManager
@@ -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