Merge lp:~stolowski/libunity/libunity.debug-tool-previews into lp:libunity
- libunity.debug-tool-previews
- Merge into trunk
Proposed by
Paweł Stołowski
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 167 |
Merged at revision: | 162 |
Proposed branch: | lp:~stolowski/libunity/libunity.debug-tool-previews |
Merge into: | lp:libunity |
Diff against target: |
2161 lines (+1490/-231) 10 files modified
protocol/Makefile.am (+3/-8) src/Makefile.am (+7/-10) test/vala/Makefile.am (+3/-3) test/vala/Makefile.integration_tests (+8/-11) tools/Makefile.am (+19/-8) tools/music-track-model-renderer.vala (+95/-0) tools/preview-renderer.vala (+457/-0) tools/unity-tool-dbus-util.vala (+100/-100) tools/unity-tool-ui.vala (+519/-85) tools/unity-tool.ui (+279/-6) |
To merge this branch: | bzr merge lp:~stolowski/libunity/libunity.debug-tool-previews |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Approve | ||
Review via email: mp+119549@code.launchpad.net |
Commit message
Preview support for libunity-tool and build fixes.
Description of the change
Preview support for libunity-tool.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'protocol/Makefile.am' |
2 | --- protocol/Makefile.am 2012-07-27 09:32:20 +0000 |
3 | +++ protocol/Makefile.am 2012-08-14 14:17:21 +0000 |
4 | @@ -12,12 +12,10 @@ |
5 | # Headers, vapi, and gir |
6 | ## |
7 | unityincludedir = $(includedir)/unity/unity |
8 | -unityinclude_HEADERS = \ |
9 | - unity-protocol.h \ |
10 | - $(NULL) |
11 | +nodist_unityinclude_HEADERS = unity-protocol.h |
12 | |
13 | unityvapidir = $(datadir)/vala/vapi |
14 | -unityvapi_DATA = \ |
15 | +nodist_unityvapi_DATA = \ |
16 | unity-protocol.vapi \ |
17 | $(NULL) |
18 | |
19 | @@ -55,7 +53,7 @@ |
20 | $(LIBUNITY_PACKAGES) \ |
21 | $(MAINTAINER_VALAFLAGS) |
22 | |
23 | -libunity_protocol_private_la_SOURCES = \ |
24 | +nodist_libunity_protocol_private_la_SOURCES = \ |
25 | $(libunity_protocol_private_la_VALASOURCES:.vala=.c) \ |
26 | $(NULL) |
27 | |
28 | @@ -88,6 +86,3 @@ |
29 | $(libunity_protocol_private_la_VALASOURCES:.vala=.c) \ |
30 | $(NULL) |
31 | |
32 | -dist-hook: |
33 | - rm -f $(addprefix $(distdir)/,$(libunity_protocol_private_la_VALASOURCES:.vala=.c)) |
34 | - |
35 | |
36 | === modified file 'src/Makefile.am' |
37 | --- src/Makefile.am 2012-07-27 09:32:20 +0000 |
38 | +++ src/Makefile.am 2012-08-14 14:17:21 +0000 |
39 | @@ -12,15 +12,15 @@ |
40 | # Headers, vapi, and gir |
41 | ## |
42 | unityincludedir = $(includedir)/unity/unity |
43 | -unityinclude_HEADERS = \ |
44 | - unity.h \ |
45 | - unity-trace.h \ |
46 | - $(NULL) |
47 | +nodist_unityinclude_HEADERS = unity.h |
48 | +dist_unityinclude_HEADERS = unity-trace.h |
49 | |
50 | unityvapidir = $(datadir)/vala/vapi |
51 | -unityvapi_DATA = \ |
52 | +nodist_unityvapi_DATA = \ |
53 | unity.vapi \ |
54 | unity.deps \ |
55 | + $(NULL) |
56 | +dist_unityvapi_DATA = \ |
57 | unity-trace.vapi \ |
58 | unity-trace.deps \ |
59 | $(NULL) |
60 | @@ -80,8 +80,8 @@ |
61 | $(LIBUNITY_PACKAGES) \ |
62 | $(MAINTAINER_VALAFLAGS) |
63 | |
64 | -libunity_la_SOURCES = \ |
65 | - $(libunity_la_VALASOURCES:.vala=.c) \ |
66 | +nodist_libunity_la_SOURCES = $(libunity_la_VALASOURCES:.vala=.c) |
67 | +dist_libunity_la_SOURCES = \ |
68 | unity-trace.c \ |
69 | unity-trace.h |
70 | |
71 | @@ -142,9 +142,6 @@ |
72 | $(libunity_la_VALASOURCES:.vala=.c) \ |
73 | unity.deps |
74 | |
75 | -dist-hook: |
76 | - rm -f $(addprefix $(distdir)/,$(libunity_la_VALASOURCES:.vala=.c)) |
77 | - |
78 | ## |
79 | # Compile .typelib from .gir |
80 | ## |
81 | |
82 | === modified file 'test/vala/Makefile.am' |
83 | --- test/vala/Makefile.am 2012-07-27 09:32:20 +0000 |
84 | +++ test/vala/Makefile.am 2012-08-14 14:17:21 +0000 |
85 | @@ -51,15 +51,15 @@ |
86 | test-scope-signals.vala \ |
87 | test-vala.vala \ |
88 | $(NULL) |
89 | -test_vala_SOURCES = $(test_vala_VALASOURCES:.vala=.c) |
90 | +nodist_test_vala_SOURCES = $(test_vala_VALASOURCES:.vala=.c) |
91 | |
92 | test_lens_LDADD = $(test_libs) |
93 | test_lens_VALASOURCES = test-lens.vala |
94 | -test_lens_SOURCES = $(test_lens_VALASOURCES:.vala=.c) |
95 | +nodist_test_lens_SOURCES = $(test_lens_VALASOURCES:.vala=.c) |
96 | |
97 | test_remote_scope_LDADD = $(test_libs) |
98 | test_remote_scope_VALASOURCES = test-remote-scope.vala |
99 | -test_remote_scope_SOURCES = $(test_remote_scope_VALASOURCES:.vala=.c) |
100 | +nodist_test_remote_scope_SOURCES = $(test_remote_scope_VALASOURCES:.vala=.c) |
101 | |
102 | BUILT_SOURCES = \ |
103 | test-vala.vala.stamp \ |
104 | |
105 | === modified file 'test/vala/Makefile.integration_tests' |
106 | --- test/vala/Makefile.integration_tests 2012-07-27 09:32:20 +0000 |
107 | +++ test/vala/Makefile.integration_tests 2012-08-14 14:17:21 +0000 |
108 | @@ -1,3 +1,5 @@ |
109 | +if ENABLE_INTEGRATION_TESTS |
110 | + |
111 | check_PROGRAMS += \ |
112 | test-launcher-integration \ |
113 | test-sound-menu \ |
114 | @@ -6,11 +8,6 @@ |
115 | test-mpris-backend-prop-updates-client \ |
116 | test-mpris-backend-prop-updates-server |
117 | |
118 | -# We must still build all the .c and .stamp files to distribute, |
119 | -# so we only disable the actual test runs when integration tests |
120 | -# are switched off |
121 | -if ENABLE_INTEGRATION_TESTS |
122 | - |
123 | TEST_PROGS += \ |
124 | test-lens-scope-interactions \ |
125 | test-launcher-integration \ |
126 | @@ -43,7 +40,7 @@ |
127 | ######################################### |
128 | test_launcher_integration_VALASOURCES = \ |
129 | test-launcher-integration.vala |
130 | -test_launcher_integration_SOURCES = \ |
131 | +nodist_test_launcher_integration_SOURCES = \ |
132 | $(test_launcher_integration_VALASOURCES:.vala=.c) |
133 | |
134 | test_launcher_integration_LDADD = $(test_libs) |
135 | @@ -53,7 +50,7 @@ |
136 | ######################################### |
137 | test_sound_menu_VALASOURCES = \ |
138 | test-sound-menu.vala |
139 | -test_sound_menu_SOURCES = \ |
140 | +nodist_test_sound_menu_SOURCES = \ |
141 | $(test_sound_menu_VALASOURCES:.vala=.c) |
142 | |
143 | test_sound_menu_LDADD = $(test_libs) |
144 | @@ -63,7 +60,7 @@ |
145 | ######################################### |
146 | test_mpris_backend_client_VALASOURCES = \ |
147 | test-mpris-backend-client.vala |
148 | -test_mpris_backend_client_SOURCES = \ |
149 | +nodist_test_mpris_backend_client_SOURCES = \ |
150 | $(test_mpris_backend_client_VALASOURCES:.vala=.c) |
151 | |
152 | test_mpris_backend_client_LDADD = $(test_libs) |
153 | @@ -73,7 +70,7 @@ |
154 | ######################################## |
155 | test_mpris_backend_server_VALASOURCES = \ |
156 | test-mpris-backend-server.vala |
157 | -test_mpris_backend_server_SOURCES = \ |
158 | +nodist_test_mpris_backend_server_SOURCES = \ |
159 | $(test_mpris_backend_server_VALASOURCES:.vala=.c) |
160 | |
161 | test_mpris_backend_server_LDADD = $(test_libs) |
162 | @@ -88,7 +85,7 @@ |
163 | ######################################### |
164 | test_mpris_backend_prop_updates_client_VALASOURCES = \ |
165 | test-mpris-backend-prop-updates-client.vala |
166 | -test_mpris_backend_prop_updates_client_SOURCES = \ |
167 | +nodist_test_mpris_backend_prop_updates_client_SOURCES = \ |
168 | $(test_mpris_backend_prop_updates_client_VALASOURCES:.vala=.c) |
169 | |
170 | test_mpris_backend_prop_updates_client_LDADD = $(test_libs) |
171 | @@ -98,7 +95,7 @@ |
172 | ######################################## |
173 | test_mpris_backend_prop_updates_server_VALASOURCES = \ |
174 | test-mpris-backend-prop-updates-server.vala |
175 | -test_mpris_backend_prop_updates_server_SOURCES = \ |
176 | +nodist_test_mpris_backend_prop_updates_server_SOURCES = \ |
177 | $(test_mpris_backend_prop_updates_server_VALASOURCES:.vala=.c) |
178 | |
179 | test_mpris_backend_prop_updates_server_LDADD = $(test_libs) |
180 | |
181 | === modified file 'tools/Makefile.am' |
182 | --- tools/Makefile.am 2012-07-27 10:03:20 +0000 |
183 | +++ tools/Makefile.am 2012-08-14 14:17:21 +0000 |
184 | @@ -9,6 +9,8 @@ |
185 | libunity_tool_CPPFLAGS = \ |
186 | -DG_LOG_DOMAIN=\"libunity-tool\" \ |
187 | -I$(srcdir) \ |
188 | + -I$(top_builddir)/src \ |
189 | + -I$(top_builddir)/protocol \ |
190 | $(LIBUNITY_CFLAGS) \ |
191 | $(UNITYTOOL_CFLAGS) |
192 | |
193 | @@ -21,36 +23,44 @@ |
194 | endif |
195 | |
196 | libunity_tool_LDADD = \ |
197 | + $(top_builddir)/src/libunity.la \ |
198 | + $(top_builddir)/protocol/libunity-protocol-private.la \ |
199 | $(LIBUNITY_LIBS) \ |
200 | $(UNITYTOOL_LIBS) |
201 | |
202 | libunity_tool_VALAFLAGS = \ |
203 | -C \ |
204 | --vapidir $(top_srcdir)/vapi \ |
205 | - --pkg config --pkg gtk+-3.0 --pkg gmodule-2.0 \ |
206 | - $(LIBUNITY_PACKAGES) |
207 | + --vapidir=$(top_builddir)/protocol \ |
208 | + --vapidir=$(top_builddir)/src \ |
209 | + --pkg config \ |
210 | + --pkg gtk+-3.0 \ |
211 | + --pkg gmodule-2.0 \ |
212 | + --pkg unity-internal \ |
213 | + --pkg unity-protocol \ |
214 | + $(LIBUNITY_PACKAGES) \ |
215 | $(MAINTAINER_VALAFLAGS) |
216 | |
217 | libunity_tool_VALASOURCES = \ |
218 | unity-tool.vala \ |
219 | unity-tool-dbus-util.vala \ |
220 | unity-tool-ui.vala \ |
221 | + preview-renderer.vala \ |
222 | + music-track-model-renderer.vala \ |
223 | $(NULL) |
224 | |
225 | - |
226 | libunity_tool_UISOURCES = unity-tool-res.gresource.xml unity-tool.ui dbus-lens-connect.ui |
227 | |
228 | unity-tool-res.c: $(libunity_tool_UISOURCES) |
229 | - $(AM_V_GEN)$(GLIB_RESCOMPILE) --sourcedir $(srcdir) --generate-source $< |
230 | + $(AM_V_GEN)$(GLIB_RESCOMPILE) --sourcedir $(srcdir) --target=$@ --generate-source $(filter %.xml,$^) |
231 | |
232 | -libunity_tool_SOURCES = \ |
233 | +nodist_libunity_tool_SOURCES = \ |
234 | $(libunity_tool_VALASOURCES:.vala=.c) \ |
235 | unity-tool-res.c \ |
236 | $(NULL) |
237 | |
238 | -BUILT_SOURCES += unity_tool_vala.stamp |
239 | +BUILT_SOURCES += unity-tool-res.c unity_tool_vala.stamp |
240 | EXTRA_DIST += \ |
241 | - $(BUILT_SOURCES) \ |
242 | $(libunity_tool_VALASOURCES) \ |
243 | $(libunity_tool_UISOURCES) \ |
244 | $(NULL) |
245 | @@ -60,7 +70,8 @@ |
246 | @touch $@ |
247 | |
248 | CLEANFILES += \ |
249 | - *.stamp \ |
250 | + unity_tool_vala.stamp \ |
251 | + unity-tool-res.c \ |
252 | $(libunity_tool_VALASOURCES:.vala=.c) \ |
253 | $(NULL) |
254 | |
255 | |
256 | === added file 'tools/music-track-model-renderer.vala' |
257 | --- tools/music-track-model-renderer.vala 1970-01-01 00:00:00 +0000 |
258 | +++ tools/music-track-model-renderer.vala 2012-08-14 14:17:21 +0000 |
259 | @@ -0,0 +1,95 @@ |
260 | +/* |
261 | + * Copyright (C) 2012 Canonical Ltd |
262 | + * |
263 | + * This program is free software: you can redistribute it and/or modify |
264 | + * it under the terms of the GNU General Public License version 3 as |
265 | + * published by the Free Software Foundation. |
266 | + * |
267 | + * This program is distributed in the hope that it will be useful, |
268 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
269 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
270 | + * GNU General Public License for more details. |
271 | + * |
272 | + * You should have received a copy of the GNU General Public License |
273 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
274 | + * |
275 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
276 | + * |
277 | + */ |
278 | + |
279 | +using Gtk; |
280 | + |
281 | +namespace Unity.Tester { |
282 | + |
283 | +public class MusicTrackModelRenderer: Object |
284 | +{ |
285 | + public string dbus_model { get; construct; } |
286 | + private Dee.SharedModel? track_model; |
287 | + private Dee.ModelTag<int> track_model_tag; |
288 | + private int row_counter = 0; |
289 | + private ulong model_sync_sig_id = 0; |
290 | + public ListStore track_view_model { get; construct; } |
291 | + |
292 | + public signal void track_list_synchronized(); |
293 | + |
294 | + construct |
295 | + { |
296 | + track_view_model = new ListStore(6, typeof(string), typeof(int), typeof(string), typeof(uint), typeof(uint), typeof(double)); |
297 | + } |
298 | + |
299 | + public MusicTrackModelRenderer(string dbus_model) |
300 | + { |
301 | + Object(dbus_model: dbus_model); |
302 | + } |
303 | + |
304 | + public void sync() |
305 | + { |
306 | + track_model = new Dee.SharedModel(dbus_model); |
307 | + track_model_tag = new Dee.ModelTag<int>(track_model); |
308 | + |
309 | + track_model.row_added.connect(track_added_cb); |
310 | + track_model.row_changed.connect(track_changed_cb); |
311 | + |
312 | + model_sync_sig_id = track_model.notify["synchronized"].connect(track_model_synchronized_cb); |
313 | + } |
314 | + |
315 | + private void track_added_cb(Dee.Model model, Dee.ModelIter iter) |
316 | + { |
317 | + var row = model.get_row(iter); |
318 | + |
319 | + track_model_tag.set(track_model, iter, row_counter++); |
320 | + |
321 | + TreeIter tm_iter; |
322 | + track_view_model.append(out tm_iter); |
323 | + track_view_model.set(tm_iter, 0, row[0].get_string(), 1, row[1].get_int32(), 2, row[2].get_string(), 3, row[3].get_uint32(), 4, row[4].get_uint32(), 5, row[5].get_double(), -1); |
324 | + } |
325 | + |
326 | + private void track_changed_cb(Dee.Model model, Dee.ModelIter iter) |
327 | + { |
328 | + int index = track_model_tag.get(track_model, iter); |
329 | + TreeIter tm_iter; |
330 | + if (track_view_model.get_iter_first(out tm_iter)) { |
331 | + while (index > 0) |
332 | + { |
333 | + if (!track_view_model.iter_next(ref tm_iter)) { |
334 | + break; |
335 | + } |
336 | + --index; |
337 | + } |
338 | + if (index == 0) { |
339 | + var row = model.get_row(iter); |
340 | + track_view_model.set(tm_iter, 0, row[0].get_string(), 1, row[1].get_int32(), 2, row[2].get_string(), 3, row[3].get_uint32(), 4, row[4].get_uint32(), 5, row[5].get_double(), -1); |
341 | + } else { |
342 | + stderr.printf("can't update row"); |
343 | + } |
344 | + } |
345 | + } |
346 | + |
347 | + private void track_model_synchronized_cb() |
348 | + { |
349 | + SignalHandler.disconnect (track_model, model_sync_sig_id); |
350 | + track_list_synchronized(); |
351 | + } |
352 | +} |
353 | + |
354 | +} |
355 | \ No newline at end of file |
356 | |
357 | === added file 'tools/preview-renderer.vala' |
358 | --- tools/preview-renderer.vala 1970-01-01 00:00:00 +0000 |
359 | +++ tools/preview-renderer.vala 2012-08-14 14:17:21 +0000 |
360 | @@ -0,0 +1,457 @@ |
361 | +/* |
362 | + * Copyright (C) 2012 Canonical Ltd |
363 | + * |
364 | + * This program is free software: you can redistribute it and/or modify |
365 | + * it under the terms of the GNU General Public License version 3 as |
366 | + * published by the Free Software Foundation. |
367 | + * |
368 | + * This program is distributed in the hope that it will be useful, |
369 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
370 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
371 | + * GNU General Public License for more details. |
372 | + * |
373 | + * You should have received a copy of the GNU General Public License |
374 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
375 | + * |
376 | + * Authored by Pawel Stolowski <pawel.stolowski@canonical.com> |
377 | + * |
378 | + */ |
379 | +using Gtk; |
380 | + |
381 | +namespace Unity.Tester { |
382 | + |
383 | + public abstract class PreviewRenderer: Object |
384 | + { |
385 | + public signal void preview_action_clicked(string uri); |
386 | + |
387 | + public abstract Gtk.Widget get_widget(); |
388 | + public abstract Gtk.Widget get_buttons(); |
389 | + public abstract Gtk.Widget get_extra_buttons(); |
390 | + |
391 | + internal abstract void render_buttons(); |
392 | + internal abstract void render_extra_buttons(); |
393 | + internal abstract void render(); |
394 | + |
395 | + public static PreviewRenderer? create(Unity.Protocol.Preview preview, string scope_uri) |
396 | + { |
397 | + if (preview is Unity.Protocol.GenericPreview) { |
398 | + return new GenericPreviewRenderer(preview as Unity.Protocol.GenericPreview, scope_uri); |
399 | + } |
400 | + if (preview is Unity.Protocol.ApplicationPreview) { |
401 | + return new ApplicationPreviewRenderer(preview as Unity.Protocol.ApplicationPreview, scope_uri); |
402 | + } |
403 | + if (preview is Unity.Protocol.MusicPreview) { |
404 | + return new MusicPreviewRenderer(preview as Unity.Protocol.MusicPreview, scope_uri); |
405 | + } |
406 | + if (preview is Unity.Protocol.MoviePreview) { |
407 | + return new MoviePreviewRenderer(preview as Unity.Protocol.MoviePreview, scope_uri); |
408 | + } |
409 | + if (preview is Unity.Protocol.SeriesPreview) { |
410 | + return new SeriesPreviewRenderer(preview as Unity.Protocol.SeriesPreview, scope_uri); |
411 | + } |
412 | + return null; |
413 | + } |
414 | + |
415 | + public Unity.Protocol.Preview preview { get; construct; } |
416 | + public string scope_uri { get; construct; } |
417 | + } |
418 | + |
419 | + /** |
420 | + * Render preview in Gtk.Grid with 2 columns (name and value). |
421 | + */ |
422 | + public abstract class GridRenderer: PreviewRenderer |
423 | + { |
424 | + public GridRenderer() |
425 | + { |
426 | + Object(); |
427 | + } |
428 | + |
429 | + internal void add_standard_attributes(Unity.Protocol.Preview preview) |
430 | + { |
431 | + add_text_row("<b>Title</b>", preview.title); |
432 | + add_text_row("<b>Subtitle</b>", preview.subtitle); |
433 | + add_text_row("<b>Description</b>", preview.description); |
434 | + add_text_row("<b>Image source</b>", preview.image_source_uri); |
435 | + add_text_icon_row("<b>Image</b>", preview.image, preview.image.to_string(), 512); |
436 | + } |
437 | + |
438 | + internal void add_info_hints(Unity.Protocol.Preview preview) |
439 | + { |
440 | + Unity.Protocol.InfoHintRaw[] hints = preview.get_info_hints(); |
441 | + add_headline("<b><u>Info Hint</u></b>"); |
442 | + foreach (Unity.Protocol.InfoHintRaw hint in hints) { |
443 | + add_text_row("<b>Id</b>", hint.id); |
444 | + add_text_row("<b>Display Name</b>", hint.display_name); |
445 | + add_text_row("<b>Icon hint</b>", hint.icon_hint); |
446 | + add_text_row("<b>Value</b>", hint.value.print(true)); |
447 | + } |
448 | + } |
449 | + |
450 | + /** |
451 | + * Renders name and value in two adjacent cells of grid row |
452 | + */ |
453 | + public void add_text_row(string name, string? value) |
454 | + { |
455 | + var name_label = new Gtk.Label(null); |
456 | + name_label.set_markup(name); |
457 | + grid.attach(name_label, 0, row, 1, 1); |
458 | + var value_label = new Gtk.Label(value); |
459 | + value_label.selectable = true; |
460 | + grid.attach(value_label, 1, row, 1, 1); |
461 | + |
462 | + ++row; |
463 | + } |
464 | + |
465 | + /** |
466 | + * Renders text in two joined cells of grid row |
467 | + */ |
468 | + public void add_headline(string text) |
469 | + { |
470 | + var label = new Gtk.Label(null); |
471 | + label.set_markup(text); |
472 | + grid.attach(label, 0, row, 2, 1); |
473 | + |
474 | + ++row; |
475 | + } |
476 | + |
477 | + /** |
478 | + * Renders name and arbitrary widget in two adjacent cells of grid row |
479 | + */ |
480 | + public void add_widget(string name, Gtk.Widget widget) |
481 | + { |
482 | + var name_label = new Gtk.Label(null); |
483 | + name_label.set_markup(name); |
484 | + grid.attach(name_label, 0, row, 1, 1); |
485 | + grid.attach(widget, 1, row, 1, 1); |
486 | + ++row; |
487 | + } |
488 | + |
489 | + public void on_preview_action_clicked(Gtk.Button button) |
490 | + { |
491 | + string uri = preview_actions.get(button); |
492 | + preview_action_clicked(uri); |
493 | + } |
494 | + |
495 | + /** |
496 | + * Renders name and icon in two adjacent cells of grid row |
497 | + */ |
498 | + public void add_text_icon_row(string name, GLib.Icon? icon, string? tooltip, int size=32) |
499 | + { |
500 | + var icon_label = new Gtk.Label(null); |
501 | + icon_label.set_markup(name); |
502 | + grid.attach(icon_label, 0, row, 1, 1); |
503 | + var themed_icon = Gtk.IconTheme.get_default().lookup_by_gicon(icon, size, 0); |
504 | + var pixbuf = themed_icon.load_icon(); |
505 | + Gtk.Image image = new Gtk.Image.from_pixbuf(pixbuf); |
506 | + if (tooltip != null) { |
507 | + image.set_tooltip_text(tooltip); |
508 | + } |
509 | + grid.attach(image, 1, row, 1, 1); |
510 | + |
511 | + ++row; |
512 | + } |
513 | + |
514 | + public override Gtk.Widget get_widget() |
515 | + { |
516 | + render(); |
517 | + grid.foreach((obj) => { obj.set_halign(Gtk.Align.START); }); |
518 | + return grid; |
519 | + } |
520 | + |
521 | + public override Gtk.Widget get_buttons() |
522 | + { |
523 | + render_buttons(); |
524 | + return preview_actions_box; |
525 | + } |
526 | + |
527 | + public override Gtk.Widget get_extra_buttons() |
528 | + { |
529 | + render_extra_buttons(); |
530 | + return preview_extra_buttons_box; |
531 | + } |
532 | + |
533 | + public override void render_buttons() |
534 | + { |
535 | + preview_actions = new GLib.HashTable<Gtk.Button, string>(null, null); |
536 | + Unity.Protocol.PreviewActionRaw[] actions = preview.get_actions(); |
537 | + for (int i=0; i<actions.length; i++) { |
538 | + unowned Unity.Protocol.PreviewActionRaw action = actions[i]; |
539 | + Gtk.Button btn = new Gtk.Button.with_label(action.display_name); |
540 | + btn.clicked.connect(on_preview_action_clicked); |
541 | + preview_actions_box.pack_start(btn, false, false); |
542 | + string action_uri = "%s:%s".printf(action.id, scope_uri); |
543 | + btn.set_tooltip_text(action_uri); |
544 | + preview_actions.insert(btn, action_uri); |
545 | + btn.show_all(); |
546 | + } |
547 | + } |
548 | + |
549 | + internal override void render_extra_buttons() |
550 | + { |
551 | + } |
552 | + |
553 | + construct { |
554 | + grid = new Gtk.Grid(); |
555 | + grid.set_column_spacing(5); |
556 | + grid.set_row_spacing(5); |
557 | + grid.border_width = 5; |
558 | + grid.set_halign(Gtk.Align.FILL); |
559 | + grid.set_valign(Gtk.Align.FILL); |
560 | + grid.hexpand = true; |
561 | + grid.vexpand = true; |
562 | + |
563 | + preview_actions_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 5); |
564 | + preview_actions_box.set_halign(Gtk.Align.FILL); |
565 | + preview_actions_box.set_valign(Gtk.Align.FILL); |
566 | + preview_actions_box.hexpand = false; |
567 | + preview_actions_box.vexpand = false; |
568 | + |
569 | + preview_extra_buttons_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 5); |
570 | + preview_extra_buttons_box.set_halign(Gtk.Align.FILL); |
571 | + preview_extra_buttons_box.set_valign(Gtk.Align.FILL); |
572 | + preview_extra_buttons_box.hexpand = false; |
573 | + preview_extra_buttons_box.vexpand = false; |
574 | + } |
575 | + |
576 | + private int row = 0; |
577 | + public Gtk.Grid grid { get; construct; } |
578 | + public Gtk.Box preview_actions_box { get; construct; } |
579 | + public Gtk.Box preview_extra_buttons_box { get; construct; } |
580 | + private GLib.HashTable<Gtk.Button, string> preview_actions = null; |
581 | + } |
582 | + |
583 | + public class GenericPreviewRenderer: GridRenderer |
584 | + { |
585 | + public GenericPreviewRenderer(Unity.Protocol.GenericPreview preview, string scope_uri) |
586 | + { |
587 | + Object(preview: preview, scope_uri: scope_uri); |
588 | + } |
589 | + |
590 | + internal override void render() |
591 | + { |
592 | + assert(preview != null); |
593 | + |
594 | + base.add_standard_attributes(preview as Unity.Protocol.GenericPreview); |
595 | + base.add_info_hints(preview as Unity.Protocol.GenericPreview); |
596 | + } |
597 | + } |
598 | + |
599 | + public class ApplicationPreviewRenderer: GridRenderer |
600 | + { |
601 | + public ApplicationPreviewRenderer(Unity.Protocol.ApplicationPreview preview, string scope_uri) |
602 | + { |
603 | + Object(preview: preview, scope_uri: scope_uri); |
604 | + } |
605 | + |
606 | + internal override void render() |
607 | + { |
608 | + assert(preview != null); |
609 | + |
610 | + var app_preview = preview as Unity.Protocol.ApplicationPreview; |
611 | + |
612 | + base.add_standard_attributes(preview); |
613 | + base.add_text_row("<b>License</b>", app_preview.license); |
614 | + base.add_text_row("<b>Copyright</b>", app_preview.copyright); |
615 | + base.add_text_row("<b>Last update</b>", app_preview.last_update); |
616 | + base.add_text_row("<b>Rating</b>", "%.2f".printf(app_preview.rating)); |
617 | + base.add_text_row("<b>Number of ratings</b>", "%u".printf(app_preview.num_ratings)); |
618 | + base.add_text_icon_row("<b>Application icon</b>", app_preview.app_icon, app_preview.app_icon.to_string()); |
619 | + base.add_info_hints(app_preview); |
620 | + } |
621 | + } |
622 | + |
623 | + public class MusicPreviewRenderer: GridRenderer |
624 | + { |
625 | + private MusicTrackModelRenderer track_model_renderer; |
626 | + private Gtk.TreeView track_view; |
627 | + private Gtk.Menu track_view_popup_menu; |
628 | + |
629 | + public signal void play_music_track_clicked(string uri); |
630 | + public signal void pause_music_track_clicked(string uri); |
631 | + |
632 | + public MusicPreviewRenderer(Unity.Protocol.MusicPreview preview, string scope_uri) |
633 | + { |
634 | + Object(preview: preview, scope_uri: scope_uri); |
635 | + } |
636 | + |
637 | + internal override void render() |
638 | + { |
639 | + assert(preview != null); |
640 | + var music_preview = preview as Unity.Protocol.MusicPreview; |
641 | + |
642 | + base.add_standard_attributes(preview); |
643 | + base.add_text_row("<b>Track data swarm name</b>", music_preview.track_data_swarm_name); |
644 | + base.add_text_row("<b>Track data address</b>", music_preview.track_data_address); |
645 | + base.add_info_hints(music_preview); |
646 | + |
647 | + if (music_preview.track_data_swarm_name != null && music_preview.track_data_swarm_name != "") |
648 | + { |
649 | + track_model_renderer = new MusicTrackModelRenderer(music_preview.track_data_swarm_name); |
650 | + track_view = new TreeView(); |
651 | + var track_view_viewport = new Viewport(null, null); |
652 | + |
653 | + track_view.set_model(track_model_renderer.track_view_model); |
654 | + |
655 | + track_view.insert_column_with_attributes(-1, "uri", new CellRendererText (), "text", 0); |
656 | + track_view.insert_column_with_attributes(-1, "track no", new CellRendererText (), "text", 1); |
657 | + track_view.insert_column_with_attributes(-1, "title", new CellRendererText (), "text", 2); |
658 | + track_view.insert_column_with_attributes(-1, "length", new CellRendererText (), "text", 3); |
659 | + track_view.insert_column_with_attributes(-1, "playing", new CellRendererText (), "text", 4); |
660 | + track_view.insert_column_with_attributes(-1, "progress", new CellRendererText (), "text", 5); |
661 | + |
662 | + track_view_viewport.add_with_properties(track_view); |
663 | + add_widget("Track model", track_view_viewport); |
664 | + |
665 | + track_view_popup_menu = new Gtk.Menu(); |
666 | + var play_item = new Gtk.MenuItem.with_label("Play"); |
667 | + play_item.activate.connect(on_play_item_clicked); |
668 | + track_view_popup_menu.append(play_item); |
669 | + play_item.show(); |
670 | + var pause_item = new Gtk.MenuItem.with_label("Pause"); |
671 | + pause_item.activate.connect(on_pause_item_clicked); |
672 | + track_view_popup_menu.append(pause_item); |
673 | + pause_item.show(); |
674 | + |
675 | + track_view.button_press_event.connect(on_track_view_right_click); |
676 | + track_model_renderer.sync(); |
677 | + } |
678 | + } |
679 | + |
680 | + public bool on_track_view_right_click(Gtk.Widget widget, Gdk.EventButton event) |
681 | + { |
682 | + if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3 /* right mouse button */) { |
683 | + track_view_popup_menu.popup(null, null, null, event.button, event.time); |
684 | + } |
685 | + return false; |
686 | + } |
687 | + |
688 | + internal string get_selected_track_uri() |
689 | + { |
690 | + TreeModel model; |
691 | + TreeIter iter; |
692 | + var selection = track_view.get_selection(); |
693 | + if (selection.get_selected(out model, out iter)) { |
694 | + Value val; |
695 | + // get uri column |
696 | + model.get_value(iter, 0, out val); |
697 | + return val.get_string(); |
698 | + } |
699 | + return ""; |
700 | + } |
701 | + |
702 | + internal void on_play_item_clicked(Gtk.MenuItem item) |
703 | + { |
704 | + string uri = get_selected_track_uri(); |
705 | + if (uri != "") |
706 | + { |
707 | + play_music_track_clicked(uri); |
708 | + } |
709 | + } |
710 | + |
711 | + internal void on_pause_item_clicked(Gtk.MenuItem item) |
712 | + { |
713 | + string uri = get_selected_track_uri(); |
714 | + if (uri != "") |
715 | + { |
716 | + pause_music_track_clicked(uri); |
717 | + } |
718 | + } |
719 | + } |
720 | + |
721 | + public class MoviePreviewRenderer: GridRenderer |
722 | + { |
723 | + public MoviePreviewRenderer(Unity.Protocol.MoviePreview preview, string scope_uri) |
724 | + { |
725 | + Object(preview: preview, scope_uri: scope_uri); |
726 | + } |
727 | + |
728 | + internal override void render() |
729 | + { |
730 | + assert(preview != null); |
731 | + var movie_preview= preview as Unity.Protocol.MoviePreview; |
732 | + |
733 | + base.add_standard_attributes(preview); |
734 | + base.add_text_row("<b>Rating</b>", "%.2f".printf(movie_preview.rating)); |
735 | + base.add_text_row("<b>Number of ratings</b>", "%u".printf(movie_preview.num_ratings)); |
736 | + base.add_info_hints(movie_preview); |
737 | + } |
738 | + } |
739 | + |
740 | + public class SeriesPreviewRenderer: GridRenderer |
741 | + { |
742 | + public signal void change_selected_series_item_clicked(string uri, int index); |
743 | + |
744 | + public SeriesPreviewRenderer(Unity.Protocol.SeriesPreview preview, string scope_uri) |
745 | + { |
746 | + Object(preview: preview, scope_uri: scope_uri); |
747 | + } |
748 | + |
749 | + public void update_child_preview(Unity.Protocol.Preview child_preview) |
750 | + { |
751 | + (preview as Unity.Protocol.SeriesPreview).child_preview = child_preview; |
752 | + } |
753 | + |
754 | + private void on_change_selected_item_clicked(Gtk.ComboBox combo) |
755 | + { |
756 | + int index = int.parse(combo.active_id); |
757 | + var series_preview = preview as Unity.Protocol.SeriesPreview; |
758 | + if (index != series_preview.selected_item) { |
759 | + change_selected_series_item_clicked(scope_uri, index); |
760 | + } |
761 | + } |
762 | + |
763 | + internal override void render_extra_buttons() |
764 | + { |
765 | + var series_preview = preview as Unity.Protocol.SeriesPreview; |
766 | + |
767 | + Gtk.Box box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); |
768 | + |
769 | + Gtk.ComboBoxText items_combo = new Gtk.ComboBoxText(); |
770 | + items_combo.changed.connect(on_change_selected_item_clicked); |
771 | + Protocol.SeriesItemRaw[] items = series_preview.get_items(); |
772 | + for (int i=0; i<items.length; i++) { |
773 | + items_combo.append("%u".printf(i), "Series item #%u".printf(i)); |
774 | + } |
775 | + items_combo.set_active_id("%u".printf(series_preview.selected_item)); |
776 | + |
777 | + var label = new Gtk.Label("Set active:"); |
778 | + box.pack_start(label); |
779 | + box.pack_start(items_combo, false, false); |
780 | + box.show_all(); |
781 | + |
782 | + preview_extra_buttons_box.pack_start(box, false, false); |
783 | + } |
784 | + |
785 | + internal override void render() |
786 | + { |
787 | + assert(preview != null); |
788 | + var series_preview = preview as Unity.Protocol.SeriesPreview; |
789 | + |
790 | + base.add_standard_attributes(preview); |
791 | + base.add_text_row("<b>Selected item</b>", "%d".printf(series_preview.selected_item)); |
792 | + Protocol.SeriesItemRaw[] items = series_preview.get_items(); |
793 | + |
794 | + PreviewRenderer? child_preview = PreviewRenderer.create(series_preview.child_preview, scope_uri); |
795 | + if (child_preview != null) { |
796 | + base.add_widget("<b>Child preview</b>", child_preview.get_widget()); |
797 | + } |
798 | + |
799 | + for (int i=0; i<items.length; i++) { |
800 | + base.add_headline("<u><b>Series item #%u</b></u>".printf(i)); |
801 | + base.add_text_row("<b>Title</b>", items[i].title); |
802 | + base.add_text_row("<b>Uri</b>", items[i].uri); |
803 | + |
804 | + if (items[i].icon_hint != null) { |
805 | + try { |
806 | + var icon = GLib.Icon.new_for_string(items[i].icon_hint); |
807 | + base.add_text_icon_row("<b>Icon</b>", icon, items[i].icon_hint.to_string()); |
808 | + } |
809 | + catch (GLib.Error e) { |
810 | + stderr.printf("Series Item icon couldn't be loaded: %s\n", e.message); |
811 | + } |
812 | + } |
813 | + } |
814 | + base.add_info_hints(series_preview); |
815 | + } |
816 | + } |
817 | +} |
818 | |
819 | === modified file 'tools/unity-tool-dbus-util.vala' |
820 | --- tools/unity-tool-dbus-util.vala 2012-06-13 15:17:44 +0000 |
821 | +++ tools/unity-tool-dbus-util.vala 2012-08-14 14:17:21 +0000 |
822 | @@ -17,12 +17,12 @@ |
823 | |
824 | public DBusLensUtil() |
825 | { |
826 | - try { |
827 | - lens_dbusname_regex = new Regex("^([a-zA-Z-]+(\\.[a-zA-Z-]+)+)\\.T[\\d]+.[a-zA-Z]+$"); |
828 | - } |
829 | - catch (Error e) { |
830 | - stderr.printf("Error parsing lens_dbusname_regex"); |
831 | - } |
832 | + try { |
833 | + lens_dbusname_regex = new Regex("^([a-zA-Z-]+(\\.[a-zA-Z-]+)+)\\.T[\\d]+.[a-zA-Z]+$"); |
834 | + } |
835 | + catch (Error e) { |
836 | + stderr.printf("Error parsing lens_dbusname_regex"); |
837 | + } |
838 | } |
839 | |
840 | /** |
841 | @@ -32,22 +32,22 @@ |
842 | { |
843 | List<string> services = new List<string>(); |
844 | |
845 | - var vt = new VariantType ("(as)"); |
846 | - var bus = Bus.get_sync (BusType.SESSION); |
847 | - Variant v = bus.call_sync("org.freedesktop.DBus", |
848 | - "/org/freedesktop/DBus", |
849 | - "org.freedesktop.DBus", |
850 | - "ListNames", |
851 | - null, |
852 | - vt, |
853 | - 0, |
854 | - -1, |
855 | - null); |
856 | + var vt = new VariantType ("(as)"); |
857 | + var bus = Bus.get_sync (BusType.SESSION); |
858 | + Variant v = bus.call_sync("org.freedesktop.DBus", |
859 | + "/org/freedesktop/DBus", |
860 | + "org.freedesktop.DBus", |
861 | + "ListNames", |
862 | + null, |
863 | + vt, |
864 | + 0, |
865 | + -1, |
866 | + null); |
867 | |
868 | - string *[]names = v.get_child_value(0).get_strv(); |
869 | - foreach (string *s in names) { |
870 | - services.append(s); |
871 | - } |
872 | + string *[]names = v.get_child_value(0).get_strv(); |
873 | + foreach (string *s in names) { |
874 | + services.append(s); |
875 | + } |
876 | |
877 | return services; |
878 | } |
879 | @@ -89,85 +89,85 @@ |
880 | */ |
881 | public async unowned List<DBusObjectAddress?> findLenses() throws GLib.Error |
882 | { |
883 | - if (lens_dbusname_regex == null) { |
884 | - stderr.printf("Invalid lens_dbusname_regex"); |
885 | - return lenses; |
886 | - } |
887 | - |
888 | - var bus = Bus.get_sync (BusType.SESSION); |
889 | - var vt = new VariantType ("(s)"); |
890 | - |
891 | - // |
892 | - // Service filtering - potential lenses must match this regexp; |
893 | - // e.g. com.canonical.Unity.Lens.applications.T1338793992370.Results |
894 | - foreach (string srv in getServices()) { |
895 | - if (lens_dbusname_regex.match(srv)) { |
896 | - try { |
897 | - var vb = new VariantBuilder(new VariantType("(s)")); |
898 | - vb.add_value(srv); |
899 | - |
900 | - Variant v = bus.call_sync( |
901 | - "org.freedesktop.DBus", |
902 | - "/", |
903 | - "org.freedesktop.DBus", |
904 | - "GetNameOwner", |
905 | - vb.end(), |
906 | - vt, |
907 | - 0, |
908 | - 10, |
909 | - null); |
910 | - |
911 | - if (v != null) { |
912 | - string owner = v.get_child_value(0).get_string(); |
913 | - if (owner != null) { |
914 | - DBusObjectAddress obj = DBusObjectAddress() { |
915 | - dbus_name = owner, |
916 | - dbus_path = "/" |
917 | - }; |
918 | - nodes.push_tail(obj); |
919 | - } |
920 | - } |
921 | - } |
922 | - catch (Error e) { |
923 | - // silently ignore |
924 | - } |
925 | - |
926 | - } |
927 | - } |
928 | - |
929 | - // |
930 | - // introspect all dbus paths from nodes queue. |
931 | - // queue may grow as new paths are discovered. |
932 | - while (nodes.length > 0) { |
933 | - DBusObjectAddress node = nodes.pop_head(); |
934 | - |
935 | - current_dbus_name = node.dbus_name; |
936 | - current_dbus_path = node.dbus_path; |
937 | - |
938 | - try { |
939 | - Variant v = bus.call_sync(current_dbus_name, |
940 | - current_dbus_path, |
941 | - "org.freedesktop.DBus.Introspectable", |
942 | - "Introspect", |
943 | - null, |
944 | - vt, |
945 | - 0, |
946 | - 10, |
947 | - null); |
948 | - |
949 | - if (v != null) { |
950 | - string xmldata = v.get_child_value(0).get_string(); |
951 | - var context = new MarkupParseContext (parser, MarkupParseFlags.TREAT_CDATA_AS_TEXT, this, null); |
952 | - context.parse (xmldata, xmldata.length); |
953 | - } |
954 | - } |
955 | - catch (Error e) { |
956 | - // silently ignore |
957 | - } |
958 | - |
959 | - Idle.add(findLenses.callback); |
960 | - yield; |
961 | - } |
962 | + if (lens_dbusname_regex == null) { |
963 | + stderr.printf("Invalid lens_dbusname_regex"); |
964 | + return lenses; |
965 | + } |
966 | + |
967 | + var bus = Bus.get_sync (BusType.SESSION); |
968 | + var vt = new VariantType ("(s)"); |
969 | + |
970 | + // |
971 | + // Service filtering - potential lenses must match this regexp; |
972 | + // e.g. com.canonical.Unity.Lens.applications.T1338793992370.Results |
973 | + foreach (string srv in getServices()) { |
974 | + if (lens_dbusname_regex.match(srv)) { |
975 | + try { |
976 | + var vb = new VariantBuilder(new VariantType("(s)")); |
977 | + vb.add_value(srv); |
978 | + |
979 | + Variant v = bus.call_sync( |
980 | + "org.freedesktop.DBus", |
981 | + "/", |
982 | + "org.freedesktop.DBus", |
983 | + "GetNameOwner", |
984 | + vb.end(), |
985 | + vt, |
986 | + 0, |
987 | + 10, |
988 | + null); |
989 | + |
990 | + if (v != null) { |
991 | + string owner = v.get_child_value(0).get_string(); |
992 | + if (owner != null) { |
993 | + DBusObjectAddress obj = DBusObjectAddress() { |
994 | + dbus_name = owner, |
995 | + dbus_path = "/" |
996 | + }; |
997 | + nodes.push_tail(obj); |
998 | + } |
999 | + } |
1000 | + } |
1001 | + catch (Error e) { |
1002 | + // silently ignore |
1003 | + } |
1004 | + |
1005 | + } |
1006 | + } |
1007 | + |
1008 | + // |
1009 | + // introspect all dbus paths from nodes queue. |
1010 | + // queue may grow as new paths are discovered. |
1011 | + while (nodes.length > 0) { |
1012 | + DBusObjectAddress node = nodes.pop_head(); |
1013 | + |
1014 | + current_dbus_name = node.dbus_name; |
1015 | + current_dbus_path = node.dbus_path; |
1016 | + |
1017 | + try { |
1018 | + Variant v = bus.call_sync(current_dbus_name, |
1019 | + current_dbus_path, |
1020 | + "org.freedesktop.DBus.Introspectable", |
1021 | + "Introspect", |
1022 | + null, |
1023 | + vt, |
1024 | + 0, |
1025 | + 10, |
1026 | + null); |
1027 | + |
1028 | + if (v != null) { |
1029 | + string xmldata = v.get_child_value(0).get_string(); |
1030 | + var context = new MarkupParseContext (parser, MarkupParseFlags.TREAT_CDATA_AS_TEXT, this, null); |
1031 | + context.parse (xmldata, xmldata.length); |
1032 | + } |
1033 | + } |
1034 | + catch (Error e) { |
1035 | + // silently ignore |
1036 | + } |
1037 | + |
1038 | + Idle.add(findLenses.callback); |
1039 | + yield; |
1040 | + } |
1041 | |
1042 | return lenses; |
1043 | } |
1044 | |
1045 | === modified file 'tools/unity-tool-ui.vala' |
1046 | --- tools/unity-tool-ui.vala 2012-06-13 15:32:55 +0000 |
1047 | +++ tools/unity-tool-ui.vala 2012-08-14 14:17:21 +0000 |
1048 | @@ -43,34 +43,48 @@ |
1049 | uimodel = builder.get_object("results_model") as ListStore; |
1050 | ui_filter_model = builder.get_object("filters_model") as ListStore; |
1051 | |
1052 | + notebook = builder.get_object("notebook") as Notebook; |
1053 | search_entry = builder.get_object("search_entry") as Entry; |
1054 | search_type_global_rbutton = builder.get_object("search_type_global") as RadioButton; |
1055 | search_button = builder.get_object("search_button") as Button; |
1056 | + results_button = builder.get_object("results_button") as Button; |
1057 | + prev_preview_button = builder.get_object("prev_preview_btn") as Button; |
1058 | + next_preview_button = builder.get_object("next_preview_btn") as Button; |
1059 | statusbar = builder.get_object("statusbar") as Statusbar; |
1060 | log_buffer = builder.get_object("log_buffer") as TextBuffer; |
1061 | + preview_raw_data = builder.get_object("preview_raw_data") as TextBuffer; |
1062 | + preview_buttons_container = builder.get_object("preview_buttons_container") as Alignment; |
1063 | + preview_extra_buttons_container = builder.get_object("preview_extra_buttons_container") as Alignment; |
1064 | + preview_viewport = builder.get_object("preview_viewport") as Viewport; |
1065 | + assert(preview_viewport != null); |
1066 | + |
1067 | + results_view = builder.get_object("results_view") as TreeView; |
1068 | + results_view_selection = builder.get_object("results_view_selection") as TreeSelection; |
1069 | + results_popup_menu = builder.get_object("results_popup_menu") as Gtk.Menu; |
1070 | |
1071 | statusbar_info_ctx = statusbar.get_context_id("Info"); |
1072 | statusbar_error_ctx = statusbar.get_context_id("Error"); |
1073 | |
1074 | + show_no_preview(); |
1075 | show_connect_dialog(); |
1076 | } |
1077 | catch (GLib.Error e) { |
1078 | ui_load_error(e.message); |
1079 | - return false; |
1080 | + return false; |
1081 | } |
1082 | return true; |
1083 | } |
1084 | |
1085 | - private void ui_load_error(string message) |
1086 | - { |
1087 | - Gtk.Dialog dlg = new Gtk.MessageDialog(null, |
1088 | + private void ui_load_error(string message) |
1089 | + { |
1090 | + Gtk.Dialog dlg = new Gtk.MessageDialog(null, |
1091 | Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL, |
1092 | Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, |
1093 | "Error loading UI file:\n%s".printf(message)); |
1094 | - dlg.title = "Error creating UI"; |
1095 | - dlg.run(); |
1096 | - dlg.destroy(); |
1097 | - } |
1098 | + dlg.title = "Error creating UI"; |
1099 | + dlg.run(); |
1100 | + dlg.destroy(); |
1101 | + } |
1102 | |
1103 | private void discover_lens() |
1104 | { |
1105 | @@ -94,7 +108,7 @@ |
1106 | stderr.printf("DBus Lens auto-discovery failed %s\n", e.message); |
1107 | lens_discovery_spinner.stop(); |
1108 | } |
1109 | - }); |
1110 | + }); |
1111 | } |
1112 | |
1113 | [CCode (instance_pos = -1)] |
1114 | @@ -113,37 +127,50 @@ |
1115 | } |
1116 | |
1117 | // |
1118 | - // 'New' menu action handler |
1119 | + // Handler for File > New menu item. |
1120 | [CCode (instance_pos = -1)] |
1121 | public void on_connect_clicked(Gtk.MenuItem item) |
1122 | { |
1123 | show_connect_dialog(); |
1124 | } |
1125 | |
1126 | + /** |
1127 | + * Handler for Edit > Clear Log menu item. |
1128 | + */ |
1129 | + [CCode (instance_pos = -1)] |
1130 | + public void on_clear_log_clicked(Gtk.MenuItem item) |
1131 | + { |
1132 | + Gtk.TextIter start; |
1133 | + Gtk.TextIter end; |
1134 | + log_buffer.get_start_iter(out start); |
1135 | + log_buffer.get_end_iter(out end); |
1136 | + log_buffer.delete(ref start, ref end); |
1137 | + } |
1138 | + |
1139 | private void show_connect_dialog() |
1140 | { |
1141 | var builder = new Builder (); |
1142 | - try { |
1143 | - builder.add_from_resource("/com/canonical/Unity/unity-tool/dbus-lens-connect.ui"); |
1144 | - builder.connect_signals(this); |
1145 | - lens_discovery_spinner = builder.get_object("lens_discovery_spinner") as Spinner; |
1146 | - lens_list_model = builder.get_object("lens_list_model") as ListStore; |
1147 | - lens_list_combobox = builder.get_object("lens_list_combobox") as ComboBox; |
1148 | - dbus_name_entry = builder.get_object("dbus_name_entry") as Entry; |
1149 | - dbus_path_entry = builder.get_object("dbus_path_entry") as Entry; |
1150 | - lens_connect_dlg = builder.get_object("lens_connect_dialog") as Dialog; |
1151 | + try { |
1152 | + builder.add_from_resource("/com/canonical/Unity/unity-tool/dbus-lens-connect.ui"); |
1153 | + builder.connect_signals(this); |
1154 | + lens_discovery_spinner = builder.get_object("lens_discovery_spinner") as Spinner; |
1155 | + lens_list_model = builder.get_object("lens_list_model") as ListStore; |
1156 | + lens_list_combobox = builder.get_object("lens_list_combobox") as ComboBox; |
1157 | + dbus_name_entry = builder.get_object("dbus_name_entry") as Entry; |
1158 | + dbus_path_entry = builder.get_object("dbus_path_entry") as Entry; |
1159 | + lens_connect_dlg = builder.get_object("lens_connect_dialog") as Dialog; |
1160 | |
1161 | - discover_lens(); |
1162 | - |
1163 | - if (Options.lens_dbus_path != null && Options.lens_dbus_path != "" && Options.lens_dbus_name != null && Options.lens_dbus_name != "") { |
1164 | - dbus_name_entry.text = Options.lens_dbus_name; |
1165 | - dbus_path_entry.text = Options.lens_dbus_path; |
1166 | - } |
1167 | - lens_connect_dlg.show_all(); |
1168 | - } |
1169 | - catch (GLib.Error e) { |
1170 | - ui_load_error(e.message); |
1171 | - } |
1172 | + discover_lens(); |
1173 | + |
1174 | + if (Options.lens_dbus_path != null && Options.lens_dbus_path != "" && Options.lens_dbus_name != null && Options.lens_dbus_name != "") { |
1175 | + dbus_name_entry.text = Options.lens_dbus_name; |
1176 | + dbus_path_entry.text = Options.lens_dbus_path; |
1177 | + } |
1178 | + lens_connect_dlg.show_all(); |
1179 | + } |
1180 | + catch (GLib.Error e) { |
1181 | + ui_load_error(e.message); |
1182 | + } |
1183 | } |
1184 | |
1185 | private void results_row_added_cb(Dee.Model model, Dee.ModelIter iter) |
1186 | @@ -153,7 +180,7 @@ |
1187 | uimodel.append(out uiiter); |
1188 | |
1189 | uimodel.set(uiiter, 0, row[0].get_string(), 1, row[1].get_string(), 2, row[2].get_uint32(), 3, row[3].get_string(), 4, row[4].get_string(), 5, |
1190 | - row[5].get_string(), 6, row[6].get_string(), -1); |
1191 | + row[5].get_string(), 6, row[6].get_string(), -1); |
1192 | } |
1193 | |
1194 | private void filters_row_added_cb(Dee.Model model, Dee.ModelIter iter) |
1195 | @@ -163,14 +190,14 @@ |
1196 | ui_filter_model.append(out uiiter); |
1197 | |
1198 | ui_filter_model.set(uiiter, 0, row[0].get_string(), 1, row[1].get_string (), 2, row[2].get_string (), 3, row[3].get_string (), 4, row[4].print(true), |
1199 | - 5, row[5].get_boolean (), 6, row[6].get_boolean (), 7, row[7].get_boolean(), -1); |
1200 | + 5, row[5].get_boolean (), 6, row[6].get_boolean (), 7, row[7].get_boolean(), -1); |
1201 | } |
1202 | |
1203 | private void update_status() |
1204 | { |
1205 | statusbar.pop(statusbar_info_ctx); |
1206 | statusbar.push(statusbar_info_ctx, "%u records".printf(dee_results_model.get_n_rows()) + ", DBus name: " + Options.lens_dbus_name + " path: " + |
1207 | - Options.lens_dbus_path); |
1208 | + Options.lens_dbus_path); |
1209 | } |
1210 | |
1211 | private void model_synchronized_cb() |
1212 | @@ -186,8 +213,35 @@ |
1213 | dee_filters_model = null; |
1214 | } |
1215 | |
1216 | + private void on_lens_service_vanished(GLib.DBusConnection connection, string name) |
1217 | + { |
1218 | + handle_error("Disconnected from %s".printf(name)); |
1219 | + GLib.Bus.unwatch_name(dbus_watcher_id); |
1220 | + dbus_watcher_id = 0; |
1221 | + lens_proxy = null; |
1222 | + |
1223 | + clear_data(); |
1224 | + remove_preview(); |
1225 | + show_no_preview(); |
1226 | + |
1227 | + disable_ui_actions_on_error_condition(); |
1228 | + } |
1229 | + |
1230 | + private void disable_ui_actions_on_error_condition() |
1231 | + { |
1232 | + if (lens_proxy == null || Options.lens_dbus_path == null || Options.lens_dbus_path.length == 0 || Options.lens_dbus_name == null || Options.lens_dbus_name.length == 0) { |
1233 | + search_entry.sensitive = false; |
1234 | + results_button.sensitive = false; |
1235 | + search_button.sensitive = false; |
1236 | + } else { |
1237 | + search_entry.sensitive = true; |
1238 | + results_button.sensitive = true; |
1239 | + search_button.sensitive = true; |
1240 | + } |
1241 | + } |
1242 | + |
1243 | /** |
1244 | - * Triggered clicking 'Ok' in the connection dialog. |
1245 | + * Triggered by clicking 'Ok' in the connection dialog. |
1246 | */ |
1247 | [CCode (instance_pos = -1)] |
1248 | public void on_lens_connect(Gtk.Dialog dlg, int response) |
1249 | @@ -195,16 +249,43 @@ |
1250 | // |
1251 | // user clicked 'Ok' in the Lens Connect dialog |
1252 | if (response == 1) { |
1253 | + clear_data(); |
1254 | + remove_preview(); |
1255 | + show_no_preview(); |
1256 | + |
1257 | Options.lens_dbus_name = dbus_name_entry.text; |
1258 | Options.lens_dbus_path = dbus_path_entry.text; |
1259 | - } |
1260 | - if (Options.lens_dbus_path == null || Options.lens_dbus_path.length == 0 || Options.lens_dbus_name == null || Options.lens_dbus_name.length == 0) { |
1261 | - search_entry.sensitive = false; |
1262 | - search_button.sensitive = false; |
1263 | - } else { |
1264 | - search_entry.sensitive = true; |
1265 | - search_button.sensitive = true; |
1266 | - } |
1267 | + |
1268 | + lens_proxy = null; |
1269 | + DBusConnection? bus = null; |
1270 | + |
1271 | + try |
1272 | + { |
1273 | + bus = Bus.get_sync(BusType.SESSION); |
1274 | + lens_proxy = bus.get_proxy_sync<Protocol.LensService>(Options.lens_dbus_name, Options.lens_dbus_path); |
1275 | + |
1276 | + if (dbus_watcher_id > 0) { |
1277 | + GLib.Bus.unwatch_name(dbus_watcher_id); |
1278 | + } |
1279 | + dbus_watcher_id = GLib.Bus.watch_name(GLib.BusType.SESSION, Options.lens_dbus_name, GLib.BusNameWatcherFlags.AUTO_START, null, on_lens_service_vanished); |
1280 | + |
1281 | + lens_proxy.changed.connect((info) => { |
1282 | + string model_name = search_type_global_rbutton.get_active() ? info.global_results_model_name : info.results_model_name; |
1283 | + dee_results_model = new Dee.SharedModel(model_name); |
1284 | + model_sync_sig_id = dee_results_model.notify["synchronized"].connect(model_synchronized_cb); |
1285 | + dee_results_model.row_added.connect(results_row_added_cb); |
1286 | + |
1287 | + dee_filters_model = new Dee.SharedModel(info.filters_model_name); |
1288 | + filters_model_sync_sig_id = dee_filters_model.notify["synchronized"].connect(filter_model_synchronized_cb); |
1289 | + dee_filters_model.row_added.connect(filters_row_added_cb); |
1290 | + }); |
1291 | + append_log_message("Connected to: %s, %s\n".printf(Options.lens_dbus_name, Options.lens_dbus_path)); |
1292 | + } |
1293 | + catch (GLib.IOError e) { |
1294 | + handle_error(e.message); |
1295 | + } |
1296 | + } |
1297 | + disable_ui_actions_on_error_condition(); |
1298 | dlg.destroy(); |
1299 | } |
1300 | |
1301 | @@ -222,20 +303,20 @@ |
1302 | var file_chooser = new FileChooserDialog("Open Lens file", null, Gtk.FileChooserAction.OPEN, Gtk.Stock.CANCEL, 0, Gtk.Stock.OPEN, 1); |
1303 | file_chooser.set_filter(filter); |
1304 | if (file_chooser.run() == 1) { |
1305 | - try { |
1306 | - get_lens_params_from_file(file_chooser.get_filename()); |
1307 | - dbus_name_entry.text = Options.lens_dbus_name; |
1308 | - dbus_path_entry.text = Options.lens_dbus_path; |
1309 | - } |
1310 | - catch (Error e) { |
1311 | - Gtk.Dialog dlg = new Gtk.MessageDialog(null, |
1312 | - Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL, |
1313 | - Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, |
1314 | - "Error loading lens parameters from file:\n%s".printf(e.message)); |
1315 | - dlg.title = "Error loading lens file"; |
1316 | - dlg.run(); |
1317 | - dlg.destroy(); |
1318 | - } |
1319 | + try { |
1320 | + get_lens_params_from_file(file_chooser.get_filename()); |
1321 | + dbus_name_entry.text = Options.lens_dbus_name; |
1322 | + dbus_path_entry.text = Options.lens_dbus_path; |
1323 | + } |
1324 | + catch (Error e) { |
1325 | + Gtk.Dialog dlg = new Gtk.MessageDialog(null, |
1326 | + Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL, |
1327 | + Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, |
1328 | + "Error loading lens parameters from file:\n%s".printf(e.message)); |
1329 | + dlg.title = "Error loading lens file"; |
1330 | + dlg.run(); |
1331 | + dlg.destroy(); |
1332 | + } |
1333 | } |
1334 | file_chooser.destroy(); |
1335 | } |
1336 | @@ -251,12 +332,19 @@ |
1337 | } |
1338 | |
1339 | /** |
1340 | - * Request lens info via debus, creates dee models. |
1341 | + * Request lens info via dbus, creates dee models. |
1342 | */ |
1343 | private void request_lens_info() |
1344 | { |
1345 | spinner.start(); |
1346 | - |
1347 | + lens_proxy.info_request(); |
1348 | + } |
1349 | + |
1350 | + /** |
1351 | + * Clears all models, removing all search results. |
1352 | + */ |
1353 | + private void clear_data() |
1354 | + { |
1355 | if (dee_filters_model != null) { |
1356 | dee_filters_model = null; |
1357 | } |
1358 | @@ -265,21 +353,13 @@ |
1359 | } |
1360 | uimodel.clear(); |
1361 | ui_filter_model.clear(); |
1362 | - |
1363 | - LensInfo info = get_lens_info((msg) => { handle_error(msg); }); |
1364 | - string model_name = search_type_global_rbutton.get_active() ? info.global_results_model_name : info.results_model_name; |
1365 | - dee_results_model = new Dee.SharedModel(model_name); |
1366 | - model_sync_sig_id = dee_results_model.notify["synchronized"].connect(model_synchronized_cb); |
1367 | - dee_results_model.row_added.connect(results_row_added_cb); |
1368 | - |
1369 | - dee_filters_model = new Dee.SharedModel(info.filters_model_name); |
1370 | - filters_model_sync_sig_id = dee_filters_model.notify["synchronized"].connect(filter_model_synchronized_cb); |
1371 | - dee_filters_model.row_added.connect(filters_row_added_cb); |
1372 | } |
1373 | |
1374 | [CCode (instance_pos = -1)] |
1375 | public void on_results_button_clicked(Gtk.Button btn) |
1376 | { |
1377 | + clear_data(); |
1378 | + remove_preview(); |
1379 | request_lens_info(); |
1380 | } |
1381 | |
1382 | @@ -290,29 +370,71 @@ |
1383 | public void on_search_button_clicked(Gtk.Button btn) |
1384 | { |
1385 | string text = search_entry.text; |
1386 | - if (text != "") { |
1387 | - spinner.start(); |
1388 | + spinner.start(); |
1389 | |
1390 | - if (DBus.is_name(Options.lens_dbus_name) && GLib.Variant.is_object_path(Options.lens_dbus_path)) { |
1391 | - append_log_message("Query: '%s' (%s), DBus name: %s, DBus path: %s\n".printf( |
1392 | - text, |
1393 | - search_type_global_rbutton.get_active() ? "global" : "local", |
1394 | - Options.lens_dbus_name, |
1395 | - Options.lens_dbus_path)); |
1396 | - call_lens_search(text, search_type_global_rbutton.get_active() ? 1 : 0, (result) => |
1397 | - { |
1398 | - append_log_message(result.print(true) + "\n"); |
1399 | - request_lens_info(); |
1400 | - }, (msg) => { |
1401 | - handle_error(msg); |
1402 | - } |
1403 | - ); |
1404 | + if (DBus.is_name(Options.lens_dbus_name) && GLib.Variant.is_object_path(Options.lens_dbus_path)) { |
1405 | + append_log_message("Query: '%s' (%s), DBus name: %s, DBus path: %s\n".printf( |
1406 | + text, |
1407 | + search_type_global_rbutton.get_active() ? "global" : "local", |
1408 | + Options.lens_dbus_name, |
1409 | + Options.lens_dbus_path)); |
1410 | + |
1411 | + remove_preview(); |
1412 | + show_no_preview(); |
1413 | + clear_data(); |
1414 | + |
1415 | + if (search_type_global_rbutton.get_active()) { |
1416 | + lens_proxy.global_search.begin(text, new HashTable<string, Variant>(null, null), |
1417 | + (obj, res) => { |
1418 | + try { |
1419 | + var result = lens_proxy.global_search.end(res); |
1420 | + append_log_message("Search reply: " + dump_ht_reply(result) + "\n"); |
1421 | + request_lens_info(); |
1422 | + } |
1423 | + catch (Error e) { |
1424 | + handle_error(e.message); |
1425 | + } |
1426 | + }); |
1427 | } else { |
1428 | - handle_error("Invalid DBus name/path"); |
1429 | + lens_proxy.search.begin(text, new HashTable<string, Variant>(null, null), |
1430 | + (obj, res) => { |
1431 | + try { |
1432 | + var result = lens_proxy.search.end(res); |
1433 | + append_log_message("Search reply: " + dump_ht_reply(result) + "\n"); |
1434 | + request_lens_info(); |
1435 | + } |
1436 | + catch (Error e) { |
1437 | + handle_error(e.message); |
1438 | + } |
1439 | + }); |
1440 | } |
1441 | + } else { |
1442 | + handle_error("Invalid DBus name/path"); |
1443 | } |
1444 | } |
1445 | |
1446 | + private static string dump_ht_reply(HashTable<string, Variant> reply) |
1447 | + { |
1448 | + var bld = new StringBuilder("{\n"); |
1449 | + reply.foreach((k, v) => { |
1450 | + bld.append_printf("\t%s = %s", k, v.print(true)); |
1451 | + }); |
1452 | + bld.append("\n}"); |
1453 | + return bld.str; |
1454 | + } |
1455 | + |
1456 | + private static string dump_activation_reply(Unity.Protocol.ActivationReplyRaw reply) |
1457 | + { |
1458 | + var bld = new StringBuilder(); |
1459 | + string handled_str = ((EnumClass) typeof (Unity.HandledType).class_ref()).get_value((int)reply.handled).value_name; |
1460 | + bld.append_printf("ActivationReplyRaw: {\n\turi=%s,\n\thandled=%s,\n\thints={\n\t", reply.uri, handled_str); |
1461 | + reply.hints.foreach((k, v) => { |
1462 | + bld.append_printf("\t\t%s = %s", k, v.print(true)); |
1463 | + }); |
1464 | + bld.append("\n\t}\n}"); |
1465 | + return bld.str; |
1466 | + } |
1467 | + |
1468 | /** |
1469 | * Helper method that stops spinner and puts error message on statusbar. |
1470 | */ |
1471 | @@ -324,11 +446,321 @@ |
1472 | append_log_message(message + "\n"); |
1473 | } |
1474 | |
1475 | + /** |
1476 | + * Helper method to workaround vala-0.16 & vala-0.17 bug - |
1477 | + * fix is coming to vala - see http://git.gnome.org/browse/vala/commit/?id=79925e1174d62d740ca8f360f489dd1660ea5881 |
1478 | + */ |
1479 | + private async void send_activate (string uri, uint action_type, out Unity.Protocol.ActivationReplyRaw reply) throws GLib.IOError |
1480 | + { |
1481 | + reply = yield lens_proxy.activate (uri, action_type); |
1482 | + } |
1483 | + |
1484 | + private async void send_update (string uri, HashTable<string, Variant> props, out HashTable<string, Variant> reply) throws GLib.IOError |
1485 | + { |
1486 | + reply = yield lens_proxy.update_preview_property (preview_scope_uri, props); |
1487 | + } |
1488 | + |
1489 | + private void activate_preview(string preview_uri) |
1490 | + { |
1491 | + // call lens activate over dbus |
1492 | + Unity.Protocol.ActivationReplyRaw? reply_struct = null; |
1493 | + send_activate.begin(preview_uri, |
1494 | + Unity.Protocol.ActionType.PREVIEW_RESULT, |
1495 | + (obj, res) => { |
1496 | + try { |
1497 | + send_activate.end(res, out reply_struct); |
1498 | + preview_scope_uri = reply_struct.uri; |
1499 | + handle_activation_reply(reply_struct); |
1500 | + notebook.set_current_page(2); //activate 'Preview' tab |
1501 | + } |
1502 | + catch (GLib.IOError e) { |
1503 | + handle_error(e.message); |
1504 | + } |
1505 | + }); |
1506 | + } |
1507 | + |
1508 | + private void update_next_prev_buttons(TreeModel model, TreeIter cur_iter) |
1509 | + { |
1510 | + TreeIter iter; |
1511 | + |
1512 | + iter = cur_iter; |
1513 | + prev_preview_button.sensitive = model.iter_previous(ref iter); |
1514 | + iter = cur_iter; |
1515 | + next_preview_button.sensitive = model.iter_next(ref iter); |
1516 | + } |
1517 | + |
1518 | + /** |
1519 | + * Handler for 'Request preview' context menu item. |
1520 | + */ |
1521 | + [CCode (instance_pos = -1)] |
1522 | + public void on_request_preview(Gtk.MenuItem item) |
1523 | + { |
1524 | + TreeModel model; |
1525 | + TreeIter iter; |
1526 | + if (results_view_selection.get_selected(out model, out iter)) { |
1527 | + Value val; |
1528 | + last_active_model = model; |
1529 | + last_active_iter = iter; |
1530 | + // get value from uri column |
1531 | + model.get_value(iter, 0, out val); |
1532 | + activate_preview(val.get_string()); |
1533 | + update_next_prev_buttons(model, iter); |
1534 | + } |
1535 | + } |
1536 | + |
1537 | + /** |
1538 | + * Handler for 'Request preview' context menu item. |
1539 | + */ |
1540 | + [CCode (instance_pos = -1)] |
1541 | + public void on_prev_preview_clicked(Gtk.Button button) |
1542 | + requires (last_active_model != null) |
1543 | + { |
1544 | + TreeModel model = last_active_model; |
1545 | + TreeIter iter = last_active_iter; |
1546 | + if (last_active_model.iter_previous (ref iter)) { |
1547 | + Value val; |
1548 | + last_active_iter = iter; |
1549 | + // get value from uri column |
1550 | + model.get_value(iter, 0, out val); |
1551 | + activate_preview(val.get_string()); |
1552 | + update_next_prev_buttons(model, iter); |
1553 | + } |
1554 | + } |
1555 | + /** |
1556 | + * Handler for 'Request preview' context menu item. |
1557 | + */ |
1558 | + [CCode (instance_pos = -1)] |
1559 | + public void on_next_preview_clicked(Gtk.MenuItem item) |
1560 | + requires (last_active_model != null) |
1561 | + { |
1562 | + TreeModel model = last_active_model; |
1563 | + TreeIter iter = last_active_iter; |
1564 | + if (last_active_model.iter_next (ref iter)) { |
1565 | + Value val; |
1566 | + last_active_iter = iter; |
1567 | + // get value from uri column |
1568 | + model.get_value(iter, 0, out val); |
1569 | + activate_preview(val.get_string()); |
1570 | + update_next_prev_buttons(model, iter); |
1571 | + } |
1572 | + } |
1573 | + /** |
1574 | + * Handler for 'Activate result' context menu item. |
1575 | + */ |
1576 | + [CCode (instance_pos = -1)] |
1577 | + public void on_activate_result(Gtk.MenuItem item) |
1578 | + { |
1579 | + TreeModel model; |
1580 | + TreeIter iter; |
1581 | + if (results_view_selection.get_selected(out model, out iter)) { |
1582 | + Value val; |
1583 | + // get value from uri column |
1584 | + model.get_value(iter, 0, out val); |
1585 | + |
1586 | + // |
1587 | + // call lens activate over dbus |
1588 | + // |
1589 | + Unity.Protocol.ActivationReplyRaw? reply_struct = null; |
1590 | + send_activate.begin(val.get_string(), Unity.Protocol.ActionType.ACTIVATE_RESULT, (obj, res) => { |
1591 | + try { |
1592 | + send_activate.end(res, out reply_struct); |
1593 | + handle_activation_reply(reply_struct); |
1594 | + } |
1595 | + catch (GLib.IOError e) { |
1596 | + handle_error(e.message); |
1597 | + } |
1598 | + }); |
1599 | + } |
1600 | + } |
1601 | + |
1602 | + /** |
1603 | + * Render preview and action buttons depending on preview type (if applicable); log reply. |
1604 | + */ |
1605 | + private void handle_activation_reply(Unity.Protocol.ActivationReplyRaw reply_struct) |
1606 | + { |
1607 | + append_log_message("Activate reply: " + dump_activation_reply(reply_struct) + "\n"); |
1608 | + |
1609 | + if (reply_struct.handled == Unity.HandledType.SHOW_PREVIEW) { |
1610 | + if (reply_struct.hints.contains("preview")) { |
1611 | + handle_preview(reply_struct.hints["preview"]); |
1612 | + } else { |
1613 | + handle_error("Reply hints don't contain preview element"); |
1614 | + } |
1615 | + } else { |
1616 | + remove_preview(); |
1617 | + show_no_preview(); |
1618 | + } |
1619 | + } |
1620 | + |
1621 | + private void handle_preview(Variant preview_var) |
1622 | + { |
1623 | + Unity.Protocol.Preview? reconstructed = Unity.Protocol.Preview.parse(preview_var); |
1624 | + preview_raw_data.set_text(preview_var.print(true)); |
1625 | + preview_renderer = PreviewRenderer.create(reconstructed, preview_scope_uri); |
1626 | + update_preview(); |
1627 | + } |
1628 | + |
1629 | + private void update_preview() |
1630 | + { |
1631 | + remove_preview(); |
1632 | + |
1633 | + if (preview_renderer != null) { |
1634 | + preview_renderer.preview_action_clicked.connect(on_preview_action_clicked); |
1635 | + if (preview_renderer is SeriesPreviewRenderer) { |
1636 | + ((SeriesPreviewRenderer)preview_renderer).change_selected_series_item_clicked.connect(on_change_selected_series_item_clicked); |
1637 | + } |
1638 | + else if (preview_renderer is MusicPreviewRenderer) { |
1639 | + var renderer = preview_renderer as MusicPreviewRenderer; |
1640 | + renderer.play_music_track_clicked.connect(on_play_music_track_clicked); |
1641 | + renderer.pause_music_track_clicked.connect(on_pause_music_track_clicked); |
1642 | + } |
1643 | + preview_viewport.add_with_properties(preview_renderer.get_widget()); |
1644 | + preview_viewport.show_all(); |
1645 | + |
1646 | + preview_buttons_container.add_with_properties(preview_renderer.get_buttons()); |
1647 | + preview_buttons_container.show_all(); |
1648 | + |
1649 | + preview_extra_buttons_container.add_with_properties(preview_renderer.get_extra_buttons()); |
1650 | + preview_extra_buttons_container.show_all(); |
1651 | + } else { |
1652 | + handle_error("Unknown preview type"); |
1653 | + show_no_preview(); |
1654 | + } |
1655 | + } |
1656 | + |
1657 | + private void show_no_preview() |
1658 | + { |
1659 | + preview_renderer = null; |
1660 | + |
1661 | + preview_raw_data.set_text(""); |
1662 | + var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); |
1663 | + var label = new Gtk.Label("No preview"); |
1664 | + box.pack_start(label); |
1665 | + preview_viewport.add_with_properties(box); |
1666 | + box.show_all(); |
1667 | + } |
1668 | + |
1669 | + /** |
1670 | + * Destroys all preview objects in the 'Render' tab. |
1671 | + */ |
1672 | + private void remove_preview() |
1673 | + { |
1674 | + preview_viewport.foreach((obj) => { obj.destroy(); }); |
1675 | + |
1676 | + // remove preview buttons |
1677 | + preview_buttons_container.foreach((btn) => { btn.destroy(); }); |
1678 | + preview_extra_buttons_container.foreach((btn) => { btn.destroy(); }); |
1679 | + } |
1680 | + |
1681 | + private void on_preview_action_clicked(PreviewRenderer renderer, string uri) |
1682 | + { |
1683 | + Unity.Protocol.ActivationReplyRaw? reply_struct = null; |
1684 | + send_activate.begin(uri, Unity.Protocol.ActionType.PREVIEW_ACTION, (obj, res) => { |
1685 | + try { |
1686 | + send_activate.end(res, out reply_struct); |
1687 | + handle_activation_reply(reply_struct); |
1688 | + } |
1689 | + catch (GLib.IOError e) { |
1690 | + handle_error(e.message); |
1691 | + } |
1692 | + }); |
1693 | + } |
1694 | + |
1695 | + private void on_play_music_track_clicked(MusicPreviewRenderer renderer, string uri) |
1696 | + { |
1697 | + renderer.preview.begin_updates(); |
1698 | + (renderer.preview as Unity.Protocol.MusicPreview).play_uri(uri); |
1699 | + handle_music_track_signals(renderer.preview.end_updates_as_hashtable()); |
1700 | + } |
1701 | + |
1702 | + private void on_pause_music_track_clicked(MusicPreviewRenderer renderer, string uri) |
1703 | + { |
1704 | + renderer.preview.begin_updates(); |
1705 | + (renderer.preview as Unity.Protocol.MusicPreview).pause_uri(uri); |
1706 | + handle_music_track_signals(renderer.preview.end_updates_as_hashtable()); |
1707 | + } |
1708 | + |
1709 | + private void handle_music_track_signals(HashTable<string, Variant> props) |
1710 | + { |
1711 | + HashTable<string, Variant>? ht = null; |
1712 | + send_update.begin(preview_scope_uri, props, (obj, res) => { |
1713 | + try { |
1714 | + send_update.end(res, out ht); |
1715 | + if (ht != null) { |
1716 | + append_log_message("UpdatePreviewProperty reply: " + dump_ht_reply(ht) + "\n"); //TODO: do we expect any reply? |
1717 | + } |
1718 | + } |
1719 | + catch (GLib.IOError e) { |
1720 | + handle_error(e.message); |
1721 | + } |
1722 | + }); |
1723 | + } |
1724 | + |
1725 | + private void on_change_selected_series_item_clicked(SeriesPreviewRenderer renderer, string uri, int index) |
1726 | + { |
1727 | + var props = new HashTable<string, Variant>(str_hash, str_equal); |
1728 | + props["series-active-index"] = new Variant.int32(index); |
1729 | + |
1730 | + HashTable<string, Variant>? ht = null; |
1731 | + send_update.begin(uri, props, (obj, res) => { |
1732 | + try { |
1733 | + send_update.end(res, out ht); |
1734 | + if (ht != null) { |
1735 | + append_log_message("UpdatePreviewProperty reply: " + dump_ht_reply(ht) + "\n"); |
1736 | + if (ht.contains("preview")) { |
1737 | + if (preview_renderer is SeriesPreviewRenderer) { |
1738 | + (preview_renderer as SeriesPreviewRenderer).update_child_preview(Unity.Protocol.Preview.parse(ht["preview"])); |
1739 | + update_preview(); |
1740 | + } |
1741 | + } |
1742 | + } |
1743 | + } |
1744 | + catch (GLib.IOError e) { |
1745 | + handle_error(e.message); |
1746 | + } |
1747 | + }); |
1748 | + } |
1749 | + |
1750 | + /** |
1751 | + * Handle 'Request preview' context menu action. |
1752 | + */ |
1753 | + [CCode (instance_pos = -1)] |
1754 | + public void on_results_popup_request(Gtk.Widget widget) |
1755 | + { |
1756 | + } |
1757 | + |
1758 | + /** |
1759 | + * Handles right mouse button click event in 'Results' tab. |
1760 | + */ |
1761 | + [CCode (instance_pos = -1)] |
1762 | + public bool on_results_right_click(Gtk.Widget widget, Gdk.EventButton event) |
1763 | + { |
1764 | + if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3 /* right mouse button */) { |
1765 | + results_popup_menu.popup(null, null, null, event.button, event.time); |
1766 | + } |
1767 | + return false; |
1768 | + } |
1769 | + |
1770 | + private PreviewRenderer preview_renderer = null; |
1771 | + private Protocol.LensService lens_proxy = null; |
1772 | + private uint dbus_watcher_id = 0; |
1773 | + private string preview_scope_uri; |
1774 | + private Gtk.Notebook notebook = null; |
1775 | + private Gtk.Viewport preview_viewport = null; |
1776 | + private Gtk.TreeSelection results_view_selection = null; |
1777 | + private Gtk.Alignment preview_buttons_container = null; |
1778 | + private Gtk.Alignment preview_extra_buttons_container = null; |
1779 | + private Gtk.TextBuffer preview_raw_data = null; |
1780 | + private Gtk.Menu results_popup_menu = null; |
1781 | + private Gtk.TreeView results_view = null; |
1782 | private Gtk.RadioButton search_type_global_rbutton = null; |
1783 | private Gtk.Dialog lens_connect_dlg = null; |
1784 | private Gtk.Spinner spinner = null; |
1785 | private Gtk.Spinner lens_discovery_spinner = null; |
1786 | private Gtk.Button search_button = null; |
1787 | + private Gtk.Button results_button = null; |
1788 | + private Gtk.Button prev_preview_button = null; |
1789 | + private Gtk.Button next_preview_button = null; |
1790 | private Gtk.Statusbar statusbar = null; |
1791 | private Gtk.TextBuffer log_buffer = null; |
1792 | private uint statusbar_info_ctx; |
1793 | @@ -344,6 +776,8 @@ |
1794 | private ulong filters_model_sync_sig_id; |
1795 | private Dee.SharedModel? dee_results_model = null; |
1796 | private Dee.SharedModel? dee_filters_model = null; |
1797 | + private TreeModel? last_active_model = null; |
1798 | + private TreeIter? last_active_iter = null; |
1799 | } |
1800 | |
1801 | } |
1802 | |
1803 | === modified file 'tools/unity-tool.ui' |
1804 | --- tools/unity-tool.ui 2012-06-05 10:02:21 +0000 |
1805 | +++ tools/unity-tool.ui 2012-08-14 14:17:21 +0000 |
1806 | @@ -22,6 +22,7 @@ |
1807 | </columns> |
1808 | </object> |
1809 | <object class="GtkTextBuffer" id="log_buffer"/> |
1810 | + <object class="GtkTextBuffer" id="preview_raw_data"/> |
1811 | <object class="GtkListStore" id="results_model"> |
1812 | <columns> |
1813 | <!-- column-name col1 --> |
1814 | @@ -40,6 +41,30 @@ |
1815 | <column type="gchararray"/> |
1816 | </columns> |
1817 | </object> |
1818 | + <object class="GtkMenu" id="results_popup_menu"> |
1819 | + <property name="visible">True</property> |
1820 | + <property name="can_focus">False</property> |
1821 | + <child> |
1822 | + <object class="GtkMenuItem" id="activate_result"> |
1823 | + <property name="use_action_appearance">False</property> |
1824 | + <property name="visible">True</property> |
1825 | + <property name="can_focus">False</property> |
1826 | + <property name="label" translatable="yes">Activate result</property> |
1827 | + <property name="use_underline">True</property> |
1828 | + <signal name="activate" handler="unity_tester_unity_tool_ui_on_activate_result" swapped="no"/> |
1829 | + </object> |
1830 | + </child> |
1831 | + <child> |
1832 | + <object class="GtkMenuItem" id="request_preview"> |
1833 | + <property name="use_action_appearance">False</property> |
1834 | + <property name="visible">True</property> |
1835 | + <property name="can_focus">False</property> |
1836 | + <property name="label" translatable="yes">Request preview</property> |
1837 | + <property name="use_underline">True</property> |
1838 | + <signal name="activate" handler="unity_tester_unity_tool_ui_on_request_preview" swapped="no"/> |
1839 | + </object> |
1840 | + </child> |
1841 | + </object> |
1842 | <object class="GtkWindow" id="window"> |
1843 | <property name="can_focus">False</property> |
1844 | <property name="title" translatable="yes">Libunity Tool</property> |
1845 | @@ -99,6 +124,31 @@ |
1846 | </child> |
1847 | </object> |
1848 | </child> |
1849 | + <child> |
1850 | + <object class="GtkMenuItem" id="menuitem2"> |
1851 | + <property name="use_action_appearance">False</property> |
1852 | + <property name="visible">True</property> |
1853 | + <property name="can_focus">False</property> |
1854 | + <property name="label" translatable="yes">_Edit</property> |
1855 | + <property name="use_underline">True</property> |
1856 | + <child type="submenu"> |
1857 | + <object class="GtkMenu" id="menu2"> |
1858 | + <property name="visible">True</property> |
1859 | + <property name="can_focus">False</property> |
1860 | + <child> |
1861 | + <object class="GtkMenuItem" id="menuitem3"> |
1862 | + <property name="use_action_appearance">False</property> |
1863 | + <property name="visible">True</property> |
1864 | + <property name="can_focus">False</property> |
1865 | + <property name="label" translatable="yes">Clear Log</property> |
1866 | + <property name="use_underline">True</property> |
1867 | + <signal name="activate" handler="unity_tester_unity_tool_ui_on_clear_log_clicked" swapped="no"/> |
1868 | + </object> |
1869 | + </child> |
1870 | + </object> |
1871 | + </child> |
1872 | + </object> |
1873 | + </child> |
1874 | </object> |
1875 | <packing> |
1876 | <property name="expand">False</property> |
1877 | @@ -110,6 +160,7 @@ |
1878 | <object class="GtkBox" id="box2"> |
1879 | <property name="visible">True</property> |
1880 | <property name="can_focus">False</property> |
1881 | + <property name="border_width">6</property> |
1882 | <child> |
1883 | <object class="GtkBox" id="box3"> |
1884 | <property name="visible">True</property> |
1885 | @@ -281,16 +332,18 @@ |
1886 | </packing> |
1887 | </child> |
1888 | <child> |
1889 | - <object class="GtkNotebook" id="notebook1"> |
1890 | + <object class="GtkNotebook" id="notebook"> |
1891 | <property name="visible">True</property> |
1892 | <property name="can_focus">True</property> |
1893 | + <property name="margin_left">6</property> |
1894 | + <property name="margin_right">6</property> |
1895 | <child> |
1896 | <object class="GtkScrolledWindow" id="scrolledwindow1"> |
1897 | <property name="visible">True</property> |
1898 | - <property name="can_focus">True</property> |
1899 | + <property name="can_focus">False</property> |
1900 | <property name="shadow_type">in</property> |
1901 | <child> |
1902 | - <object class="GtkTreeView" id="treeview3"> |
1903 | + <object class="GtkTreeView" id="results_view"> |
1904 | <property name="visible">True</property> |
1905 | <property name="can_focus">True</property> |
1906 | <property name="model">results_model</property> |
1907 | @@ -298,8 +351,10 @@ |
1908 | <property name="enable_search">False</property> |
1909 | <property name="search_column">0</property> |
1910 | <property name="show_expanders">False</property> |
1911 | + <signal name="button-press-event" handler="unity_tester_unity_tool_ui_on_results_right_click" swapped="no"/> |
1912 | + <signal name="popup-menu" handler="unity_tester_unity_tool_ui_on_results_popup_request" swapped="no"/> |
1913 | <child internal-child="selection"> |
1914 | - <object class="GtkTreeSelection" id="treeview-selection1"/> |
1915 | + <object class="GtkTreeSelection" id="results_view_selection"/> |
1916 | </child> |
1917 | <child> |
1918 | <object class="GtkTreeViewColumn" id="treeviewcolumn1"> |
1919 | @@ -539,6 +594,224 @@ |
1920 | </packing> |
1921 | </child> |
1922 | <child> |
1923 | + <object class="GtkBox" id="box6"> |
1924 | + <property name="visible">True</property> |
1925 | + <property name="can_focus">False</property> |
1926 | + <child> |
1927 | + <object class="GtkButton" id="prev_preview_btn"> |
1928 | + <property name="label" translatable="yes"><<</property> |
1929 | + <property name="use_action_appearance">False</property> |
1930 | + <property name="visible">True</property> |
1931 | + <property name="sensitive">False</property> |
1932 | + <property name="can_focus">True</property> |
1933 | + <property name="receives_default">True</property> |
1934 | + <property name="use_action_appearance">False</property> |
1935 | + <signal name="clicked" handler="unity_tester_unity_tool_ui_on_prev_preview_clicked" swapped="no"/> |
1936 | + </object> |
1937 | + <packing> |
1938 | + <property name="expand">False</property> |
1939 | + <property name="fill">True</property> |
1940 | + <property name="position">0</property> |
1941 | + </packing> |
1942 | + </child> |
1943 | + <child> |
1944 | + <object class="GtkBox" id="box7"> |
1945 | + <property name="visible">True</property> |
1946 | + <property name="can_focus">False</property> |
1947 | + <property name="vexpand">True</property> |
1948 | + <property name="orientation">vertical</property> |
1949 | + <property name="spacing">10</property> |
1950 | + <child> |
1951 | + <object class="GtkFrame" id="frame1"> |
1952 | + <property name="visible">True</property> |
1953 | + <property name="can_focus">False</property> |
1954 | + <property name="label_xalign">0</property> |
1955 | + <property name="shadow_type">none</property> |
1956 | + <child> |
1957 | + <object class="GtkAlignment" id="preview_buttons_container"> |
1958 | + <property name="visible">True</property> |
1959 | + <property name="can_focus">False</property> |
1960 | + <property name="left_padding">12</property> |
1961 | + <child> |
1962 | + <placeholder/> |
1963 | + </child> |
1964 | + </object> |
1965 | + </child> |
1966 | + <child type="label"> |
1967 | + <object class="GtkLabel" id="label6"> |
1968 | + <property name="visible">True</property> |
1969 | + <property name="can_focus">False</property> |
1970 | + <property name="label" translatable="yes"><b>Preview actions</b></property> |
1971 | + <property name="use_markup">True</property> |
1972 | + </object> |
1973 | + </child> |
1974 | + </object> |
1975 | + <packing> |
1976 | + <property name="expand">False</property> |
1977 | + <property name="fill">True</property> |
1978 | + <property name="position">0</property> |
1979 | + </packing> |
1980 | + </child> |
1981 | + <child> |
1982 | + <object class="GtkSeparator" id="separator1"> |
1983 | + <property name="visible">True</property> |
1984 | + <property name="can_focus">False</property> |
1985 | + </object> |
1986 | + <packing> |
1987 | + <property name="expand">False</property> |
1988 | + <property name="fill">True</property> |
1989 | + <property name="position">1</property> |
1990 | + </packing> |
1991 | + </child> |
1992 | + <child> |
1993 | + <object class="GtkFrame" id="frame2"> |
1994 | + <property name="visible">True</property> |
1995 | + <property name="can_focus">False</property> |
1996 | + <property name="label_xalign">0</property> |
1997 | + <property name="shadow_type">none</property> |
1998 | + <child> |
1999 | + <object class="GtkAlignment" id="preview_extra_buttons_container"> |
2000 | + <property name="visible">True</property> |
2001 | + <property name="can_focus">False</property> |
2002 | + <property name="left_padding">12</property> |
2003 | + <child> |
2004 | + <placeholder/> |
2005 | + </child> |
2006 | + </object> |
2007 | + </child> |
2008 | + <child type="label"> |
2009 | + <object class="GtkLabel" id="label9"> |
2010 | + <property name="visible">True</property> |
2011 | + <property name="can_focus">False</property> |
2012 | + <property name="label" translatable="yes"><b>Preview signals</b></property> |
2013 | + <property name="use_markup">True</property> |
2014 | + </object> |
2015 | + </child> |
2016 | + </object> |
2017 | + <packing> |
2018 | + <property name="expand">False</property> |
2019 | + <property name="fill">True</property> |
2020 | + <property name="position">2</property> |
2021 | + </packing> |
2022 | + </child> |
2023 | + </object> |
2024 | + <packing> |
2025 | + <property name="expand">False</property> |
2026 | + <property name="fill">True</property> |
2027 | + <property name="position">1</property> |
2028 | + </packing> |
2029 | + </child> |
2030 | + <child> |
2031 | + <object class="GtkNotebook" id="notebook2"> |
2032 | + <property name="visible">True</property> |
2033 | + <property name="can_focus">True</property> |
2034 | + <property name="hexpand">True</property> |
2035 | + <property name="vexpand">True</property> |
2036 | + <property name="tab_pos">bottom</property> |
2037 | + <child> |
2038 | + <object class="GtkScrolledWindow" id="scrolledwindow5"> |
2039 | + <property name="visible">True</property> |
2040 | + <property name="can_focus">True</property> |
2041 | + <property name="shadow_type">in</property> |
2042 | + <child> |
2043 | + <object class="GtkViewport" id="preview_viewport"> |
2044 | + <property name="visible">True</property> |
2045 | + <property name="can_focus">False</property> |
2046 | + <child> |
2047 | + <placeholder/> |
2048 | + </child> |
2049 | + </object> |
2050 | + </child> |
2051 | + </object> |
2052 | + </child> |
2053 | + <child type="tab"> |
2054 | + <object class="GtkLabel" id="label7"> |
2055 | + <property name="visible">True</property> |
2056 | + <property name="can_focus">False</property> |
2057 | + <property name="label" translatable="yes">Rendered</property> |
2058 | + </object> |
2059 | + <packing> |
2060 | + <property name="tab_fill">False</property> |
2061 | + </packing> |
2062 | + </child> |
2063 | + <child> |
2064 | + <object class="GtkScrolledWindow" id="scrolledwindow4"> |
2065 | + <property name="visible">True</property> |
2066 | + <property name="can_focus">True</property> |
2067 | + <property name="hscrollbar_policy">never</property> |
2068 | + <property name="shadow_type">in</property> |
2069 | + <child> |
2070 | + <object class="GtkTextView" id="preview_raw_view"> |
2071 | + <property name="visible">True</property> |
2072 | + <property name="can_focus">True</property> |
2073 | + <property name="editable">False</property> |
2074 | + <property name="wrap_mode">char</property> |
2075 | + <property name="buffer">preview_raw_data</property> |
2076 | + </object> |
2077 | + </child> |
2078 | + </object> |
2079 | + <packing> |
2080 | + <property name="position">1</property> |
2081 | + </packing> |
2082 | + </child> |
2083 | + <child type="tab"> |
2084 | + <object class="GtkLabel" id="label8"> |
2085 | + <property name="visible">True</property> |
2086 | + <property name="can_focus">False</property> |
2087 | + <property name="label" translatable="yes">Raw data</property> |
2088 | + </object> |
2089 | + <packing> |
2090 | + <property name="position">1</property> |
2091 | + <property name="tab_fill">False</property> |
2092 | + </packing> |
2093 | + </child> |
2094 | + <child> |
2095 | + <placeholder/> |
2096 | + </child> |
2097 | + <child type="tab"> |
2098 | + <placeholder/> |
2099 | + </child> |
2100 | + </object> |
2101 | + <packing> |
2102 | + <property name="expand">False</property> |
2103 | + <property name="fill">True</property> |
2104 | + <property name="position">2</property> |
2105 | + </packing> |
2106 | + </child> |
2107 | + <child> |
2108 | + <object class="GtkButton" id="next_preview_btn"> |
2109 | + <property name="label" translatable="yes">>></property> |
2110 | + <property name="use_action_appearance">False</property> |
2111 | + <property name="visible">True</property> |
2112 | + <property name="sensitive">False</property> |
2113 | + <property name="can_focus">True</property> |
2114 | + <property name="receives_default">True</property> |
2115 | + <property name="use_action_appearance">False</property> |
2116 | + <signal name="clicked" handler="unity_tester_unity_tool_ui_on_next_preview_clicked" swapped="no"/> |
2117 | + </object> |
2118 | + <packing> |
2119 | + <property name="expand">False</property> |
2120 | + <property name="fill">True</property> |
2121 | + <property name="position">3</property> |
2122 | + </packing> |
2123 | + </child> |
2124 | + </object> |
2125 | + <packing> |
2126 | + <property name="position">2</property> |
2127 | + </packing> |
2128 | + </child> |
2129 | + <child type="tab"> |
2130 | + <object class="GtkLabel" id="label5"> |
2131 | + <property name="visible">True</property> |
2132 | + <property name="can_focus">False</property> |
2133 | + <property name="label" translatable="yes">Preview</property> |
2134 | + </object> |
2135 | + <packing> |
2136 | + <property name="position">2</property> |
2137 | + <property name="tab_fill">False</property> |
2138 | + </packing> |
2139 | + </child> |
2140 | + <child> |
2141 | <object class="GtkScrolledWindow" id="scrolledwindow3"> |
2142 | <property name="visible">True</property> |
2143 | <property name="can_focus">True</property> |
2144 | @@ -554,7 +827,7 @@ |
2145 | </child> |
2146 | </object> |
2147 | <packing> |
2148 | - <property name="position">2</property> |
2149 | + <property name="position">3</property> |
2150 | </packing> |
2151 | </child> |
2152 | <child type="tab"> |
2153 | @@ -564,7 +837,7 @@ |
2154 | <property name="label" translatable="yes">Log</property> |
2155 | </object> |
2156 | <packing> |
2157 | - <property name="position">2</property> |
2158 | + <property name="position">3</property> |
2159 | <property name="tab_fill">False</property> |
2160 | </packing> |
2161 | </child> |
Works well, let's get it in...