Merge lp:~pitti/autopilot-gtk/enum-flags-properties into lp:autopilot-gtk

Proposed by Martin Pitt
Status: Merged
Approved by: Martin Pitt
Approved revision: 49
Merged at revision: 47
Proposed branch: lp:~pitti/autopilot-gtk/enum-flags-properties
Merge into: lp:autopilot-gtk
Diff against target: 174 lines (+86/-50)
2 files modified
lib/GtkNode.cpp (+71/-45)
tests/autopilot/tests/test_properties.py (+15/-5)
To merge this branch: bzr merge lp:~pitti/autopilot-gtk/enum-flags-properties
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+171713@code.launchpad.net

Commit message

Handle enum and flags properties. (LP: #1193342)

Description of the change

This branch enables enum and flag properties, such as GtkButton.relief or
GtkWidget.events. The first commit refactors the MatchProperty() method, to avoid having to introduce more duplicated code, and fix the GValue leak. After that, introducing support for new property types is a matter of only adding them to the convert_value() helper function, and then introspecting and matching will both support it.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/GtkNode.cpp'
--- lib/GtkNode.cpp 2013-06-26 10:16:59 +0000
+++ lib/GtkNode.cpp 2013-06-27 04:52:28 +0000
@@ -37,6 +37,36 @@
37 g_clear_object(&object_);37 g_clear_object(&object_);
38}38}
3939
40// we cannot represent GEnums, GFlags, etc. through D-BUS and autopilot's API,
41// so convert them to strings, ints, and other primitive types
42static void convert_value (GParamSpec *pspec, GValue *value)
43{
44 if (G_VALUE_HOLDS_ENUM(value)) {
45 GEnumValue *ev = g_enum_get_value(G_PARAM_SPEC_ENUM(pspec)->enum_class,
46 g_value_get_enum(value));
47 if (ev != NULL) {
48 //g_debug("attribute %s of type %s holds enum %s", g_param_spec_get_name(pspec),
49 // g_type_name(pspec->value_type), ev->value_name);
50 g_value_unset(value);
51 *value = G_VALUE_INIT;
52 g_value_init(value, G_TYPE_STRING);
53 g_value_set_string(value, ev->value_name);
54 }
55 }
56
57 // representing flags as strings is too unwieldy; let's just represent them
58 // as integer
59 if (G_VALUE_HOLDS_FLAGS(value)) {
60 guint flags = g_value_get_flags(value);
61 g_warning("attribute %s of type %s holds flags %x", g_param_spec_get_name(pspec),
62 g_type_name(pspec->value_type), flags);
63 g_value_unset(value);
64 *value = G_VALUE_INIT;
65 g_value_init(value, G_TYPE_UINT);
66 g_value_set_uint(value, flags);
67 }
68}
69
40GVariant* GtkNode::Introspect() const70GVariant* GtkNode::Introspect() const
41{71{
42 GVariantBuilder builder;72 GVariantBuilder builder;
@@ -59,6 +89,7 @@
59 GValue value = G_VALUE_INIT;89 GValue value = G_VALUE_INIT;
60 g_value_init(&value, param_spec->value_type);90 g_value_init(&value, param_spec->value_type);
61 g_object_get_property(object_, g_param_spec_get_name(param_spec), &value);91 g_object_get_property(object_, g_param_spec_get_name(param_spec), &value);
92 convert_value(param_spec, &value);
62 builder_wrapper.add(param_spec->name, &value);93 builder_wrapper.add(param_spec->name, &value);
63 g_value_unset(&value); //Free the memory accquired by the value object. Absence of this was causig the applications to crash.94 g_value_unset(&value); //Free the memory accquired by the value object. Absence of this was causig the applications to crash.
64 }95 }
@@ -181,55 +212,50 @@
181212
182bool GtkNode::MatchProperty(const std::string& name,213bool GtkNode::MatchProperty(const std::string& name,
183 const std::string& value) const {214 const std::string& value) const {
184215 if (name == "id")
185 // g_debug("attempting to match a node's property");
186
187 if (name == "id") {
188 return value == std::to_string(GetObjectId());216 return value == std::to_string(GetObjectId());
189217
190 } else {218 GObjectClass* klass = G_OBJECT_GET_CLASS(object_);
191 GObjectClass* klass = G_OBJECT_GET_CLASS(object_);219 GParamSpec* pspec = g_object_class_find_property(klass, name.c_str());
192 GParamSpec* pspec = g_object_class_find_property(klass, name.c_str());220 if (pspec == NULL)
193 if (pspec == NULL)221 return false;
222
223 // read the property into a GValue
224 g_debug("Matching property %s of type (%s).", g_param_spec_get_name(pspec),
225 g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
226
227 GValue dest_value = G_VALUE_INIT;
228 g_value_init(&dest_value, G_PARAM_SPEC_VALUE_TYPE(pspec));
229 g_object_get_property(object_, name.c_str(), &dest_value);
230 convert_value(pspec, &dest_value);
231 std::string dest_string;
232
233 // convert it to a string; always doing string comparison avoids having to do
234 // type comparison, conversion and error handling on value
235 switch (G_VALUE_TYPE(&dest_value)) {
236 case G_TYPE_INT:
237 dest_string = std::to_string(g_value_get_int(&dest_value));
238 break;
239 case G_TYPE_UINT:
240 dest_string = std::to_string(g_value_get_uint(&dest_value));
241 break;
242 case G_TYPE_DOUBLE:
243 dest_string = std::to_string(g_value_get_double(&dest_value));
244 break;
245 case G_TYPE_STRING: {
246 const gchar *str = g_value_get_string(&dest_value);
247 dest_string = (str != NULL) ? str : "";
248 break;
249 }
250 default:
251 g_debug("Unhandled type %s for matching property %s",
252 g_type_name(G_VALUE_TYPE(&dest_value)), g_param_spec_get_name(pspec));
253 g_value_unset(&dest_value);
194 return false;254 return false;
195
196 g_debug("Matching a property of type (%s).", g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
197
198 if (pspec && G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT) {
199 GValue dest_value = G_VALUE_INIT;
200 g_value_init(&dest_value, G_TYPE_INT);
201 g_object_get_property(object_, name.c_str(), &dest_value);
202
203 const gint cint = g_value_get_int(&dest_value);
204 g_value_unset(&dest_value);
205 std::stringstream out;
206 out << cint;
207 std::string dest_string(out.str());
208 return dest_string == value;
209
210 } else if (pspec && G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_DOUBLE) {
211 GValue dest_value = G_VALUE_INIT;
212 g_value_init(&dest_value, G_TYPE_DOUBLE);
213 g_object_get_property(object_, name.c_str(), &dest_value);
214
215 const gdouble cdbl = g_value_get_double(&dest_value);
216 g_value_unset(&dest_value);
217 std::stringstream out;
218 out << cdbl;
219 std::string dest_string(out.str());
220 return dest_string == value;
221
222 } else if (pspec && G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) {
223 gchar *strval = NULL;
224 g_object_get(object_, name.c_str(), &strval, NULL);
225 if (strval == NULL)
226 return false;
227
228 std::string dest_string(strval);
229 return dest_string == value;
230 }
231 return false;
232 }255 }
256
257 g_value_unset(&dest_value);
258 return dest_string == value;
233}259}
234260
235xpathselect::NodeList GtkNode::Children() const {261xpathselect::NodeList GtkNode::Children() const {
236262
=== modified file 'tests/autopilot/tests/test_properties.py'
--- tests/autopilot/tests/test_properties.py 2013-06-26 07:21:14 +0000
+++ tests/autopilot/tests/test_properties.py 2013-06-27 04:52:28 +0000
@@ -90,10 +90,20 @@
90 self.assertEqual(entry_name.text_length, 0)90 self.assertEqual(entry_name.text_length, 0)
91 self.assertEqual(entry_color.text_length, 0)91 self.assertEqual(entry_color.text_length, 0)
9292
93 #https://launchpad.net/bugs/119334293 def test_enum_flags_properties(self):
94 @unittest.expectedFailure94 '''enum and flags properties'''
95 def test_enum_properties(self):
96 '''enum properties'''
9795
96 # enum
98 btn_greet = self.app.select_single('GtkButton', label='Greet')97 btn_greet = self.app.select_single('GtkButton', label='Greet')
99 self.assertTrue(hasattr(btn_greet, 'relief'))98 self.assertEqual(btn_greet.relief, 'GTK_RELIEF_NORMAL')
99 self.assertEqual(btn_greet.resize_mode, 'GTK_RESIZE_PARENT')
100
101 res = self.app.select_many(relief='GTK_RELIEF_NORMAL', visible=True)
102 self.assertGreaterEqual(len(res), 3)
103 self.assertIn('Button', str(type(res[0])))
104
105 # flags
106 self.assertGreaterEqual(btn_greet.events, 0)
107
108 res = self.app.select_many('GtkButton', events=btn_greet.events)
109 self.assertGreater(len(res), 0)

Subscribers

People subscribed via source and target branches

to all changes: