ruber 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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