Class: Ruber::Document

Inherits:
Qt::Object
  • Object
show all
Extended by:
Forwardable
Includes:
Activable, KTextEditorWrapper
Defined in:
lib/ruber/editor/document.rb

Constant Summary

ICON_NAMES =

A hash associating icon roles used by Document with icon names. It is used by ICONS

{ 
:modified => 'document-save',
:modified_on_disk => 'dialog-warning'
}
ICONS =

Hash containing a list of predefined icons, each associated with a role (usually a symbol describing the icon’s use).

At the beginning, this hash is empty. It is automatically filled by loading icons according with the associations specified in ICON_NAMES as they’re requested. This is necessary because the hash is created when this file is read, which may happen before the application is created.

Hash.new do |h, k|
  icon = KDE::IconLoader.load_icon ICON_NAMES[k]
  h[k] = icon
end

Instance Method Summary (collapse)

Methods included from KTextEditorWrapper

#connect_wrapped_signals, #initialize_wrapper, #interface, #internal, #method_missing, prepare_wrapper_connections

Methods included from Activable

#activate, #active=, #active?, #deactivate, #do_activation, #do_deactivation

Signal Summary

Constructor Details

- (Document) initialize(file = nil, parent = nil)

Creates a new Ruber::Document.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ruber/editor/document.rb', line 118

def initialize file = nil, parent = nil
  super parent
  @active = false
  @doc = KTextEditor::EditorChooser.editor('katepart').create_document( self)
  initialize_wrapper @doc, self.class.instance_variable_get(:@signal_table)
  @views = []
  @doc.openUrl(file.is_a?(String) ? KDE::Url.from_path(file) : file) if file
  @annotation_model = AnnotationModel.new self
  interface('annotation_interface').annotation_model = @annotation_model
  interface('modification_interface').modified_on_disk_warning = true
  @modified_on_disk = false
  @project = DocumentProject.new self
  @project.finalize
  @doc.connect(SIGNAL('modifiedChanged(KTextEditor::Document*)')) do |doc|
    emit modified_changed(@doc.modified?, self)
  end
  @doc.connect(SIGNAL('documentUrlChanged(KTextEditor::Document*)')) do |doc|
    if !doc.url.remote_file?
      Ruber[:components].each_component{|c| c.update_project @project}
    end
    emit document_url_changed self
  end
  
  @doc.connect SIGNAL(:completed) do
    if @doc.url.remote_file?
      Ruber[:components].each_component{|c|c.update_project @project}
    end
    emit completed
  end
  
  @doc.connect SIGNAL('documentNameChanged(KTextEditor::Document*)') do |doc|
    emit document_name_changed doc.document_name, self
  end
  
  @doc.connect(SIGNAL('textChanged(KTextEditor::Document*, KTextEditor::Range, KTextEditor::Range)')){|_, o, n| emit text_modified(o, n, self)}
  
  @doc.connect(SIGNAL('textInserted(KTextEditor::Document*, KTextEditor::Range)')) do |_, r| 
    begin
      emit text_inserted(r, self)
    rescue ArgumentError => e
      ExceptionDialog.new e, nil, true, "An exception was raised from emit text_inserted. See issue number 6 at http://github.com/stcrocco/ruber/issues"
    end
  end
  
  @doc.connect(SIGNAL('textRemoved(KTextEditor::Document*, KTextEditor::Range)')){|_, r| emit text_removed(r, self)}
  @doc.connect(SIGNAL('modifiedOnDisk(KTextEditor::Document*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)')) do |_, mod, reason|
    @modified_on_disk = (reason != KTextEditor::ModificationInterface::OnDiskUnmodified)
    emit modified_on_disk(self, mod, reason)
  end
  connect @doc, SIGNAL('completed(bool)'), self, SIGNAL('completed1(bool)')

end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Ruber::KTextEditorWrapper

Instance Method Details

- (EditorView?) active_view

The view which currently has user focus, if any

Returns:

  • (EditorView, nil)

    the view associated with the document which currently has user focus or nil if none of the views associated with the document has user focus



198
199
200
# File 'lib/ruber/editor/document.rb', line 198

def active_view
  @doc.active_view.parent rescue nil
end

- (Object) close(ask = true)

Closes the document. If ask is true, the query_close method is called, asking the user what to do if the document is modified. If the user confirms closing or if there’s no need of confirmation, the following happens:

  • the closing(QObject*) signal is emitted
  • the view (if it exists) is closed
  • the close_url method is called
  • all the documnent extensions are removed
  • al singnals are disconnected from the document
  • the document is disposed of

Returns true if the document was closed and false otherwise

TODO: maybe remove the argument, since this method is not called anymore at



452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/ruber/editor/document.rb', line 452

def close ask = true
  if !ask || query_close
    emit closing(self)
    @project.save unless path.empty?
    @views.dup.each{|v| v.close}
    return false unless close_url false
    @project.close false
    delete_later
    self.disconnect
    true
  else false
  end
end

- (Object) create_view(parent = nil)

Creats a view for the document. parent is the view’s parent widget. Raises RuntimeError if the document already has a view.



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/ruber/editor/document.rb', line 338

def create_view parent = nil
  inner_view = @doc.create_view nil
  view = EditorView.new self, inner_view, parent
  @views << view
  gui = view.send(:internal)
  action = gui.action_collection.action('file_save_as')
  disconnect action, SIGNAL(:triggered), @doc, SLOT('documentSaveAs()')
  connect action, SIGNAL(:triggered), self, SLOT(:document_save_as)
  action = gui.action_collection.action('file_save')
  disconnect action, SIGNAL(:triggered), @doc, SLOT('documentSave()')
  connect action, SIGNAL(:triggered), self, SLOT(:save)
  view.connect(SIGNAL('closing(QWidget*)')) do |v| 
    emit closing_view v, self
    @views.delete v
  end
  emit view_created(view, self)
  view
end

- (Object) document_save_as (private)

Works like KTextEditor::Document#documentSave but sets the starting directory to either the project directory, if there’s an active project, or to the default script directory otherwise.

Note: there’s a small difference with KTextEditor::Document#documentSave. In that method, the encoding initially selected in the combo box is read from the configuration. Since I couldn’t figure how to access that, instead, the default encoding here is set to UTF-8 if using ruby 1.9 and to ISO-8859-1 if using ruby 1.8



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/ruber/editor/document.rb', line 484

def document_save_as
  enc = RUBY_VERSION.match(/1\.9/) ? 'UTF-8' : 'ISO-8859-1'
  prj = Ruber[:world].active_project
  path = if !self.path.empty? then self.path
  elsif prj then prj.project_directory
  else ''
  end
  
  res = KDE::EncodingFileDialog.get_save_file_name_and_encoding enc, path, '', 
      Ruber[:main_window], KDE.i18n('Save File')
  return false if res.file_names.empty? or res.file_names.first.empty?
  u = KDE::Url.new res.file_names.first
  if u.is_local_file and File.exist?(u.path)
    ans = KDE::MessageBox.warning_continue_cancel Ruber[:main_window],
        KDE.i18n(format("A file named \"%s\" already exists. \nAre you sure you want to overwrite it?", u.path)),
        i18n( "Overwrite File?" ), KDE::StandardGuiItem.overwrite,
        KDE::StandardGuiItem.cancel, '', KDE::MessageBox::Notify | KDE::MessageBox::Dangerous
    return false if ans == KDE::MessageBox::Cancel
  end
  @doc.encoding = res.encoding
  @project.save
  @doc.saveAs u
end

Slot Signature:

document_save_as()

- (Object) editing

Executes the given block inside a pair of start_editing/end_editing calls.



429
430
431
432
433
434
435
# File 'lib/ruber/editor/document.rb', line 429

def editing
  begin
    @doc.start_editing
    yield
  ensure @doc.end_editing
  end
end

- (Object) execute_action(name, arg = nil)

Executes the action with name name contained in document’s view’s action collection. This is made by having the action emit the triggered() or toggled(bool) signal (depending on whether it’s a standard action or a KDE::ToggleAction). In the second case, arg is the argument passed to the signal.

Returns true if name is the name of an action and false otherwise.

Note: for this method to work, a view should have been created for the document, otherwise this method will always return *false.



214
215
216
# File 'lib/ruber/editor/document.rb', line 214

def execute_action name, arg = nil
  @view ? @view.execute_action( name, arg) : false
end

- (Object) extension(name)

Returns the document extension with name name or nil if such an extension doesn’t exist



251
252
253
# File 'lib/ruber/editor/document.rb', line 251

def extension name
  @project.extension name
end

- (Boolean) file_type_match?(mimetypes = [], patterns = [])

Compares the mimetype and file name of the document with a list of mimetypes ( using KDE::MimeType#=~) and/or patterns (using File.fnmatch), returning true if any of the comparisons is successful and false if all fails. Both mimetypes and patterns can be either a string or an array of strings (a single string will be treated as an array containing a single string).

====Notes:

  • if both mimetypes and patterns are empty, the comparison always returns true.
  • if the document is not associated with a file (that is, if path returns an empty string) it won’t match any pattern. It will match the text/plain mimetype, however.
  • only the basename of the file will be taken into account for pattern matching. For example, the pattern abc/xyz.jkl will match the pattern xyz.jkl, which wouldn’t be the case if the whole filename was included.

Returns:

  • (Boolean)


235
236
237
238
239
240
241
242
243
244
245
# File 'lib/ruber/editor/document.rb', line 235

def file_type_match? mimetypes = [], patterns = []
  mime = KDE::MimeType.mime_type @doc.mime_type
  mimetypes = Array(mimetypes).reject{|i| i.empty?}
  patterns = Array(patterns).reject{|i| i.empty?}
  base = File.basename path
  if mimetypes.empty? and patterns.empty? then true
  elsif mimetypes.any? {|m| mime =~ m} then true
  elsif patterns.any? {|pat| File.fnmatch? pat, base, File::FNM_DOTMATCH} then true
  else false
  end
end

- (Boolean) has_file?(which = :any)

Whether the document is associated with a file

Depending on the value of which this method can also return true only if the document is associated with a local file or with a remote file. In particular:

  • if it’s :local this method will return true only if the document is associated with a local file
  • if it’s :remote, this method will return true only if the document is associated with a remote file
  • with any other value, this method will return true if the document is associated with any file

Parameters:

  • which (Symbol, Object) (defaults to: :any)

    the kind of files which are acceptable

Returns:

  • (Boolean)

    true if the document is associated with a file of the kind matching which and false otherwise



288
289
290
291
292
293
294
295
296
# File 'lib/ruber/editor/document.rb', line 288

def has_file? which = :any
  u = url
  return false if u.empty?
  case which
  when :local then url.local_file?
  when :remote then !url.local_file?
  else true
  end
end

- (Boolean) has_view?

Whether the document has at least one view associated with it

Returns:

  • (Boolean)

    whether the document has at least one view associated with it



188
189
190
# File 'lib/ruber/editor/document.rb', line 188

def has_view?
  !@views.empty?
end

- (Object) icon

Returns an appropriate Qt::Icon for the document, depending on the mimetype and the status of the document.



259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/ruber/editor/document.rb', line 259

def icon
  if @modified_on_disk then ICONS[:modified_on_disk]
  elsif @doc.modified? then ICONS[:modified]
  else
    if has_file? :remote
      mime = KDE::MimeType.find_by_content Qt::ByteArray.new(@doc.text)
    else mime = KDE::MimeType.mime_type(@doc.mime_type)
    end
    icon_name = mime.icon_name
    Qt::Icon.new(KDE::IconLoader.load_mime_type_pixmap icon_name)
  end
end

- (Object) inspect



109
110
111
112
113
# File 'lib/ruber/editor/document.rb', line 109

def inspect
  if disposed? then "< #{self.class} #{object_id} DISPOSED >"
  else super
  end
end

- (String) line(n)

As KTextEditor::Document#line

Parameters:

  • n (Integer)

    the line number

Returns:

  • (String)

    the text in the given line or an empty string if the line is out of range



421
422
423
# File 'lib/ruber/editor/document.rb', line 421

def line n
  @doc.line(n) || ''
end

- (Boolean) modified_on_disk?

Tells whether the document is modified on disk or not

Returns:

  • (Boolean)


312
313
314
# File 'lib/ruber/editor/document.rb', line 312

def modified_on_disk?
  @modified_on_disk
end

- (Object) own_project

Returns the DocumentProject associated with the document



379
380
381
# File 'lib/ruber/editor/document.rb', line 379

def own_project
  @project
end

- (Object) path

Returns the path of the document



390
391
392
# File 'lib/ruber/editor/document.rb', line 390

def path
  @doc.url.path || ''
end

- (Boolean) pristine?

Tells whether the document is pristine or not. A pristine document is an empty, unmodified document which hasn’t a file associated with it. The document returned by Document.new is pristine is the second argument is nil, but it’s not pristine if a non-nil second argument was given (because in that case the document has a file associated with it).

Returns:

  • (Boolean)


305
306
307
# File 'lib/ruber/editor/document.rb', line 305

def pristine?
  @doc.url.empty? and !@doc.modified? and @doc.text.nil?
end

- (Object) project

Return the project with wider scope the document belongs to. This is:

  • the current global project if it exists and the document is associated with a file belonging to it
  • the document project if there’s no active global project or the document isn’t associated with a file or the file doesn’t belong the global project


370
371
372
373
374
# File 'lib/ruber/editor/document.rb', line 370

def project
  prj = Ruber[:world].active_project
  return @project if path.empty? or !prj
  prj.file_in_project?(url.to_encoded.to_s) ? prj : @project
end

- (Object) save

Saves the document. If the document is already associated with a file, it’s saved in that file; otherwise, a Save As dialog is displayed for the user to choose a file name. Returns true if the document was saved and false if it wasn’t for some reason (for example, if the user doesn’t have write perimission on the file or if he pressed the Cancel button in the Save As dialog).

This method is associated with the Save menu entry



325
326
327
328
329
330
331
332
# File 'lib/ruber/editor/document.rb', line 325

def save
  if path.empty? || !is_read_write then document_save_as
  else 
    res = @doc.save
    @project.save
    res
  end
end

Slot Signature:

save()

- (Object) save_settings



383
384
385
# File 'lib/ruber/editor/document.rb', line 383

def save_settings
  @project.save unless path.empty?
end

- (String) text - (String) text(range, block = false)

Note:

We can’t just delegate this method to the internal KTextEditor::Document

The document’s text

because its text method returns nil if there’s no text in the document, instead of an empty string.

Overloads:

  • - (String) text

    The text in the whole document

    Returns:

    • (String)

      the text in the whole document

  • - (String) text(range, block = false)

    The text contained in the given range

    Parameters:

    • range (KTextEditor::Range)

      the range of text to retrieve

    • block (Boolean)

      whether or not to consider the range as a visual block

    Returns:

    • (String)

      the text inside the range. An empty string is returned if the range is invalid



410
411
412
# File 'lib/ruber/editor/document.rb', line 410

def text *args
  @doc.text(*args) || ''
end

- (Object) views

@return [Array] a list of all the views associated with the document



181
182
183
# File 'lib/ruber/editor/document.rb', line 181

def views
  @views.dup
end

Signal Details

- modified_changed(bool arg1, QObject* arg2)

- document_name_changed(QString arg1, QObject* arg2)

- text_changed(QObject* arg1)

- about_to_close(QObject* arg1)

- about_to_reload(QObject* arg1)

- document_url_changed(QObject* arg1)

- highlighting_mode_changed(QObject* arg1)

- mode_changed(QObject* arg1)

- text_modified(KTextEditor::Range arg1, KTextEditor::Range arg2, QObject* arg3)

- text_inserted(KTextEditor::Range arg1, QObject* arg2)

- text_removed(KTextEditor::Range arg1, QObject* arg2)

- view_created(QObject* arg1, QObject* arg2)

- closing(QObject* arg1)

- activated

- deactivated

- modified_on_disk(QObject* arg1, bool arg2, KTextEditor::ModificationInterface::ModifiedOnDiskReason arg3)

- sig_query_close(bool* arg1, bool* arg2)

- canceled(QString arg1)

- completed

- completed1(bool arg1)

- started(KIO::Job* arg1)

- set_status_bar_text(QString arg1)

- setWindowCaption(QString arg1)

- closing_view(QWidget* view, QObject* doc)

Signal emitted before a view associated with the document is closed

When this signal is emitted, the view is still associated with the document, and it is still included in the array returned by #views

Parameters:

- document_saved_or_uploaded(QObject* arg1, bool arg2)