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(parent = nil, file = nil) ⇒ Document

Creates a new Ruber::Document.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/ruber/editor/document.rb', line 88

def initialize parent = nil, file = 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



161
162
163
# File 'lib/ruber/editor/document.rb', line 161

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



409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/ruber/editor/document.rb', line 409

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.



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/ruber/editor/document.rb', line 301

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.



386
387
388
389
390
391
392
# File 'lib/ruber/editor/document.rb', line 386

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.



177
178
179
# File 'lib/ruber/editor/document.rb', line 177

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



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

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)


198
199
200
201
202
203
204
205
206
207
208
# File 'lib/ruber/editor/document.rb', line 198

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



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

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



151
152
153
# File 'lib/ruber/editor/document.rb', line 151

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.



222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/ruber/editor/document.rb', line 222

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



79
80
81
82
83
# File 'lib/ruber/editor/document.rb', line 79

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



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

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

#modified_on_disk?Boolean

Tells whether the document is modified on disk or not

Returns:

  • (Boolean)


275
276
277
# File 'lib/ruber/editor/document.rb', line 275

def modified_on_disk?
  @modified_on_disk
end

#own_projectObject

Returns the DocumentProject associated with the document



336
337
338
# File 'lib/ruber/editor/document.rb', line 336

def own_project
  @project
end

#pathObject

Returns the path of the document



347
348
349
# File 'lib/ruber/editor/document.rb', line 347

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)


268
269
270
# File 'lib/ruber/editor/document.rb', line 268

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



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

def project
  prj = Ruber[:projects].current
  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



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

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

#save_settingsObject



340
341
342
# File 'lib/ruber/editor/document.rb', line 340

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



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

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

#viewsArray<EditorView>

Returns a list of the views assciated with the document.

Returns:



144
145
146
# File 'lib/ruber/editor/document.rb', line 144

def views
  @views.dup
end