ruber 0.0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +339 -0
- data/INSTALL +137 -0
- data/LICENSE +8 -0
- data/bin/ruber +65 -0
- data/data/share/apps/ruber/core_components.yaml +31 -0
- data/data/share/apps/ruber/ruberui.rc +109 -0
- data/data/share/icons/ruber.png +0 -0
- data/data/share/pixmaps/ruby.png +0 -0
- data/icons/ruber-16.png +0 -0
- data/icons/ruber-32.png +0 -0
- data/icons/ruber-48.png +0 -0
- data/icons/ruber-8.png +0 -0
- data/lib/ruber/application/application.rb +288 -0
- data/lib/ruber/application/plugin.yaml +11 -0
- data/lib/ruber/component_manager.rb +899 -0
- data/lib/ruber/config/config.rb +82 -0
- data/lib/ruber/config/plugin.yaml +3 -0
- data/lib/ruber/document_project.rb +209 -0
- data/lib/ruber/documents/document_list.rb +416 -0
- data/lib/ruber/documents/plugin.yaml +4 -0
- data/lib/ruber/editor/document.rb +506 -0
- data/lib/ruber/editor/editor_view.rb +167 -0
- data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
- data/lib/ruber/exception_widgets.rb +245 -0
- data/lib/ruber/external_program_plugin.rb +397 -0
- data/lib/ruber/filtered_output_widget.rb +342 -0
- data/lib/ruber/gui_states_handler.rb +231 -0
- data/lib/ruber/kde_config_option_backend.rb +167 -0
- data/lib/ruber/kde_sugar.rb +249 -0
- data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
- data/lib/ruber/main_window/main_window.rb +524 -0
- data/lib/ruber/main_window/main_window_actions.rb +537 -0
- data/lib/ruber/main_window/main_window_internal.rb +239 -0
- data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
- data/lib/ruber/main_window/output_color_widget.rb +35 -0
- data/lib/ruber/main_window/plugin.yaml +58 -0
- data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
- data/lib/ruber/main_window/status_bar.rb +156 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
- data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
- data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
- data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
- data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
- data/lib/ruber/main_window/workspace.rb +442 -0
- data/lib/ruber/output_widget.rb +1093 -0
- data/lib/ruber/plugin.rb +264 -0
- data/lib/ruber/plugin_like.rb +589 -0
- data/lib/ruber/plugin_specification.rb +106 -0
- data/lib/ruber/plugin_specification_reader.rb +451 -0
- data/lib/ruber/project.rb +493 -0
- data/lib/ruber/project_backend.rb +105 -0
- data/lib/ruber/projects/plugin.yaml +11 -0
- data/lib/ruber/projects/project_files_list.rb +314 -0
- data/lib/ruber/projects/project_files_widget.rb +301 -0
- data/lib/ruber/projects/project_list.rb +314 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
- data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
- data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
- data/lib/ruber/qt_sugar.rb +673 -0
- data/lib/ruber/settings_container.rb +515 -0
- data/lib/ruber/settings_dialog.rb +244 -0
- data/lib/ruber/settings_dialog_manager.rb +503 -0
- data/lib/ruber/utils.rb +414 -0
- data/lib/ruber/yaml_option_backend.rb +159 -0
- data/outsider_files +15 -0
- data/plugins/autosave/autosave.rb +404 -0
- data/plugins/autosave/plugin.yaml +16 -0
- data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
- data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
- data/plugins/command/command.png +0 -0
- data/plugins/command/command.rb +74 -0
- data/plugins/command/plugin.yaml +11 -0
- data/plugins/find_in_files/find_in_files.rb +337 -0
- data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
- data/plugins/find_in_files/find_in_files_ui.rc +11 -0
- data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
- data/plugins/find_in_files/plugin.yaml +23 -0
- data/plugins/find_in_files/ui/config_widget.rb +58 -0
- data/plugins/find_in_files/ui/config_widget.ui +41 -0
- data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
- data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
- data/plugins/project_browser/plugin.yaml +10 -0
- data/plugins/project_browser/project_browser.rb +245 -0
- data/plugins/rake/plugin.yaml +39 -0
- data/plugins/rake/rake.png +0 -0
- data/plugins/rake/rake.rb +567 -0
- data/plugins/rake/rake_extension.rb +153 -0
- data/plugins/rake/rake_widgets.rb +615 -0
- data/plugins/rake/rakeui.rc +27 -0
- data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
- data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
- data/plugins/rake/ui/choose_task_widget.rb +77 -0
- data/plugins/rake/ui/choose_task_widget.ui +72 -0
- data/plugins/rake/ui/config_widget.rb +127 -0
- data/plugins/rake/ui/config_widget.ui +123 -0
- data/plugins/rake/ui/project_widget.rb +217 -0
- data/plugins/rake/ui/project_widget.ui +246 -0
- data/plugins/rspec/plugin.yaml +30 -0
- data/plugins/rspec/rspec.png +0 -0
- data/plugins/rspec/rspec.rb +945 -0
- data/plugins/rspec/rspec.svg +90 -0
- data/plugins/rspec/rspecui.rc +20 -0
- data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
- data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
- data/plugins/ruby_development/plugin.yaml +27 -0
- data/plugins/ruby_development/ruby_development.png +0 -0
- data/plugins/ruby_development/ruby_development.rb +453 -0
- data/plugins/ruby_development/ruby_developmentui.rc +19 -0
- data/plugins/ruby_development/ui/project_widget.rb +112 -0
- data/plugins/ruby_development/ui/project_widget.ui +108 -0
- data/plugins/ruby_runner/config_widget.rb +116 -0
- data/plugins/ruby_runner/plugin.yaml +26 -0
- data/plugins/ruby_runner/project_widget.rb +62 -0
- data/plugins/ruby_runner/ruby.png +0 -0
- data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
- data/plugins/ruby_runner/ruby_runner.rb +411 -0
- data/plugins/ruby_runner/ui/config_widget.rb +92 -0
- data/plugins/ruby_runner/ui/config_widget.ui +91 -0
- data/plugins/ruby_runner/ui/project_widget.rb +60 -0
- data/plugins/ruby_runner/ui/project_widget.ui +48 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
- data/plugins/state/plugin.yaml +28 -0
- data/plugins/state/state.rb +520 -0
- data/plugins/state/ui/config_widget.rb +92 -0
- data/plugins/state/ui/config_widget.ui +89 -0
- data/plugins/syntax_checker/plugin.yaml +18 -0
- data/plugins/syntax_checker/syntax_checker.rb +662 -0
- data/ruber.desktop +10 -0
- data/spec/annotation_model_spec.rb +174 -0
- data/spec/common.rb +119 -0
- data/spec/component_manager_spec.rb +1259 -0
- data/spec/document_list_spec.rb +626 -0
- data/spec/document_project_spec.rb +373 -0
- data/spec/document_spec.rb +779 -0
- data/spec/editor_view_spec.rb +167 -0
- data/spec/external_program_plugin_spec.rb +676 -0
- data/spec/filtered_output_widget_spec.rb +642 -0
- data/spec/gui_states_handler_spec.rb +304 -0
- data/spec/kde_config_option_backend_spec.rb +214 -0
- data/spec/kde_sugar_spec.rb +101 -0
- data/spec/ktexteditor_wrapper_spec.rb +305 -0
- data/spec/output_widget_spec.rb +1703 -0
- data/spec/plugin_spec.rb +1393 -0
- data/spec/plugin_specification_reader_spec.rb +1765 -0
- data/spec/plugin_specification_spec.rb +401 -0
- data/spec/project_backend_spec.rb +172 -0
- data/spec/project_files_list_spec.rb +401 -0
- data/spec/project_list_spec.rb +511 -0
- data/spec/project_spec.rb +990 -0
- data/spec/qt_sugar_spec.rb +328 -0
- data/spec/settings_container_spec.rb +617 -0
- data/spec/settings_dialog_manager_spec.rb +773 -0
- data/spec/settings_dialog_spec.rb +419 -0
- data/spec/state_spec.rb +991 -0
- data/spec/utils_spec.rb +406 -0
- data/spec/workspace_spec.rb +869 -0
- data/spec/yaml_option_backend_spec.rb +246 -0
- metadata +284 -0
|
@@ -0,0 +1,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
|