Class: Ruber::Document

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

Instance Method Summary collapse

Methods included from KTextEditorWrapper

#interface, #method_missing, prepare_wrapper_connections

Methods included from Activable

#activate, #active=, #active?, #deactivate

Constructor Details

#initialize(file = nil, parent = nil) ⇒ Document

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
  
  @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 when writing text. 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

#active_viewEditorView?

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



191
192
193
# File 'lib/ruber/editor/document.rb', line 191

def active_view
  @doc.active_view.parent rescue nil
end

#close(ask = true) ⇒ Object

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



439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/ruber/editor/document.rb', line 439

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

#create_view(parent = nil) ⇒ Object

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



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/ruber/editor/document.rb', line 331

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

#editingObject

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



416
417
418
419
420
421
422
# File 'lib/ruber/editor/document.rb', line 416

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

#execute_action(name, arg = nil) ⇒ Object

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.



207
208
209
# File 'lib/ruber/editor/document.rb', line 207

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

#extension(name) ⇒ Object

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



244
245
246
# File 'lib/ruber/editor/document.rb', line 244

def extension name
  @project.extension name
end

#file_type_match?(mimetypes = [], patterns = []) ⇒ Boolean

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)


228
229
230
231
232
233
234
235
236
237
238
# File 'lib/ruber/editor/document.rb', line 228

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

#has_file?(which = :any) ⇒ Boolean

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



281
282
283
284
285
286
287
288
289
# File 'lib/ruber/editor/document.rb', line 281

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

#has_view?Boolean

Returns whether the document has at least one view associated with it.

Returns:

  • (Boolean)

    whether the document has at least one view associated with it



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

def has_view?
  !@views.empty?
end

#iconObject

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



252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/ruber/editor/document.rb', line 252

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

#inspectObject



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

#line(n) ⇒ String

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



408
409
410
# File 'lib/ruber/editor/document.rb', line 408

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

#modified_on_disk?Boolean

Tells whether the document is modified on disk or not

Returns:

  • (Boolean)


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

def modified_on_disk?
  @modified_on_disk
end

#own_projectObject

Returns the DocumentProject associated with the document



366
367
368
# File 'lib/ruber/editor/document.rb', line 366

def own_project
  @project
end

#pathObject

Returns the path of the document



377
378
379
# File 'lib/ruber/editor/document.rb', line 377

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

#pristine?Boolean

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)


298
299
300
# File 'lib/ruber/editor/document.rb', line 298

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

#projectObject

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



357
358
359
360
361
# File 'lib/ruber/editor/document.rb', line 357

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

#saveObject

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



318
319
320
321
322
323
324
325
# File 'lib/ruber/editor/document.rb', line 318

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

#save_settingsObject



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

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

#textString #text(range, block = false) ⇒ String

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:

  • #textString

    The text in the whole document

    Returns:

    • (String)

      the text in the whole document

  • #text(range, block = false) ⇒ String

    The text contained in the given range

    Parameters:

    • range (KTextEditor::Range)

      the range of text to retrieve

    • block (Boolean) (defaults to: false)

      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



397
398
399
# File 'lib/ruber/editor/document.rb', line 397

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

#viewsObject

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



174
175
176
# File 'lib/ruber/editor/document.rb', line 174

def views
  @views.dup
end