ruber 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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