ruber 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/CHANGES +25 -0
  2. data/bin/ruber +0 -0
  3. data/data/share/apps/ruber/ruberui.rc +15 -1
  4. data/data/share/icons/{ruber.png → ruber-old.pgn} +0 -0
  5. data/lib/ruber/application/application.rb +216 -73
  6. data/lib/ruber/application/plugin.yaml +2 -2
  7. data/lib/ruber/document_project.rb +25 -5
  8. data/lib/ruber/documents/document_list.rb +11 -15
  9. data/lib/ruber/editor/document.rb +106 -50
  10. data/lib/ruber/editor/editor_view.rb +4 -2
  11. data/lib/ruber/external_program_plugin.rb +8 -0
  12. data/lib/ruber/kde_config_option_backend.rb +12 -4
  13. data/lib/ruber/kde_sugar.rb +35 -1
  14. data/lib/ruber/main_window/choose_plugins_dlg.rb +10 -10
  15. data/lib/ruber/main_window/hint_solver.rb +263 -0
  16. data/lib/ruber/main_window/main_window.rb +462 -206
  17. data/lib/ruber/main_window/main_window_actions.rb +228 -62
  18. data/lib/ruber/main_window/main_window_internal.rb +169 -115
  19. data/lib/ruber/main_window/plugin.yaml +13 -3
  20. data/lib/ruber/main_window/save_modified_files_dlg.rb +1 -1
  21. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +1 -1
  22. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +1 -1
  23. data/lib/ruber/main_window/ui/new_project_widget.rb +1 -1
  24. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +1 -1
  25. data/lib/ruber/main_window/ui/output_color_widget.rb +1 -1
  26. data/lib/ruber/main_window/ui/workspace_settings_widget.rb +51 -0
  27. data/lib/ruber/main_window/ui/workspace_settings_widget.ui +28 -0
  28. data/lib/ruber/main_window/view_manager.rb +418 -0
  29. data/lib/ruber/main_window/workspace.png +0 -0
  30. data/lib/ruber/output_widget.rb +43 -37
  31. data/lib/ruber/pane.rb +621 -0
  32. data/lib/ruber/plugin_specification_reader.rb +8 -1
  33. data/lib/ruber/projects/project_files_list.rb +6 -0
  34. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +1 -1
  35. data/lib/ruber/projects/ui/project_files_widget.rb +1 -1
  36. data/lib/ruber/qt_sugar.rb +94 -4
  37. data/lib/ruber/utils.rb +16 -7
  38. data/lib/ruber/version.rb +2 -2
  39. data/plugins/autosave/autosave.rb +62 -1
  40. data/plugins/autosave/plugin.yaml +1 -0
  41. data/plugins/autosave/ui/autosave_config_widget.rb +37 -14
  42. data/plugins/autosave/ui/autosave_config_widget.ui +62 -12
  43. data/plugins/find_in_files/find_in_files_widgets.rb +1 -3
  44. data/plugins/find_in_files/ui/config_widget.rb +1 -1
  45. data/plugins/find_in_files/ui/find_in_files_widget.rb +1 -1
  46. data/plugins/rake/plugin.yaml +1 -1
  47. data/plugins/rake/ui/add_quick_task_widget.rb +1 -1
  48. data/plugins/rake/ui/choose_task_widget.rb +1 -1
  49. data/plugins/rake/ui/config_widget.rb +1 -1
  50. data/plugins/rake/ui/project_widget.rb +1 -1
  51. data/plugins/rspec/rspec.rb +14 -22
  52. data/plugins/rspec/ruber_rspec_formatter.rb +4 -1
  53. data/plugins/rspec/ui/rspec_project_widget.rb +1 -1
  54. data/plugins/ruby_development/plugin.yaml +7 -2
  55. data/plugins/ruby_development/ruby_development.rb +134 -13
  56. data/plugins/ruby_development/ui/config_widget.rb +66 -0
  57. data/plugins/ruby_development/ui/config_widget.ui +58 -0
  58. data/plugins/ruby_development/ui/project_widget.rb +1 -1
  59. data/plugins/ruby_runner/plugin.yaml +2 -2
  60. data/plugins/ruby_runner/ruby_runner.rb +15 -3
  61. data/plugins/ruby_runner/ui/config_widget.rb +1 -1
  62. data/plugins/ruby_runner/ui/project_widget.rb +1 -1
  63. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +1 -1
  64. data/plugins/state/plugin.yaml +6 -2
  65. data/plugins/state/state.rb +305 -81
  66. data/plugins/state/ui/config_widget.rb +1 -1
  67. data/spec/common.rb +11 -3
  68. data/spec/document_list_spec.rb +8 -8
  69. data/spec/document_project_spec.rb +98 -25
  70. data/spec/document_spec.rb +178 -152
  71. data/spec/editor_view_spec.rb +26 -5
  72. data/spec/framework.rb +5 -0
  73. data/spec/hint_solver_spec.rb +450 -0
  74. data/spec/kde_sugar_spec.rb +73 -6
  75. data/spec/output_widget_spec.rb +172 -156
  76. data/spec/pane_spec.rb +1165 -0
  77. data/spec/plugin_specification_reader_spec.rb +37 -1
  78. data/spec/project_files_list_spec.rb +30 -20
  79. data/spec/qt_sugar_spec.rb +269 -0
  80. data/spec/state_spec.rb +566 -353
  81. data/spec/utils_spec.rb +1 -1
  82. data/spec/view_manager_spec.rb +71 -0
  83. metadata +16 -4
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>RubyDevelopmentConfigWidget</class>
4
+ <widget class="QWidget" name="RubyDevelopmentConfigWidget">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>400</width>
10
+ <height>38</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QHBoxLayout" name="horizontalLayout">
17
+ <item>
18
+ <widget class="QLabel" name="label">
19
+ <property name="toolTip">
20
+ <string>The command to use to run a ruby script in a terminal</string>
21
+ </property>
22
+ <property name="whatsThis">
23
+ <string>In the command line, use %d to indicate the initial working directory for the terminal and %r to indicate where to put the ruby command line. The %r sequence should be either sourrounded by spaces or have a space before it and the end of the command after it.
24
+
25
+ Note that you can't use arguments containing spaces in the command line.</string>
26
+ </property>
27
+ <property name="text">
28
+ <string>&amp;Terminal</string>
29
+ </property>
30
+ <property name="buddy">
31
+ <cstring>_ruby__run_in_terminal_cmd</cstring>
32
+ </property>
33
+ </widget>
34
+ </item>
35
+ <item>
36
+ <widget class="KLineEdit" name="_ruby__run_in_terminal_cmd">
37
+ <property name="toolTip">
38
+ <string>The command to use to run a ruby script in a terminal</string>
39
+ </property>
40
+ <property name="whatsThis">
41
+ <string>In the command line, use %d to indicate the initial working directory for the terminal and %r to indicate where to put the ruby command line.
42
+
43
+ Note that you can't use arguments containing spaces in the command line</string>
44
+ </property>
45
+ </widget>
46
+ </item>
47
+ </layout>
48
+ </widget>
49
+ <customwidgets>
50
+ <customwidget>
51
+ <class>KLineEdit</class>
52
+ <extends>QLineEdit</extends>
53
+ <header>klineedit.h</header>
54
+ </customwidget>
55
+ </customwidgets>
56
+ <resources/>
57
+ <connections/>
58
+ </ui>
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'project_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -7,7 +7,7 @@ about:
7
7
  bug_address: http://github.com/stcrocco/ruber/issues
8
8
  icon: ruby.png
9
9
  class: Ruber::RubyRunner::RubyInterpretersPlugin
10
- require: ruby_runner
10
+ require: ruby_runner.rb
11
11
  ui_file: ruby_interpretersui.rc
12
12
  features: [ruby_interpreters]
13
13
  config_widgets:
@@ -19,7 +19,7 @@ config_options:
19
19
  ruby_options: {:default: [-w]}
20
20
  project_options:
21
21
  ruby:
22
- ruby: {default: 'Ruber[:config][:ruby, :ruby]', scope: [global, document], mimetype: 'application/x-ruby', file_extension: [*.rb, Rakefile, rakefile]}
22
+ ruby: {default: 'Ruber[:config][:ruby, :ruby]', scope: [global, document], mimetype: 'application/x-ruby', file_extension: [*.rb, Rakefile, rakefile], place: all}
23
23
  project_widgets:
24
24
  - {caption: Ruby, pixmap: ruby.png, class: 'Ruber::RubyRunner::ProjectWidget', scope: [global, document], mimetype: 'application/x-ruby', file_extension: [*.rb, Rakefile, rakefile]}
25
25
  actions:
@@ -156,7 +156,6 @@ the plugin
156
156
  def initialize psf
157
157
  silently do
158
158
  Object.const_set :RubyOptionsWidget, RubyOptionsWidget
159
- Ruber::RubyRunner.const_set :RubyRunnerPlugin, RubyRunnerPluginInternal
160
159
  end
161
160
  super
162
161
  @default_interpreter_action = action_collection.action('ruby_runner-configured_interpreter')
@@ -245,6 +244,18 @@ default entry is selected.
245
244
  nil
246
245
  end
247
246
 
247
+ =begin rdoc
248
+ Override of {PluginLike#unload}
249
+
250
+ Besides doing the same as the base class method, it also removes the @Ruber::RubyRunner::RubyRunnerPlugin@
251
+ constant, so that other plugins may reimplement it using another base class.
252
+ @return [nil]
253
+ =end
254
+ def unload
255
+ Ruber::RubyRunner.send :remove_const, :RubyRunnerPlugin
256
+ super
257
+ end
258
+
248
259
  end
249
260
 
250
261
  =begin
@@ -266,7 +277,7 @@ plugin.
266
277
  @api_method #interpreter_for
267
278
  @api_method #ruby_command_for
268
279
  =end
269
- class RubyRunnerPluginInternal < ExternalProgramPlugin
280
+ class RubyRunnerPlugin < ExternalProgramPlugin
270
281
 
271
282
  =begin rdoc
272
283
  Creates a new instance.
@@ -293,7 +304,7 @@ must be an array, even if it only contains one entry
293
304
  def initialize pso, group, rules = {}, order = nil, line_buffered = true
294
305
  group = group.to_sym
295
306
  @group = group
296
- default_rules = {:scope => [:global], :file_extension => [], :mimetype => []}
307
+ default_rules = {:scope => [:global], :file_extension => [], :mimetype => [], :place => [:local]}
297
308
  rules = default_rules.merge rules
298
309
  ruby_options_data = {
299
310
  :name => :ruby_options,
@@ -303,6 +314,7 @@ must be an array, even if it only contains one entry
303
314
  :mimetype => rules[:mimetype],
304
315
  :file_extension => rules[:file_extension],
305
316
  :order => order,
317
+ :place => rules[:place]
306
318
  }
307
319
  pso.project_options[[group, :ruby_options]] ||= PluginSpecificationReader::Option.new ruby_options_data
308
320
  super pso, line_buffered
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'config_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'project_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  ** Form generated from reading ui file 'ruby_runnner_plugin_option_widget.ui'
3
3
  **
4
- ** Created: ven ott 29 17:39:04 2010
4
+ ** Created: mar nov 16 11:52:49 2010
5
5
  ** by: Qt User Interface Compiler version 4.7.0
6
6
  **
7
7
  ** WARNING! All changes made in this file will be lost when recompiling ui file!
@@ -11,14 +11,18 @@ config_options:
11
11
  state:
12
12
  open_documents: {default: []}
13
13
  open_projects: {default: []}
14
- active_document: {default: nil}
15
14
  restore_cursor_position: {default: true}
16
15
  restore_project_files: {default: true}
17
16
  startup_behaviour: {default: :restore_all}
17
+ tabs: {default: []}
18
+ active_view: {default: nil}
19
+ cursor_positions: {default: []}
18
20
  project_options:
19
21
  state:
20
22
  open_documents: {default: [], type: session, scope: global}
21
- active_document: {default: ~, type: session, scope: global}
23
+ tabs: {default: [], scope: global, type: session}
24
+ cursor_positions: {default: [], type: session, scope: global }
25
+ active_view: {default: ~, type: session, scope: global}
22
26
  cursor_position: {default: [0, 0], type: session, scope: document}
23
27
  config_widgets:
24
28
  - {class: Ruber::State::ConfigWidget, caption: General}
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright (C) 2010 by Stefano Crocco
2
+ Copyright (C) 2010,2011 by Stefano Crocco
3
3
  stefano.crocco@alice.it
4
4
 
5
5
  This program is free software; you can redistribute it andor modify
@@ -30,12 +30,18 @@ module Ruber
30
30
  =begin rdoc
31
31
  Plugin which allows Ruber to store and restore back its state.
32
32
 
33
- In this context, the term _state_ means the open project and documents, the position
34
- of the cursor in each document and the active document. All this data is stored
33
+ In this context, the term _state_ means the open project and documents, the tabs
34
+ in the main window, the editors in each tab, the position of the cursor in the
35
+ editors and the active editor. All this data is stored
35
36
  in the configuration file and in the project or document project files. Using
36
37
  the API provided by this plugin, it is possible to restore a single document,
37
38
  project or the whole application to the state it was when it was last closed.
38
39
 
40
+ Documents which haven't been saved to a file are only partially restored: an empty
41
+ document is created for them (different views associated with the same document
42
+ will correctly be associated with the same empty document after restoration). Unsaved
43
+ changes in documents not associated with files won't be restored.
44
+
39
45
  In addition to providing an API for saving and restoring state, this plugin also
40
46
  restores the full Ruber state when restoring a session and (according to the
41
47
  user preferences) when the application starts up.
@@ -57,7 +63,7 @@ Plugin object for the State plugin
57
63
 
58
64
  =begin rdoc
59
65
  @param [Ruber::PluginSpecification] psf the plugin specification object associated
60
- with the plugin
66
+ with the plugin
61
67
  =end
62
68
  def initialize psf
63
69
  super
@@ -155,7 +161,7 @@ files in projects should be restored, regardless of what the user chose
155
161
  =begin rdoc
156
162
  Restores the given document
157
163
 
158
- See {DocumentExtension#restore} for more information
164
+ @see DocumentExtension#restore DocumentExtension#restore for more information
159
165
 
160
166
  @param [Ruber::Document] doc the document to restore
161
167
  @return [nil]
@@ -167,7 +173,7 @@ See {DocumentExtension#restore} for more information
167
173
  =begin rdoc
168
174
  Restores the given global project
169
175
 
170
- See {ProjectExtension#restore} for more information
176
+ @see ProjectExtension#restore ProjectExtension#restore for more information
171
177
 
172
178
  @param [Ruber::Project] prj the document to restore
173
179
  @return [nil]
@@ -179,6 +185,9 @@ See {ProjectExtension#restore} for more information
179
185
  =begin rdoc
180
186
  Restores the open projects according to a given configuration object
181
187
 
188
+ Restoring the project means closing all the open projects and opening the projects
189
+ and setting the active project according to the information in _conf_
190
+
182
191
  This method is called both when the session is restored and when ruber starts
183
192
  up (if the user chose so).
184
193
 
@@ -200,6 +209,13 @@ for more information
200
209
  =begin rdoc
201
210
  Restores the open documents according to a given configuration object
202
211
 
212
+ Restoring the open documents means:
213
+ * closing all the open documents. If any of thess is modified, the user is asked
214
+ how to proceed. If the choses to abort, nothing else is done
215
+ * opening the documents according to the @state/open_documents@ entry of _conf_
216
+ * recreating the tabs and the editors according to the @state/tabs@ entry of _conf_
217
+ * activating the editor contained in the @state/active_editor@ entry of _conf_
218
+
203
219
  This method is called both when the session is restored and when ruber starts
204
220
  up (if the user chose so).
205
221
 
@@ -208,17 +224,91 @@ for more information
208
224
  @return [nil]
209
225
  =end
210
226
  def restore_documents config = Ruber[:config]
211
- Ruber[:docs].close_all
212
- files = config[:state, :open_documents]
213
- return if files.empty?
214
- active_file = config[:state, :active_document]
215
- active_file = files[-1] unless files.include? active_file
227
+ return unless Ruber[:documents].close_all
228
+ docs = config[:state, :open_documents]
229
+ unnamed_docs = []
230
+ docs = docs.map do |i|
231
+ if i.is_a?(String) then Ruber[:documents].document(i)
232
+ else
233
+ doc = Ruber[:documents].new_document
234
+ unnamed_docs << doc
235
+ doc
236
+ end
237
+ end
238
+ return if docs.empty?
239
+ tabs = config[:state, :tabs]
216
240
  mw = Ruber[:main_window]
217
- mw.without_activating do
218
- files.each{|f| ed = mw.editor_for! f}
219
- mw.display_document active_file
241
+ positions = config[:state, :cursor_positions]
242
+ tabs.each_with_index do |t, i|
243
+ pn = restore_pane t, unnamed_docs
244
+ views = pn.to_a
245
+ views.each_with_index do |v, j|
246
+ cursor = KTextEditor::Cursor.new(*(positions[i][j] rescue [0,0]))
247
+ v.cursor_position = cursor
248
+ end
249
+ end
250
+ active_editor = config[:state, :active_view]
251
+ if active_editor
252
+ mw.focus_on_editor mw.tabs[active_editor[0]].to_a[active_editor[1]]
220
253
  end
221
- nil
254
+ end
255
+
256
+ =begin rdoc
257
+ Restores a pane
258
+
259
+ Restoring a pane means creating the editors which were contained in the pane,
260
+ in the correct disposition.
261
+
262
+ The contents of the pane are described by the array _data_, which has the following
263
+ format:
264
+
265
+ * if it has a single element, the corresponding pane contains only a view. If the
266
+ element is a string, it must represent the URL of the document the view is associated
267
+ with. If it is a number, it means the view is associated with a document which
268
+ hasn't been saved
269
+ * if it has more than one element, it means that the pane contains more than one
270
+ view. The first element represents the orientation of the pane and can be either
271
+ @Qt::Horizontal@ or @Qt::Vertical@. The other elements can be either strings,
272
+ numbers or arrays. A string or number means, as above, the URL of the document
273
+ associated with the view or a document which isn't associated with a file. An
274
+ array (which should have the same format as this) means a sub pane
275
+ @param [Array] data the array containing the description of the contents of the
276
+ pane
277
+ @param [Array<Document>] docs the document not associated with files to use for
278
+ the numeric entries of _data_. A number _n_ in _data_ means to use the entry
279
+ _n_ in _docs_
280
+ @return [Pane] the new pane
281
+ =end
282
+ def restore_pane data, docs
283
+ mw = Ruber[:main_window]
284
+ find_first_view = lambda do |array|
285
+ if array.size == 1 then array[0]
286
+ elsif array[1].is_a? Array then find_first_view.call array[1]
287
+ else array[1]
288
+ end
289
+ end
290
+ recreate_pane = lambda do |pn, array|
291
+ orientation = array[0]
292
+ last_view = pn.view
293
+ array.each_with_index do |e, i|
294
+ #the first element of the array is the orientation; the second is
295
+ #the first view, which is already contained in the pane
296
+ next if i < 2
297
+ view = e.is_a?(Array) ? find_first_view.call(e) : e
298
+ view = mw.editor_for! view.is_a?(String) ? view: docs[view],
299
+ :existing => :never, :show => false
300
+ pn.split last_view, view, orientation
301
+ last_view = view
302
+ recreate_pane.call view.parent, e if e.is_a? Array
303
+ end
304
+ recreate_pane.call pn.splitter.widget(0), array[1] if array[1].is_a?(Array)
305
+ end
306
+ view = find_first_view.call data
307
+ view = mw.editor_for! view.is_a?(String) ? view : docs[view],
308
+ :existing => :never, :new => :new_tab
309
+ pane = view.parent
310
+ recreate_pane.call pane, data
311
+ pane
222
312
  end
223
313
 
224
314
  =begin rdoc
@@ -262,7 +352,7 @@ Since this method deals with session management, it ignores the user settings
262
352
  @return [nil]
263
353
  =end
264
354
  def restore_session data
265
- hash = data['State'] || {:open_projects => [], :open_documents => [], :active_document => nil}
355
+ hash = data['State'] || {:open_projects => [], :open_documents => [], :active_view => nil, :tabs => []}
266
356
  hash = hash.map_hash{|k, v| [[:state, k], v]}
267
357
  def hash.[] k, v
268
358
  super [k, v]
@@ -281,8 +371,8 @@ Saves Ruber's state to the global config object
281
371
  def save_settings
282
372
  h = gather_settings
283
373
  cfg = Ruber[:config]
284
- [:open_projects, :open_documents, :active_document].each do |i|
285
- cfg[:state, i] = h[i]
374
+ h.each_pair do |k, v|
375
+ cfg[:state, k] = v
286
376
  end
287
377
  nil
288
378
  end
@@ -296,6 +386,84 @@ Override of {PluginLike#session_data}
296
386
  {'State' => gather_settings}
297
387
  end
298
388
 
389
+ =begin rdoc
390
+ The open projects in a form suitable to be written to a configuration object
391
+
392
+ @return [Array<String>] an array containing the names of the project files for
393
+ the currently open projects. The active project is the first one. This value
394
+ is the one to write under the @state/open_projects@ entry in a project or configuration
395
+ object
396
+ =end
397
+ def projects_state
398
+ projects = Ruber[:projects].projects.map{|pr| pr.project_file}
399
+ unless projects.empty?
400
+ active_prj = Ruber[:projects].current
401
+ projects.unshift projects.delete(active_prj.project_file) if active_prj
402
+ end
403
+ projects
404
+ end
405
+
406
+ =begin rdoc
407
+ The open documents in a form suitable to be written to a configuration object
408
+
409
+ @return [Array<String,nil>] an array containing the names of the URLs associated with
410
+ the currently open documents. Documents not associated with files are represented
411
+ by *nil*s in the array. This value is the one to write under the @state/open_documents@
412
+ entry in a project or configuration object
413
+ =end
414
+ def documents_state
415
+ docs = Ruber[:documents].documents
416
+ docs.map{ |doc| doc.has_file? ? doc.url.to_encoded.to_s : nil}
417
+ end
418
+
419
+ =begin rdoc
420
+ The open tabs configuration in a form suitable to be written to a configuration object
421
+
422
+ @return [Hash] A hash containing the following keys:
423
+ * @:tabs@: an array of arrays, with each inner array representing one tab, with
424
+ the format described in {#restore_pane}. This value is the one to write under
425
+ the @state/tabs@ entry in a project or configuration object
426
+ * @:cursor_positions@:an array of arrays. Each inner array corresponds to a tab
427
+ and contains the cursor position of each view. Each cursor position is represented
428
+ as an array with two elements: the first is the line, the second is the column.
429
+ The order the views are is the same used by {Pane#each_view}. This value is the one to write under
430
+ the @state/cursor_positions@ entry in a project or configuration object
431
+ * @:active_view@: the active view. It is represented by a size 2 array, with the
432
+ first element being the index of the tab of the active view and the second being
433
+ the index of the view in the corresponding pane (according to the order used by
434
+ {Pane#each_view}). If there's no active view, this entry is *nil*. This is the value to write under
435
+ the @state/active_view@ entry in a project or configuration object
436
+ =end
437
+ def tabs_state
438
+ res = {}
439
+ doc_map = {}
440
+ doc_idx = 0
441
+ Ruber[:documents].each do |doc|
442
+ if !doc.has_file?
443
+ doc_map[doc] = doc_idx
444
+ doc_idx += 1
445
+ end
446
+ end
447
+ tabs = Ruber[:main_window].tabs
448
+ tabs_tree = []
449
+ cursor_positions = []
450
+ tabs.each do |t|
451
+ tabs_tree << tab_to_tree(t, doc_map)
452
+ cursor_positions << t.map do |v|
453
+ pos = v.cursor_position
454
+ [pos.line, pos.column]
455
+ end
456
+ end
457
+ res[:tabs] = tabs_tree
458
+ res[:cursor_positions] = cursor_positions
459
+ active = Ruber[:main_window].active_editor
460
+ if active
461
+ active_tab = Ruber[:main_window].tab(active)
462
+ res[:active_view] = [tabs.index(active_tab), active_tab.to_a.index(active)]
463
+ end
464
+ res
465
+ end
466
+
299
467
  private
300
468
 
301
469
  =begin rdoc
@@ -307,60 +475,95 @@ Creates a hash with all the data needed to restore Ruber's state
307
475
  * @:open_documents@: an array with the name of the file corresponding to each
308
476
  open document (documents without an associated file can't be restored and aren't
309
477
  included). The order is that of opening
478
+ * @:visible_documents@: an array with the name of the files corresponding to the
479
+ documents associated with a file and having a view
310
480
  * @:active_document@: the name of the file associated with the active document or
311
481
  *nil* if there's no open document
312
482
  =end
313
483
  def gather_settings
314
- res = {}
315
- projects = Ruber[:projects].projects.map{|pr| pr.project_file}
316
- unless projects.empty?
317
- active_prj = Ruber[:projects].current
318
- projects.unshift projects.delete(active_prj.project_file) if active_prj
319
- end
320
- res[:open_projects] = projects
321
- docs = Ruber[:docs].documents.map{|doc| doc.path}.select{|path| !path.empty?}
322
- res[:open_documents] = docs
323
- current_doc = Ruber[:main_window].current_document.path rescue ''
324
- res[:active_document] = current_doc.empty? ? nil : current_doc
484
+ res = {
485
+ :open_projects => projects_state,
486
+ :open_documents => documents_state
487
+ }
488
+ res.merge! tabs_state
325
489
  res
326
490
  end
327
491
 
492
+ =begin rdoc
493
+ A representation of a pane's configuration suitable to be written to a configuration
494
+ object
495
+
496
+ @param [Pane] pane the pane to return the representation for
497
+ @param [Hash{Document=>Integer}] docs a map between documents not associated
498
+ with files and the number to represent them
499
+ @return [Array<Array,Integer,String>] an array as described in {#restore_pane}
500
+ =end
501
+ def tab_to_tree pane, docs
502
+ if pane.single_view?
503
+ doc = pane.view.document
504
+ return [doc.has_file? ? doc.url.url : docs[doc]]
505
+ end
506
+ panes = {}
507
+ tab_to_tree_prc = lambda do |pn|
508
+ if pn.single_view?
509
+ doc = pn.view.document
510
+ panes[pn.parent_pane] << (doc.has_file? ? doc.url.url : docs[doc])
511
+ else
512
+ data = [pn.orientation]
513
+ panes[pn] = data
514
+ panes[pn.parent_pane] << data if pn.parent_pane
515
+ end
516
+ end
517
+ tab_to_tree_prc.call pane
518
+ pane.each_pane :recursive, &tab_to_tree_prc
519
+ panes[pane]
520
+ end
521
+
328
522
  end
329
523
 
330
524
  =begin rdoc
331
525
  Extension for documents needed by the State plugin
332
526
 
333
- The scope of this extension is to save and restore the position of the cursor
334
- in the document
527
+ The scope of this extension is to move the cursor of all newly created views
528
+ associated with the document to the position it was in the last used view. The
529
+ cursor position for the first view is read from the document's own project, where
530
+ it is saved whenever the document is closed.
531
+
532
+ The cursor position for a view is moved in response to the {Document#view_created}
533
+ signal.
335
534
  =end
336
535
  class DocumentExtension < Qt::Object
337
536
 
338
537
  include Extension
339
538
 
340
- slots :auto_restore
539
+ slots 'auto_restore(QObject*)'
341
540
 
342
541
  =begin rdoc
343
542
  @param [Ruber::DocumentProject] prj the project associated with the document
344
543
  =end
345
544
  def initialize prj
346
545
  super
546
+ @last_view = nil
347
547
  @project = prj
348
548
  @document = prj.document
349
- connect @document, SIGNAL('view_created(QObject*, QObject*)'), self, SLOT(:auto_restore)
549
+ connect @document, SIGNAL('view_created(QObject*, QObject*)'), self, SLOT('auto_restore(QObject*)')
550
+ connect @document, SIGNAL('closing_view(QWidget*, QObject*)'), self, SLOT('view_closing(QWidget*)')
350
551
  end
351
552
 
352
553
  =begin rdoc
353
- Restores the position of the cursor according to the value saved in the document's
354
- own project
554
+ Moves the cursor of a view to the position it was in the last used view
355
555
 
356
- It does nothing if the document isn't associated with a view
556
+ If there are no other views associated with the document, the position of the
557
+ cursor is read from the document's own project
558
+ @param [EditorView] the view to move the cursor for
357
559
  @return [nil]
358
560
  =end
359
- def restore
360
- view = @document.view
361
- return unless view
362
- pos = @document.own_project[:state, :cursor_position]
363
- view.go_to *pos
561
+ def restore view
562
+ if @last_view then view.cursor_position = @last_view.cursor_position
563
+ else
564
+ pos = @document.own_project[:state, :cursor_position]
565
+ view.go_to *pos
566
+ end
364
567
  nil
365
568
  end
366
569
 
@@ -371,43 +574,74 @@ It does nothing if the document isn't associated with a view
371
574
  @return [nil]
372
575
  =end
373
576
  def save_settings
374
- view = @document.view
375
- pos = if view
376
- cur = view.cursor_position
377
- [cur.line, cur.column]
378
- else [0,0]
379
- end
380
- @project[:state, :cursor_position] = pos
577
+ if @last_view
578
+ cur = @last_view.cursor_position
579
+ pos = [cur.line, cur.column]
580
+ @project[:state, :cursor_position] = pos
581
+ end
381
582
  nil
382
583
  end
383
584
 
384
585
  private
385
586
 
386
587
  =begin rdoc
387
- Moves the cursor in a new view to the position stored in the document's own project
588
+ Restores the cursor position for a view if the user choosed to do so
589
+
590
+ It does nothing if the user choosed not to restore the cursor position when a view
591
+ is created
592
+
593
+ @param [EditorView] the view to restore the cursor position for
594
+ @return [nil]
595
+ =end
596
+ def auto_restore view
597
+ restore view if Ruber[:state].restore_cursor_position?
598
+ connect view, SIGNAL('focus_in(QWidget*)'), self, SLOT('view_received_focus(QWidget*)')
599
+ nil
600
+ end
601
+
602
+ =begin rdoc
603
+ Memorizes which view has last received focus
388
604
 
389
- It does nothing if the user chose not to have the position restored when opening
390
- a document.
605
+ This information is used to decide which view to ask for the cursor position when
606
+ a new view is created or the cursor position needs to be saved to the project
607
+ @param [EditorView] view the view which has received focus
391
608
  @return [nil]
392
609
  =end
393
- def auto_restore
394
- restore if Ruber[:state].restore_cursor_position?
610
+ def view_received_focus view
611
+ @last_view = view
395
612
  nil
396
613
  end
614
+ slots 'view_received_focus(QWidget*)'
615
+
616
+ =begin rdoc
617
+ Method called whenever a view associated with the document is closed
618
+
619
+ If the closed view is the one which last got focus, its cursor position is saved
620
+ in the document's own project. Otherwise nothing is done.
621
+ @param [EditorView] view the view being closed
622
+ @return [nil]
623
+ =end
624
+ def view_closing view
625
+ if view == @last_view
626
+ save_settings
627
+ @last_view = nil
628
+ end
629
+ end
630
+ slots 'view_closing(QWidget*)'
397
631
 
398
632
  end
399
633
 
400
634
  =begin rdoc
401
635
  Extension for projects needed by the State plugin
402
636
 
403
- The scope of this extension is to save and restore the open documents associated
404
- with projects
637
+ The scope of this extension is to save and restore the state of the tabs open
638
+ when the project was last closed
405
639
  =end
406
640
  class ProjectExtension < Qt::Object
407
641
 
408
642
  include Extension
409
643
 
410
- slots :auto_restore
644
+ slots :auto_restore, :save_settings
411
645
 
412
646
  =begin rdoc
413
647
  @param [Ruber::Project] prj the project associated with the extension
@@ -416,55 +650,45 @@ with projects
416
650
  super
417
651
  @project = prj
418
652
  connect @project, SIGNAL(:activated), self, SLOT(:auto_restore)
653
+ connect @project, SIGNAL(:deactivated), self, SLOT(:save_settings)
419
654
  end
420
655
 
421
656
  =begin rdoc
422
- Opens all the files associated with the proejct which were opened last time the
423
- project's state was changed
657
+ Restore Ruber's state as it was when the project was last closed
424
658
 
425
- Any already open document is closed (after saving)
659
+ See {Plugin#restore_documents} for more information
426
660
 
427
661
  @return [nil]
428
662
  =end
429
663
 
430
664
  def restore
431
- files = @project[:state, :open_documents]
432
- Ruber[:docs].close_all
433
- return if files.empty?
434
- active_file = @project[:state, :active_document]
435
- active_file = files[-1] unless files.include? active_file
436
- mw = Ruber[:main_window]
437
- mw.without_activating do
438
- files.each{|f| mw.editor_for! f}
439
- end
440
- mw.display_document active_file
665
+ Ruber[:state].restore_documents @project
441
666
  nil
442
667
  end
443
668
 
444
669
  =begin rdoc
445
- Saves the list of open project files to the project
670
+ Saves Ruber's state to the project
671
+
672
+ The saved information is: the configuration of open tabs, the position of the cursor
673
+ in the views and the active view
446
674
 
447
675
  @return [nil]
448
676
  =end
449
677
  def save_settings
450
- files = Ruber[:docs].documents_with_file.map{|d| d.path}
451
- active = Ruber[:main_window].current_document
452
- active_path = (active.nil? or active.path.empty?) ? nil : active.path
453
- @project[:state, :open_documents] = files
454
- @project[:state, :active_document] = active_path
678
+ @project[:state, :open_documents] = Ruber[:state].documents_state
679
+ tabs_state = Ruber[:state].tabs_state
680
+ [:tabs, :cursor_positions, :active_view].each do |e|
681
+ @project[:state, e] = tabs_state[e]
682
+ end
455
683
  nil
456
684
  end
457
685
 
458
686
  private
459
687
 
460
688
  =begin rdoc
461
- Opens all the files associated with the proejct which were opened last time the
462
- project's state was changed when the project is opened.
463
-
464
- Any already open document is closed (after saving).
689
+ Restores the project's state when a new project is activated
465
690
 
466
- It does nothing if the user chose not restore open project files when opening a
467
- project.
691
+ It does nothing if the user choosed not to restore the projects's state.
468
692
  @return [nil]
469
693
  =end
470
694
  def auto_restore