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.
Files changed (166) hide show
  1. data/COPYING +339 -0
  2. data/INSTALL +137 -0
  3. data/LICENSE +8 -0
  4. data/bin/ruber +65 -0
  5. data/data/share/apps/ruber/core_components.yaml +31 -0
  6. data/data/share/apps/ruber/ruberui.rc +109 -0
  7. data/data/share/icons/ruber.png +0 -0
  8. data/data/share/pixmaps/ruby.png +0 -0
  9. data/icons/ruber-16.png +0 -0
  10. data/icons/ruber-32.png +0 -0
  11. data/icons/ruber-48.png +0 -0
  12. data/icons/ruber-8.png +0 -0
  13. data/lib/ruber/application/application.rb +288 -0
  14. data/lib/ruber/application/plugin.yaml +11 -0
  15. data/lib/ruber/component_manager.rb +899 -0
  16. data/lib/ruber/config/config.rb +82 -0
  17. data/lib/ruber/config/plugin.yaml +3 -0
  18. data/lib/ruber/document_project.rb +209 -0
  19. data/lib/ruber/documents/document_list.rb +416 -0
  20. data/lib/ruber/documents/plugin.yaml +4 -0
  21. data/lib/ruber/editor/document.rb +506 -0
  22. data/lib/ruber/editor/editor_view.rb +167 -0
  23. data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
  24. data/lib/ruber/exception_widgets.rb +245 -0
  25. data/lib/ruber/external_program_plugin.rb +397 -0
  26. data/lib/ruber/filtered_output_widget.rb +342 -0
  27. data/lib/ruber/gui_states_handler.rb +231 -0
  28. data/lib/ruber/kde_config_option_backend.rb +167 -0
  29. data/lib/ruber/kde_sugar.rb +249 -0
  30. data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
  31. data/lib/ruber/main_window/main_window.rb +524 -0
  32. data/lib/ruber/main_window/main_window_actions.rb +537 -0
  33. data/lib/ruber/main_window/main_window_internal.rb +239 -0
  34. data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
  35. data/lib/ruber/main_window/output_color_widget.rb +35 -0
  36. data/lib/ruber/main_window/plugin.yaml +58 -0
  37. data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
  38. data/lib/ruber/main_window/status_bar.rb +156 -0
  39. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
  40. data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
  41. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
  42. data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
  43. data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
  44. data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
  45. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
  46. data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
  47. data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
  48. data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
  49. data/lib/ruber/main_window/workspace.rb +442 -0
  50. data/lib/ruber/output_widget.rb +1093 -0
  51. data/lib/ruber/plugin.rb +264 -0
  52. data/lib/ruber/plugin_like.rb +589 -0
  53. data/lib/ruber/plugin_specification.rb +106 -0
  54. data/lib/ruber/plugin_specification_reader.rb +451 -0
  55. data/lib/ruber/project.rb +493 -0
  56. data/lib/ruber/project_backend.rb +105 -0
  57. data/lib/ruber/projects/plugin.yaml +11 -0
  58. data/lib/ruber/projects/project_files_list.rb +314 -0
  59. data/lib/ruber/projects/project_files_widget.rb +301 -0
  60. data/lib/ruber/projects/project_list.rb +314 -0
  61. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
  62. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
  63. data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
  64. data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
  65. data/lib/ruber/qt_sugar.rb +673 -0
  66. data/lib/ruber/settings_container.rb +515 -0
  67. data/lib/ruber/settings_dialog.rb +244 -0
  68. data/lib/ruber/settings_dialog_manager.rb +503 -0
  69. data/lib/ruber/utils.rb +414 -0
  70. data/lib/ruber/yaml_option_backend.rb +159 -0
  71. data/outsider_files +15 -0
  72. data/plugins/autosave/autosave.rb +404 -0
  73. data/plugins/autosave/plugin.yaml +16 -0
  74. data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
  75. data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
  76. data/plugins/command/command.png +0 -0
  77. data/plugins/command/command.rb +74 -0
  78. data/plugins/command/plugin.yaml +11 -0
  79. data/plugins/find_in_files/find_in_files.rb +337 -0
  80. data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
  81. data/plugins/find_in_files/find_in_files_ui.rc +11 -0
  82. data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
  83. data/plugins/find_in_files/plugin.yaml +23 -0
  84. data/plugins/find_in_files/ui/config_widget.rb +58 -0
  85. data/plugins/find_in_files/ui/config_widget.ui +41 -0
  86. data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
  87. data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
  88. data/plugins/project_browser/plugin.yaml +10 -0
  89. data/plugins/project_browser/project_browser.rb +245 -0
  90. data/plugins/rake/plugin.yaml +39 -0
  91. data/plugins/rake/rake.png +0 -0
  92. data/plugins/rake/rake.rb +567 -0
  93. data/plugins/rake/rake_extension.rb +153 -0
  94. data/plugins/rake/rake_widgets.rb +615 -0
  95. data/plugins/rake/rakeui.rc +27 -0
  96. data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
  97. data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
  98. data/plugins/rake/ui/choose_task_widget.rb +77 -0
  99. data/plugins/rake/ui/choose_task_widget.ui +72 -0
  100. data/plugins/rake/ui/config_widget.rb +127 -0
  101. data/plugins/rake/ui/config_widget.ui +123 -0
  102. data/plugins/rake/ui/project_widget.rb +217 -0
  103. data/plugins/rake/ui/project_widget.ui +246 -0
  104. data/plugins/rspec/plugin.yaml +30 -0
  105. data/plugins/rspec/rspec.png +0 -0
  106. data/plugins/rspec/rspec.rb +945 -0
  107. data/plugins/rspec/rspec.svg +90 -0
  108. data/plugins/rspec/rspecui.rc +20 -0
  109. data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
  110. data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
  111. data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
  112. data/plugins/ruby_development/plugin.yaml +27 -0
  113. data/plugins/ruby_development/ruby_development.png +0 -0
  114. data/plugins/ruby_development/ruby_development.rb +453 -0
  115. data/plugins/ruby_development/ruby_developmentui.rc +19 -0
  116. data/plugins/ruby_development/ui/project_widget.rb +112 -0
  117. data/plugins/ruby_development/ui/project_widget.ui +108 -0
  118. data/plugins/ruby_runner/config_widget.rb +116 -0
  119. data/plugins/ruby_runner/plugin.yaml +26 -0
  120. data/plugins/ruby_runner/project_widget.rb +62 -0
  121. data/plugins/ruby_runner/ruby.png +0 -0
  122. data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
  123. data/plugins/ruby_runner/ruby_runner.rb +411 -0
  124. data/plugins/ruby_runner/ui/config_widget.rb +92 -0
  125. data/plugins/ruby_runner/ui/config_widget.ui +91 -0
  126. data/plugins/ruby_runner/ui/project_widget.rb +60 -0
  127. data/plugins/ruby_runner/ui/project_widget.ui +48 -0
  128. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
  129. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
  130. data/plugins/state/plugin.yaml +28 -0
  131. data/plugins/state/state.rb +520 -0
  132. data/plugins/state/ui/config_widget.rb +92 -0
  133. data/plugins/state/ui/config_widget.ui +89 -0
  134. data/plugins/syntax_checker/plugin.yaml +18 -0
  135. data/plugins/syntax_checker/syntax_checker.rb +662 -0
  136. data/ruber.desktop +10 -0
  137. data/spec/annotation_model_spec.rb +174 -0
  138. data/spec/common.rb +119 -0
  139. data/spec/component_manager_spec.rb +1259 -0
  140. data/spec/document_list_spec.rb +626 -0
  141. data/spec/document_project_spec.rb +373 -0
  142. data/spec/document_spec.rb +779 -0
  143. data/spec/editor_view_spec.rb +167 -0
  144. data/spec/external_program_plugin_spec.rb +676 -0
  145. data/spec/filtered_output_widget_spec.rb +642 -0
  146. data/spec/gui_states_handler_spec.rb +304 -0
  147. data/spec/kde_config_option_backend_spec.rb +214 -0
  148. data/spec/kde_sugar_spec.rb +101 -0
  149. data/spec/ktexteditor_wrapper_spec.rb +305 -0
  150. data/spec/output_widget_spec.rb +1703 -0
  151. data/spec/plugin_spec.rb +1393 -0
  152. data/spec/plugin_specification_reader_spec.rb +1765 -0
  153. data/spec/plugin_specification_spec.rb +401 -0
  154. data/spec/project_backend_spec.rb +172 -0
  155. data/spec/project_files_list_spec.rb +401 -0
  156. data/spec/project_list_spec.rb +511 -0
  157. data/spec/project_spec.rb +990 -0
  158. data/spec/qt_sugar_spec.rb +328 -0
  159. data/spec/settings_container_spec.rb +617 -0
  160. data/spec/settings_dialog_manager_spec.rb +773 -0
  161. data/spec/settings_dialog_spec.rb +419 -0
  162. data/spec/state_spec.rb +991 -0
  163. data/spec/utils_spec.rb +406 -0
  164. data/spec/workspace_spec.rb +869 -0
  165. data/spec/yaml_option_backend_spec.rb +246 -0
  166. metadata +284 -0
@@ -0,0 +1,167 @@
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 'facets/boolean'
23
+
24
+ require 'ruber/editor/ktexteditor_wrapper'
25
+
26
+ module Ruber
27
+
28
+ class EditorView < Qt::Widget
29
+
30
+ include KTextEditorWrapper
31
+
32
+ signal_data = {
33
+ 'information_message' => ['KTextEditor::View*, QString', [1, nil]],
34
+ 'context_menu_about_to_show' => ['KTextEditor::View*, QMenu*', [1, nil]],
35
+ 'focus_in' => ['KTextEditor::View*', [nil]],
36
+ 'focus_out' => ['KTextEditor::View*', [nil]],
37
+ # 'selection_changed' => ['KTextEditor::View*', [nil]],
38
+ 'vertical_scroll_position_changed' => ['KTextEditor::View*, KTextEditor::Cursor', [1, nil]],
39
+ 'horizontal_scroll_position_changed' => ['KTextEditor::View*', [nil]],
40
+ 'text_inserted' => ['KTextEditor::View*, KTextEditor::Cursor, QString', [1, 2, nil]],
41
+ }
42
+
43
+ @signal_table = KTextEditorWrapper.prepare_wrapper_connections self, signal_data
44
+
45
+ signals 'closing()', 'cursor_position_changed(KTextEditor::Cursor, QWidget*)',
46
+ 'view_mode_changed(QString, QWidget*)', 'edit_mode_changed(KTextEditor::View::EditMode, QWidget*)',
47
+ 'selection_mode_changed(bool, QWidget*)', 'mouse_position_changed(KTextEditor::Cursor, QWidget*)',
48
+ 'selection_changed(QWidget*)'
49
+
50
+ slots 'slot_selection_changed(KTextEditor::View*)'
51
+
52
+ # @view.connect(SIGNAL('selectionChanged(KTextEditor::View*)')) do |v|
53
+ # changed = @view.block_selection ^ @block_selection
54
+ # if changed
55
+ # @block_selection = @view.block_selection
56
+ # emit selection_mode_changed @block_selection, self
57
+ # end
58
+ # end
59
+
60
+
61
+
62
+ # signals 'closing()', 'information_message(QString, QObject*)',
63
+ # 'cursor_position_changed(KTextEditor::Cursor, QObject*)',
64
+ # 'view_mode_changed(QString, QObject*)', 'edit_mode_changed(KTextEditor::View::EditMode, QObject*)',
65
+ # 'selection_mode_changed(bool, QObject*)', 'context_menu_about_to_show(QMenu*, QObject*)',
66
+ # 'focus_in(QObject*)', 'focus_out(QObject*)', 'horizontal_scroll_position_changed(QObject*)',
67
+ # 'mouse_position_changed(KTextEditor::Cursor, QObject*)', 'selection_changed(QObject*)',
68
+ # 'text_inserted(KTextEditor::Cursor, QString, QObject*)', 'vertical_scroll_position_changed(KTextEditor::Cursor, QObject*)'
69
+
70
+ attr_reader :doc
71
+ alias_method :document, :doc
72
+ def initialize doc, internal, parent = nil
73
+ super parent
74
+ @block_selection = false
75
+ @doc = doc
76
+ @view = internal
77
+ @view.parent = self
78
+ initialize_wrapper @view, self.class.instance_variable_get(:@signal_table)
79
+ self.focus_proxy = @view
80
+ self.layout = Qt::VBoxLayout.new self
81
+ layout.set_contents_margins 0,0,0,0
82
+ layout.spacing = 0
83
+ layout.add_widget @view
84
+
85
+ connect @view, SIGNAL('selectionChanged(KTextEditor::View*)'), self, SLOT('slot_selection_changed(KTextEditor::View*)')
86
+
87
+ @view.connect(SIGNAL('cursorPositionChanged(KTextEditor::View*, KTextEditor::Cursor)'))do |v, c|
88
+ emit cursor_position_changed( @view.cursor_position_virtual, self)
89
+ end
90
+ @view.connect(SIGNAL('mousePositionChanged(KTextEditor::View*, KTextEditor::Cursor)')) do |v, c|
91
+ emit mouse_position_changed( @view.cursor_position_virtual, self)
92
+ end
93
+ @view.connect(SIGNAL('viewModeChanged(KTextEditor::View*)')) do |v|
94
+ emit view_mode_changed( view_mode, self)
95
+ end
96
+ @view.connect(SIGNAL('viewEditModeChanged(KTextEditor::View*, KTextEditor::View::EditMode)')) do |v, m|
97
+ emit edit_mode_changed( m, self)
98
+ end
99
+
100
+ am = @doc.interface('annotation_interface').annotation_model
101
+ am.connect(SIGNAL('annotations_changed()')) do
102
+ show = Ruber[:config][:general, :auto_annotations] && am.has_annotations?
103
+ set_annotation_border_visible(show) rescue NoMethodError
104
+ end
105
+
106
+ @view.context_menu = @view.default_context_menu(Qt::Menu.new(@view))
107
+
108
+ end
109
+
110
+ def go_to row, col
111
+ @view.cursor_position = KTextEditor::Cursor.new(row, col)
112
+ end
113
+
114
+ def show_annotation_border
115
+ set_annotation_border_visible true
116
+ end
117
+
118
+ def hide_annotation_border
119
+ set_annotation_border_visible false
120
+ end
121
+
122
+ def block_selection?
123
+ @view.block_selection.to_bool
124
+ end
125
+
126
+ def close
127
+ emit closing
128
+ super
129
+ end
130
+
131
+ def set_annotation_border_visible vis
132
+ @view.qobject_cast(KTextEditor::AnnotationViewInterface).set_annotation_border_visible vis
133
+ end
134
+
135
+ =begin rdoc
136
+ Executes the action with name the view's action
137
+ collection. This is made by having the action emit the <tt>triggered()</tt> or
138
+ <tt>toggled(bool)</tt> signal (depending on whether it's a standard action or a
139
+ <tt>KDE::ToggleAction</tt>). In the second case, _arg_ is the argument passed to
140
+ the signal.
141
+
142
+ Returns *true* if an action with name _name_ was found and *false* otherwise.
143
+ =end
144
+ def execute_action name, arg = nil
145
+ a = action_collection.action(name)
146
+ case a
147
+ when KDE::ToggleAction then a.instance_eval{emit toggled(arg)}
148
+ when nil then return false
149
+ else a.instance_eval{emit triggered}
150
+ end
151
+ true
152
+ end
153
+
154
+ private
155
+
156
+ def slot_selection_changed v
157
+ emit selection_changed(self)
158
+ changed = @view.block_selection ^ @block_selection
159
+ if changed
160
+ @block_selection = @view.block_selection
161
+ emit selection_mode_changed(@block_selection, self)
162
+ end
163
+ end
164
+
165
+ end
166
+
167
+ end
@@ -0,0 +1,202 @@
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 'facets/string/camelcase'
22
+
23
+ module Ruber
24
+
25
+ =begin rdoc
26
+ Module which abstracts some common functionality of Document and EditorView due
27
+ to the fact that both are mostly simply wrappers around two +KTextEditor+ classes.
28
+
29
+ Throught this documentation, the KTextEditor::Document or KTextEditor::View corresponding
30
+ to the object will be referred to as the <i>wrapped object</i>.
31
+
32
+ In particular, this class:
33
+ * provide a way to access methods provided by the different interfaces implemented
34
+ by the wrapped object without directly accessing it (using InterfaceProxy)
35
+ * redirect to the wrapped object any method call the object itself doesn't respond
36
+ to
37
+ * provide a (private) method to access the wrapped object
38
+ * provide some automatization in the process having the object emit an appropriate
39
+ signal when the wrapped object emits a signal.
40
+ =end
41
+ module KTextEditorWrapper
42
+
43
+ =begin rdoc
44
+ Helper class which, given a Qt::Object implementing different interfaces, allows
45
+ to access method provided by one interface without exposing the object itself.
46
+ =end
47
+ class InterfaceProxy
48
+
49
+ =begin rdoc
50
+ Creates a new InterfaceProxy. _obj_ is the <tt>Qt::Object</tt> to cast to the
51
+ appropriate interface
52
+ =end
53
+ def initialize obj
54
+ @obj = obj
55
+ @interface = nil
56
+ end
57
+
58
+ =begin rdoc
59
+ Sets the interface to which the object is going to be cast. _iface_ can be either
60
+ the name of an interface, as symbol or string, both in camelcase or snakecase
61
+ (withouth the +KTextEditor+ namespace) or the class itself. After a call to this
62
+ method (and until the next one) <tt>method_missing</tt> will redirect all unknown
63
+ method calls to this interface.
64
+ =end
65
+ def interface= iface
66
+ cls = if iface.is_a? Class then iface
67
+ else
68
+ name = iface.to_s.split('_').map(&:capitalize).join ''
69
+ KTextEditor.const_get(name)
70
+ end
71
+ @interface = @obj.qobject_cast cls
72
+ end
73
+
74
+ =begin rdoc
75
+ Passes the method call to the object cast to the current interface. If the argument
76
+ list contains instances of classes which mix-in KTextEditorWrapper, they're replaced
77
+ with the object they wrap before being passed to the interface.
78
+ =end
79
+ def method_missing name, *args, &blk
80
+ args.map!{|a| a.is_a?(KTextEditorWrapper) ? a.send(:internal) : a}
81
+ @interface.send name, *args, &blk
82
+ end
83
+
84
+ end
85
+
86
+ =begin rdoc
87
+ Makes easier having the object emit a signal in corrispondence with
88
+ signals emitted by the wrapped object. In particular, this method does the following
89
+ (for each signal given in the arguments):
90
+ * creates a signal for the object based on the name of the signal in the wrapped
91
+ object
92
+ * creates a slot for the object with a name obtained from the name of the signal, which takes
93
+ the same arguments as the signal in the wrapped object and emits the associated
94
+ signal of the object. The arguments of the emitted signal are taken from those
95
+ passed to the slot, but they can be reordered. Also, *self* can be specified
96
+ * returns a hash suitable to be passed as second argument to <tt>initialize_wrapper</tt>.
97
+ Usually, this method is called when the class is created and the returned hash
98
+ is stored in a class instance variable. The class's +initialize+ method then passes
99
+ it as second argument to <tt>initialize_wrapper</tt>.
100
+
101
+ _cls_ is the class for which signals and slots will be defined. _data_ is a hash
102
+ containing the information for the signal and slot to create.
103
+ * its keys are the names of the signals converted to snakecase. This name will be
104
+ converted to camelcase to obtain the name of the signal of the wrapped object,
105
+ while will be used as is for the signal of the object.
106
+ * its values are arrays. The first element is the signature of the signal of the
107
+ wrapped object. The second element is an array of integers and *nil*s. An integer
108
+ _i_ in the position _n_ of the array means that the _n_th argument of the new
109
+ signal will be the _i_th argument of the signal of the wrapped object (both
110
+ indexes start from 0). If the array contains *nil* in position _n_, the _n_th
111
+ argument of the new signal will be *self* (in the signature of the new signal,
112
+ this will mean <tt>QWidget*</tt> if _cls_ derives from <tt>Qt::Widget</tt> and
113
+ <tt>QObject*</tt> otherwise).
114
+ =end
115
+ def self.prepare_wrapper_connections cls, data
116
+ res = {}
117
+ data.each_pair do |name, d|
118
+ old_args = d[0].split(/,\s*/)
119
+ new_args = d[1].map do |i|
120
+ if i then old_args[i]
121
+ elsif cls.ancestors.include?(Qt::Widget) then 'QWidget*'
122
+ else 'QObject*'
123
+ end
124
+ end
125
+ new_args = new_args.join ', '
126
+ new_signal = "#{name}(#{new_args})"
127
+ old_signal = "#{name.camelcase :lower}(#{d[0]})"
128
+ slot_name = "__emit_#{name}_signal(#{d[0]})"
129
+ cls.send :signals, new_signal
130
+ cls.send :slots, slot_name
131
+ res[old_signal] = slot_name
132
+ method_def = <<-EOS
133
+ def __emit_#{name}_signal(#{old_args.size.times.map{|i| "a#{i}"}.join ', '})
134
+ emit #{name}(#{d[1].map{|i| i ? "a#{i}" : 'self'}.join ', '})
135
+ end
136
+ EOS
137
+ cls.class_eval method_def
138
+ end
139
+ res
140
+ end
141
+
142
+ =begin rdoc
143
+ Returns an InterfaceProxy set to the interface _name_. See <tt>InterfaceProxy#interface=</tt>
144
+ for the possible values for _name_. It is meant to be used this way (supposing
145
+ _doc_ is an object which wraps <tt>KTextEditor::Document</tt>)
146
+ doc.interface(:modification_interface).modified_on_disk_warning = true
147
+ =end
148
+ def interface name
149
+ @_interface.interface = name
150
+ @_interface
151
+ end
152
+
153
+ =begin rdoc
154
+ Forwards the method call to the wrapped object
155
+ =end
156
+ def method_missing name, *args, &blk
157
+ begin super
158
+ rescue NoMethodError, NameError, NotImplementedError
159
+ @_wrapped.send name, *args, &blk
160
+ end
161
+ end
162
+
163
+ private
164
+
165
+ =begin rdoc
166
+ Method which needs to be called before using any of the functionality provided by
167
+ the module (usually, it's called from +initialize+). _obj_ is the wrapped object,
168
+ while _signals_ is a hash as described in <tt>connect_wrapped_signals</tt>.
169
+
170
+ It creates an InterfaceProxy for the wrapped object and calls <tt>connect_wrapped_signals</tt>
171
+ passing _signals_ as argument.
172
+ =end
173
+ def initialize_wrapper obj, signals
174
+ @_interface = InterfaceProxy.new obj
175
+ @_wrapped = obj
176
+ connect_wrapped_signals signals
177
+ end
178
+
179
+ =begin rdoc
180
+ Returns the wrapped object (this method is mainly for internal use)
181
+ =end
182
+ def internal
183
+ @_wrapped
184
+ end
185
+
186
+ =begin rdoc
187
+ Makes a connections between a series of signals and of slots. _signals_ is a hash
188
+ whose keys are the names of the signals and whose entries are the slots each signal
189
+ should be connected to (only one slot can be connected to each signal). You can't
190
+ connect a signal to another signal with this method.
191
+
192
+ This method is mainly meant to be used in conjunction with <tt>prepare_wrapper_connections</tt>.
193
+ =end
194
+ def connect_wrapped_signals signals
195
+ signals.each_pair do |k, v|
196
+ connect @_wrapped, SIGNAL(k), self, SLOT(v)
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+ end
@@ -0,0 +1,245 @@
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
+ module Ruber
22
+
23
+ =begin rdoc
24
+ Dialog which displays the content of an exception (that is, the message and the
25
+ backtrace) to the user.
26
+
27
+ The backtrace is shown as an extension widget, only if the user clicks the 'Backtrace'
28
+ button.
29
+ =end
30
+ class ExceptionDialog < KDE::Dialog
31
+
32
+ =begin rdoc
33
+ Subclass of @KDE::TextEdit@ specialized in displaying the backtrace of an
34
+ exception.
35
+
36
+ The differences with a standard @KDE::TextEdit@ are:
37
+ * automatically uses a fixed width font
38
+ * doesn't use word wrapping
39
+ * is always read-only
40
+ * its {#size_hint} method computes (or at least tries to compute) width
41
+ and height so that each line of the backtrace fits on a single line.
42
+ * automatically extracts the message and the backtrace from the exception
43
+ =end
44
+ class ExceptionBacktraceWidget < KDE::TextEdit
45
+
46
+ =begin rdoc
47
+ @param [Exception] ex the exception whose backtrace should be displayed
48
+ @param [Qt::Widget, nil] parent the parent widget
49
+ =end
50
+ def initialize ex, parent = nil
51
+ super parent
52
+ self.line_wrap_mode = NoWrap
53
+ self.read_only = true
54
+ #Replace < and > with the corresponding HTML entities in the message
55
+ msg = ex.message.gsub(/[<>]/){|s| s == '<' ? '&lt;' : '&gt;'}
56
+ #Replace < and > with the corresponding HTML entities in the backtrace
57
+ backtrace = ex.backtrace.map{|l| l.gsub(/[<>]/){|s| s == '<' ? '&lt;' : '&gt;'}}
58
+ text = "<tt>#{msg}<br/>#{backtrace.join '<br/>'}</tt>"
59
+ self.html = text
60
+ end
61
+
62
+ =begin rdoc
63
+ Override of @KDE::TextEdit#sizeHint@
64
+
65
+ The width is computed as the size (using the fixed width font) of the longest line,
66
+ while the height is computed as the height of a single line multiplied by the
67
+ number of lines.
68
+
69
+ Both width and height are computed using @Qt::FontMetrics@
70
+
71
+ @return [Qt::Size] the suggested size of the widget
72
+ =end
73
+ def sizeHint
74
+ font = Qt::TextCursor.new(document).char_format.font
75
+ fm = Qt::FontMetrics.new font
76
+ lines = to_plain_text.split_lines
77
+ longest = lines.sort_by{|l| l.size}[-1]
78
+ Qt::Size.new fm.width(longest), fm.height * lines.size
79
+ end
80
+
81
+ end
82
+
83
+ =begin rdoc
84
+ @param [Exception] ex the exception the dialog is for
85
+ @param [Qt::Widget,nil] the parent widget
86
+ @param [Boolean] out whether to display the exception to standard error when the
87
+ dialog is executed
88
+ @param [String] msg the text to display in the dialog before the exception message.
89
+ Note that this will always be treated as rich text. Unless empty,
90
+ a line break will always be inserted after it
91
+ =end
92
+ def initialize ex, parent = nil, out = true, msg = 'Ruber raised the following exception:'
93
+ super parent
94
+ self.caption = KDE::Dialog.make_standard_caption "Exception"
95
+ self.buttons = Ok | Details
96
+ set_button_text Ok, 'Quit Ruber'
97
+ set_button_text Details, 'Backtrace'
98
+ error = ex.message.gsub(/\n/, '<br/>')
99
+ error.gsub!(/[<>]/){|s| s == '<' ? '&lt;' : '&gt;'}
100
+ text = (!msg.empty? ? msg + '<br/>' : '') + '<tt>' + error + '</tt>'
101
+ self.main_widget = Qt::Label.new text, self
102
+ @backtrace_widget = ExceptionBacktraceWidget.new ex, self
103
+ self.details_widget = @backtrace_widget
104
+ @out = out
105
+ end
106
+
107
+ =begin rdoc
108
+ Override of @KDE::Dialog#sizeHint@
109
+
110
+ It takes into account the size of the details widget, if shown.
111
+
112
+ @return [Qt::Size] the suggested size for the dialog
113
+ =end
114
+ def sizeHint
115
+ orig = super
116
+ if defined?(@backtrace_widget) and @backtrace_widget.visible?
117
+ main_width = main_widget.sizeHint.width
118
+ diff = orig.width - main_width
119
+ det_width = @backtrace_widget.sizeHint.width
120
+ w = [det_width, main_width].max + diff
121
+ Qt::Size.new(w, orig.height)
122
+ else orig
123
+ end
124
+ end
125
+
126
+ =begin rdoc
127
+ Override of @KDE::Dialog#exec@
128
+
129
+ If the _out_ parameter passed to the constructor was *true*, displays the exception
130
+ message and backtrace on standard error before displaying the dialog
131
+ @return [Integer] the exit code of the dialog
132
+ =end
133
+ def exec
134
+ if @out
135
+ $stderr.puts @backtrace_widget.to_plain_text
136
+ end
137
+ super
138
+ end
139
+
140
+ =begin rdoc
141
+ Override of @KDE::Dialog#show@
142
+
143
+ If the _out_ parameter passed to the constructor was *true*, displays the exception
144
+ message and backtrace on standard error before displaying the dialog
145
+ @return [nil]
146
+ =end
147
+ def show
148
+ if @out
149
+ $stderr.puts @backtrace_widget.to_plain_text
150
+ end
151
+ super
152
+ end
153
+
154
+ end
155
+
156
+ =begin rdoc
157
+ ExceptionDialog specialized to display failures when loading plugins and components.
158
+
159
+ It differs from {ExceptionDialog} in the following aspects:
160
+ * it provides different buttons
161
+ * it provides a check box to decide whether or not to warn of subsequent errors while
162
+ loading plugins
163
+ * its #{exec} method provides values suitable to be returned from a block passed to
164
+ {ComponentManager#load_plugins}
165
+ * it provides an appropriate text
166
+
167
+ The buttons on the dialog are:
168
+
169
+ - Go on::= ignore the failure and attempt to load the remaining plugins, hoping
170
+ everything goes well
171
+ - Quit::= immediately quit Ruber
172
+ - Skip remaining::= ignore the failure, but don't attempt to load any other plugin
173
+
174
+ If the exception was raised while loading a core component, the dialog will behave
175
+ exactly as an {ExceptionDialog} (since you can't start Ruber without one of the core
176
+ components, the other buttons and the checkbox would be useless).
177
+ =end
178
+ class ComponentLoadingErrorDialog < ExceptionDialog
179
+
180
+ =begin rdoc
181
+
182
+ @param [Symbol,String] plugin the name of the component which caused the exception
183
+ @param [Exception] ex the exception which was raised
184
+ @param [Qt::Widget,nil] the parent widget
185
+ @param [Boolean] core whether the component which caused the failure is a core
186
+ component or a plugin
187
+ =end
188
+ def initialize plugin, ex, parent = nil, core = false
189
+ msg = "An error occurred while loading the #{core ? 'component' : 'plugin' } #{plugin}. The error was:"
190
+ super ex, parent, true, msg
191
+ unless core
192
+ label = main_widget
193
+ w = Qt::Widget.new self
194
+ self.main_widget = w
195
+ w.layout = Qt::VBoxLayout.new w
196
+ label.parent = w
197
+ w.layout.add_widget label
198
+ @silent = Qt::CheckBox.new "&Don't report other errors", w
199
+ w.layout.add_widget @silent
200
+ self.buttons = Yes|No|Cancel|Details
201
+ self.set_button_text KDE::Dialog::Yes, "&Go on"
202
+ self.set_button_text KDE::Dialog::No, "&Quit Ruber"
203
+ self.set_button_text KDE::Dialog::Cancel, "&Skip remaining plugins"
204
+ self.escape_button = KDE::Dialog::No
205
+ end
206
+ end
207
+
208
+ =begin rdoc
209
+ Whether or not the user checked to ignore subsequent errors
210
+
211
+ @return [Boolean,nil] *true* if the user checked the "Don't report other errors" check
212
+ box and *false* otherwise. If the dialog is shown for a core
213
+ component, this method always returns *nil*
214
+ =end
215
+ def silently?
216
+ @silent.checked? rescue nil
217
+ end
218
+
219
+ =begin rdoc
220
+ Override of {ExceptionDialog#exec}
221
+
222
+ It returns a different value according to the button pressed by the user and to
223
+ whether he checked the "Don't report other errors" checkbox. The returned values
224
+ are suitable for use by a block passed to {ComponentManager#load_plugins}.
225
+
226
+ @return [Boolean,Symbol]
227
+
228
+ - *true*:= if the user pressed the "Go on" button without checking the checkbox
229
+ - @:silent@:= if the user pressed the "Go on" button and checked the checkbox
230
+ - *false*:= if the user pressed the "Quit" button
231
+ - @:skip@:= if the user pressed the "Skip" button
232
+ =end
233
+ def exec
234
+ res = super
235
+ case res
236
+ when KDE::Dialog::Yes then dlg.silently? ? :silent : true
237
+ when KDE::Dialog::No then false
238
+ when KDE::Dialog::Cancel then :skip
239
+ else res
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ end