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,4 @@
1
+ name: documents
2
+ require: document_list
3
+ class: Ruber::DocumentList
4
+ features: :docs
@@ -0,0 +1,506 @@
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 'ktexteditor'
22
+ require 'forwardable'
23
+ require 'dictionary'
24
+
25
+ require 'ruber/editor/ktexteditor_wrapper'
26
+ require 'ruber/editor/editor_view'
27
+ require 'ruber/utils'
28
+ require 'ruber/document_project'
29
+
30
+ module Ruber
31
+
32
+ class Document < Qt::Object
33
+
34
+ extend Forwardable
35
+
36
+ include Activable
37
+
38
+ include KTextEditorWrapper
39
+
40
+ def_delegator :@doc, :documentSave, :save_document
41
+
42
+ signal_data = {
43
+ 'text_changed' => ['KTextEditor::Document*', [nil]],
44
+ 'about_to_close' => ['KTextEditor::Document*', [nil]],
45
+ 'about_to_reload' => ['KTextEditor::Document*', [nil]],
46
+ 'highlighting_mode_changed' => ['KTextEditor::Document*', [nil]],
47
+ 'document_url_changed' => ['KTextEditor::Document*', [nil]],
48
+ 'mode_changed' => ['KTextEditor::Document*', [nil]]
49
+ }
50
+
51
+ @signal_table = KTextEditorWrapper.prepare_wrapper_connections self, signal_data
52
+
53
+ signals 'modified_changed(bool, QObject*)', 'document_name_changed(QString, QObject*)',
54
+ 'text_changed(QObject*)', 'about_to_close(QObject*)', 'about_to_reload(QObject*)',
55
+ 'document_url_changed(QObject*)', 'highlighting_mode_changed(QObject*)',
56
+ 'mode_changed(QObject*)', 'text_modified(KTextEditor::Range, KTextEditor::Range, QObject*)',
57
+ 'text_inserted(KTextEditor::Range, QObject*)', 'text_removed(KTextEditor::Range, QObject*)',
58
+ 'view_created(QObject*, QObject*)', 'closing(QObject*)', :activated, :deactivated,
59
+ 'modified_on_disk(QObject*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)'
60
+
61
+ slots :document_save_as, :save
62
+
63
+ =begin rdoc
64
+ The view associated with the document. If a view hasn't been created, this is *nil*
65
+ =end
66
+ attr_reader :view
67
+
68
+ def inspect
69
+ if disposed? then "< #{self.class} #{object_id}DISPOSED >"
70
+ else super
71
+ end
72
+ end
73
+
74
+ =begin rdoc
75
+ Creates a new Ruber::Document.
76
+ =end
77
+ def initialize parent = nil, file = nil
78
+ super parent
79
+ @active = false
80
+ @doc = KTextEditor::EditorChooser.editor('katepart').create_document( self)
81
+ initialize_wrapper @doc, self.class.instance_variable_get(:@signal_table)
82
+ @view = nil
83
+ @doc.openUrl(file.is_a?(String) ? KDE::Url.from_path(file) : file) if file
84
+ @annotation_model = AnnotationModel.new self
85
+ interface('annotation_interface').annotation_model = @annotation_model
86
+ interface('modification_interface').modified_on_disk_warning = true
87
+ @modified_on_disk = false
88
+ @project = DocumentProject.new self
89
+
90
+ @doc.connect(SIGNAL('modifiedChanged(KTextEditor::Document*)')) do |doc|
91
+ emit modified_changed(@doc.modified?, self)
92
+ end
93
+ @doc.connect(SIGNAL('documentNameChanged(KTextEditor::Document*)')) do |doc|
94
+ Ruber[:components].each_component{|c| c.update_project @project}
95
+ emit document_name_changed doc.document_name, self
96
+ end
97
+
98
+ @doc.connect(SIGNAL('textChanged(KTextEditor::Document*, KTextEditor::Range, KTextEditor::Range)')){|_, o, n| emit text_modified(o, n, self)}
99
+
100
+ @doc.connect(SIGNAL('textInserted(KTextEditor::Document*, KTextEditor::Range)')) do |_, r|
101
+ begin
102
+ emit text_inserted(r, self)
103
+ rescue ArgumentError => e
104
+ ExceptionDialog.new e, nil, true, "An exception was raised when writing text. See issue number 6 at http://github.com/stcrocco/ruber/issues"
105
+ end
106
+ end
107
+
108
+ @doc.connect(SIGNAL('textRemoved(KTextEditor::Document*, KTextEditor::Range)')){|_, r| emit text_removed(r, self)}
109
+ @doc.connect(SIGNAL('modifiedOnDisk(KTextEditor::Document*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)')) do |_, mod, reason|
110
+ @modified_on_disk = (reason != KTextEditor::ModificationInterface::OnDiskUnmodified)
111
+ emit modified_on_disk(self, mod, reason)
112
+ end
113
+
114
+ end
115
+
116
+ =begin rdoc
117
+ Executes the action with name _name_ contained in document's view's action
118
+ collection. This is made by having the action emit the <tt>triggered()</tt> or
119
+ <tt>toggled(bool)</tt> signal (depending on whether it's a standard action or a
120
+ <tt>KDE::ToggleAction</tt>). In the second case, _arg_ is the argument passed to
121
+ the signal.
122
+
123
+ Returns *true* if _name_ is the name of an action and *false* otherwise.
124
+
125
+ <b>Note:</b> for this method to work, a view should have been created for the
126
+ document, otherwise this method will always return *false.
127
+ =end
128
+ def execute_action name, arg = nil
129
+ @view ? @view.execute_action( name, arg) : false
130
+ end
131
+
132
+ =begin rdoc
133
+ Compares the mimetype and file name of the document with a list of mimetypes (
134
+ using <tt>KDE::MimeType#=~</tt>) and/or patterns (using <tt>File.fnmatch</tt>),
135
+ returning *true* if any of the comparisons is successful and
136
+ *false* if all fails. Both _mimetypes_ and _patterns_ can be either a string or
137
+ an array of strings (a single string will be treated as an array containing a
138
+ single string).
139
+
140
+ ====Notes:
141
+ * if both _mimetypes_ and _patterns_ are empty, the comparison always returns *true*.
142
+ * if the document is not associated with a file (that is, if +path+ returns an
143
+ empty string) it won't match any pattern. It will match the <tt>text/plain</tt>
144
+ mimetype, however.
145
+ * only the basename of the file will be taken into account for pattern matching.
146
+ For example, the pattern <tt>abc/xyz.jkl</tt> will match the pattern <tt>xyz.jkl</tt>,
147
+ which wouldn't be the case if the whole filename was included.
148
+ =end
149
+ def file_type_match? mimetypes = [], patterns = []
150
+ mime = KDE::MimeType.mime_type @doc.mime_type
151
+ mimetypes = Array(mimetypes).reject{|i| i.empty?}
152
+ patterns = Array(patterns).reject{|i| i.empty?}
153
+ base = File.basename path
154
+ if mimetypes.empty? and patterns.empty? then true
155
+ elsif mimetypes.any? {|m| mime =~ m} then true
156
+ elsif patterns.any? {|pat| File.fnmatch? pat, base, File::FNM_DOTMATCH} then true
157
+ else false
158
+ end
159
+ end
160
+
161
+ =begin rdoc
162
+ Returns the document extension with name _name_ or *nil* if such an extension
163
+ doesn't exist
164
+ =end
165
+ def extension name
166
+ @project.extension name
167
+ end
168
+
169
+ =begin rdoc
170
+ Returns an appropriate <tt>Qt::Icon</tt> for the document, depending on the mimetype and the
171
+ status of the document.
172
+ =end
173
+ def icon
174
+ if @modified_on_disk then ICONS[:modified_on_disk]
175
+ elsif @doc.modified? then ICONS[:modified]
176
+ else
177
+ icon_name = KDE::MimeType.mime_type(@doc.mime_type).icon_name
178
+ Qt::Icon.new(KDE::IconLoader.load_mime_type_pixmap icon_name)
179
+ end
180
+ end
181
+
182
+ =begin rdoc
183
+ Tells whether the document is associated with a file, that is if it has been
184
+ saved to file before or not.
185
+ =end
186
+ def has_file?
187
+ !@doc.url.empty?
188
+ end
189
+
190
+ =begin rdoc
191
+ Tells whether the document is _pristine_ or not. A pristine document is an empty,
192
+ unmodified document which hasn't a file associated with it. The document returned
193
+ by <tt>Document.new</tt> is pristine is the second argument is *nil*, but it's
194
+ not pristine if a non-*nil* second argument was given (because in that case the
195
+ document has a file associated with it).
196
+ =end
197
+ def pristine?
198
+ @doc.url.empty? and !@doc.modified? and @doc.text.nil?
199
+ end
200
+
201
+ =begin rdoc
202
+ Tells whether the document is modified on disk or not
203
+ =end
204
+ def modified_on_disk?
205
+ @modified_on_disk
206
+ end
207
+
208
+ =begin rdoc
209
+ Saves the document. If the document is already associated with a file, it's saved
210
+ in that file; otherwise, a Save As dialog is displayed for the user to choose a
211
+ file name. Returns *true* if the document was saved and *false* if it wasn't for
212
+ some reason (for example, if the user doesn't have write perimission on the file
213
+ or if he pressed the Cancel button in the Save As dialog).
214
+
215
+ This method is associated with the Save menu entry
216
+ =end
217
+ def save
218
+ if path.empty? || !is_read_write then document_save_as
219
+ else
220
+ res = @doc.save
221
+ @project.save
222
+ res
223
+ end
224
+ # unless url.empty? then save_document
225
+ # else document_save_as
226
+ # res = KDE::FileDialog.get_save_file_name KDE::Url.new, "*.rb|Ruby files (*.rb)\n*|All files", nil,
227
+ # KDE::i18n("Save \"#{@doc.document_name}\" as")
228
+ # return false unless res
229
+ # save_as KDE::Url.from_path(res)
230
+ # end
231
+ end
232
+
233
+ =begin rdoc
234
+ Creats a view for the document. _parent_ is the view's parent widget. Raises
235
+ +RuntimeError+ if the document already has a view.
236
+ =end
237
+ def create_view parent = nil
238
+ raise "Can't create a second view for this document" if @view
239
+ @doc.create_view nil
240
+ @view = EditorView.new self, @doc.views.first, parent
241
+ @view.connect(SIGNAL('closing()')){@view = nil}
242
+ @view.connect(SIGNAL('destroyed(QObject*)')){@view = nil}
243
+ gui = @view.send(:internal)
244
+ action = gui.action_collection.action('file_save_as')
245
+ disconnect action, SIGNAL(:triggered), @doc, SLOT('documentSaveAs()')
246
+ connect action, SIGNAL(:triggered), self, SLOT(:document_save_as)
247
+ action = gui.action_collection.action('file_save')
248
+ disconnect action, SIGNAL(:triggered), @doc, SLOT('documentSave()')
249
+ connect action, SIGNAL(:triggered), self, SLOT(:save)
250
+ emit view_created(@view, self)
251
+ @view
252
+ end
253
+
254
+ =begin rdoc
255
+ Return the project with wider scope the document belongs to. This is:
256
+ * the current global project if it exists and the document is associated with a file
257
+ belonging to it
258
+ * the document project if there's no active global project or the document isn't
259
+ associated with a file or the file doesn't belong the global project
260
+ =end
261
+ def project
262
+ prj = Ruber[:projects].current
263
+ return @project if path.empty? or !prj
264
+ prj.project_files.file_in_project?(path) ? prj : @project
265
+ end
266
+
267
+ =begin rdoc
268
+ Returns the DocumentProject associated with the document
269
+ =end
270
+ def own_project
271
+ @project
272
+ end
273
+
274
+ def save_settings
275
+ @project.save unless path.empty?
276
+ end
277
+
278
+ =begin rdoc
279
+ Returns the path of the document
280
+ =end
281
+ def path
282
+ @doc.url.path || ''
283
+ end
284
+
285
+ =begin rdoc
286
+ Returns the text in the document
287
+ ---
288
+ We can't just delegate this method to the internal <tt>KTextEditor::Document</tt>
289
+ because its +text+ method returns nil if there's no text in the document, instead
290
+ of an empty string.
291
+ =end
292
+ def text
293
+ @doc.text || ''
294
+ end
295
+
296
+ =begin rdoc
297
+ Executes the given block inside a pair of <tt>start_editing</tt>/<tt>end_editing</tt>
298
+ calls.
299
+ =end
300
+ def editing
301
+ begin
302
+ @doc.start_editing
303
+ yield
304
+ ensure @doc.end_editing
305
+ end
306
+ end
307
+
308
+ =begin rdoc
309
+ Closes the document. If _ask_ is *true*, the <tt>query_close</tt> method is called,
310
+ asking the user what to do if the document is modified. If the user confirms
311
+ closing or if there's no need of confirmation, the following happens:
312
+ * the <tt>closing(QObject*)</tt> signal is emitted
313
+ * the view (if it exists) is closed
314
+ * the <tt>close_url</tt> method is called
315
+ * all the documnent extensions are removed
316
+ * al singnals are disconnected from the document
317
+ * the document is disposed of
318
+
319
+ Returns *true* if the document was closed and *false* otherwise
320
+
321
+ TODO: maybe remove the argument, since this method is not called anymore at
322
+ =end
323
+ def close ask = true
324
+ if !ask || query_close
325
+ emit closing(self)
326
+ @project.save unless path.empty?
327
+ @view.close if @doc.views.size > 0
328
+ return false unless close_url false
329
+ @project.close false
330
+ self.disconnect
331
+ dispose
332
+ true
333
+ else false
334
+ end
335
+ end
336
+
337
+ =begin rdoc
338
+ Closes the view _view_ associated with the document.
339
+
340
+ Currently, the _view_ parameter is unused, as a document can only have one view,
341
+ and all this method does is to call the <tt>close</tt> method with _ask_ as argument.
342
+ =end
343
+ def close_view view, ask = true
344
+ close ask
345
+ end
346
+
347
+ =begin rdoc
348
+ The <tt>KParts::Part</tt> associated with the document
349
+ =end
350
+ alias_method :part, :internal
351
+
352
+ private
353
+
354
+ =begin rdoc
355
+ Works like <tt>KTextEditor::Document#documentSave</tt> but sets the starting directory to
356
+ either the project directory, if there's an active project, or to the default script
357
+ directory otherwise.
358
+
359
+ <b>Note:</b> there's a small difference with <tt>KTextEditor::Document#documentSave</tt>.
360
+ In that method, the encoding initially selected in the combo box is read from the
361
+ configuration. Since I couldn't figure how to access that, instead, the default
362
+ encoding here is set to UTF-8 if using ruby 1.9 and to ISO-8859-1 if using ruby
363
+ 1.8
364
+ =end
365
+ def document_save_as
366
+ enc = RUBY_VERSION.match(/1\.9/) ? 'UTF-8' : 'ISO-8859-1'
367
+ prj = Ruber[:projects].current
368
+ path = if !self.path.empty? then self.path
369
+ elsif prj then prj.project_directory
370
+ else ''
371
+ end
372
+
373
+ res = KDE::EncodingFileDialog.get_save_file_name_and_encoding enc, path, '',
374
+ Ruber[:main_window], KDE.i18n('Save File')
375
+ return false if res.file_names.empty? or res.file_names.first.empty?
376
+ u = KDE::Url.new res.file_names.first
377
+ if u.is_local_file and File.exist?(u.path)
378
+ ans = KDE::MessageBox.warning_continue_cancel Ruber[:main_window],
379
+ KDE.i18n(format("A file named \"%s\" already exists. \nAre you sure you want to overwrite it?", u.path)),
380
+ i18n( "Overwrite File?" ), KDE::StandardGuiItem.overwrite,
381
+ KDE::StandardGuiItem.cancel, '', KDE::MessageBox::Notify | KDE::MessageBox::Dangerous
382
+ return false if ans == KDE::MessageBox::Cancel
383
+ end
384
+ @doc.encoding = res.encoding
385
+ @project.save
386
+ @doc.saveAs u
387
+ end
388
+
389
+ =begin rdoc
390
+ A hash associating icon roles used by Document with icon names. It is used by
391
+ +ICONS+
392
+ =end
393
+ ICON_NAMES = {
394
+ :modified => 'document-save',
395
+ :modified_on_disk => 'dialog-warning'
396
+ }
397
+
398
+ =begin rdoc
399
+ Hash containing a list of predefined icons, each associated with a role (usually
400
+ a symbol describing the icon's use).
401
+
402
+ At the beginning, this hash is empty. It is automatically filled by loading icons
403
+ according with the associations specified in <tt>ICON_NAMES</tt> as they're requested.
404
+ This is necessary because the hash is created when this file is read, which may
405
+ happen before the application is created.
406
+ =end
407
+ ICONS = Hash.new do |h, k|
408
+ icon = KDE::IconLoader.load_icon ICON_NAMES[k]
409
+ h[k] = icon
410
+ end
411
+
412
+ end
413
+
414
+ class AnnotationModel < KTextEditor::AnnotationModel
415
+
416
+ include Enumerable
417
+
418
+ Annotation = Struct.new :type, :line, :msg, :tool_tip, :data
419
+
420
+ signals 'annotations_changed()', 'annotation_changed(int)'
421
+
422
+ @annotation_types = {}
423
+
424
+ class << self
425
+ attr_reader :annotation_types
426
+ end
427
+
428
+ def self.register_annotation_type type, back = nil, fore = nil
429
+ raise ArgumentError, "Annotation type #{type} has already been added" if
430
+ @annotation_types.has_key?(type)
431
+ @annotation_types[type] = [back, fore].map{|i| i ? Qt::Variant.fromValue(i) : Qt::Variant.new}
432
+ end
433
+
434
+ def initialize doc
435
+ super()
436
+ @doc = doc
437
+ @annotations = Dictionary.alpha
438
+ connect self, SIGNAL('annotation_changed(int)'), self, SIGNAL('lineChanged(int)')
439
+ end
440
+
441
+ def add_annotation *args
442
+ a = args.size == 1 ? args[0] : Annotation.new( *args )
443
+ # TODO: see why this sometimes gives extremely weird errors
444
+ #The begin/rescue clause is there to find out why sometimes I get a crash saying:
445
+ # `<': comparison of Fixnum with Qt::Variant failed (ArgumentError)
446
+ # begin
447
+
448
+ # raise IndexError, "Invalid line: #{a.line}" unless a.line < @doc.lines
449
+ # rescue ArgumentError
450
+ # puts "a.line: #{a.line}(#{a.line.class})"
451
+ # puts "@doc.lines: #{@doc.lines}(#{@doc.lines.class})"
452
+ # end
453
+ @annotations[a.line] = a
454
+ emit annotations_changed
455
+ emit annotation_changed( a.line)
456
+ end
457
+
458
+ def data line, role
459
+ a = @annotations[line]
460
+ return Qt::Variant.new unless a
461
+ case role
462
+ when Qt::DisplayRole then Qt::Variant.new a.msg
463
+ when Qt::ToolTipRole then Qt::Variant.new a.tool_tip
464
+ when Qt::ForegroundRole then self.class.annotation_types[a.type][1]
465
+ when Qt::BackgroundRole then self.class.annotation_types[a.type][0]
466
+ else Qt::Variant.new
467
+ end
468
+ end
469
+
470
+ def annotation line
471
+ @annotations[line]
472
+ end
473
+ alias_method :[], :annotation
474
+
475
+ def has_annotation? line
476
+ @annotations.has_key? line
477
+ end
478
+
479
+ def has_annotations?
480
+ !@annotations.empty?
481
+ end
482
+
483
+ def empty?
484
+ @annotations.empty?
485
+ end
486
+
487
+ def clear
488
+ @annotations.clear
489
+ emit annotations_changed
490
+ emit reset
491
+ end
492
+
493
+ def remove_annotation line
494
+ if @annotations.delete line
495
+ emit annotations_changed
496
+ emit annotation_changed( line )
497
+ end
498
+ end
499
+
500
+ def each
501
+ @annotations.each_pair{|k, v| yield v}
502
+ end
503
+
504
+ end
505
+
506
+ end