changes: update to 0.9.5 + vala compatibility patch
[platform/upstream/folks.git] / tools / inspect / utils.vala
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  *
4  * This library is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 2.1 of the License, or
7  * (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors:
18  *       Philip Withnall <philip.withnall@collabora.co.uk>
19  */
20
21 using Folks;
22 using Gee;
23 using GLib;
24
25 private class Folks.Inspect.Utils
26 {
27   /* The current indentation level, in spaces */
28   private static uint indentation = 0;
29   private static string indentation_string = "";
30
31   /* The FILE we're printing output to. */
32   public static unowned FileStream output_filestream = GLib.stdout;
33
34   public static void init ()
35     {
36       Utils.indentation_string = "";
37       Utils.indentation = 0;
38       Utils.output_filestream = GLib.stdout;
39
40       /* Register some general transformation functions */
41       Value.register_transform_func (typeof (Object), typeof (string),
42           Utils.transform_object_to_string);
43       Value.register_transform_func (typeof (Folks.PersonaStore),
44           typeof (string), Utils.transform_persona_store_to_string);
45       Value.register_transform_func (typeof (string[]), typeof (string),
46           Utils.transform_string_array_to_string);
47       Value.register_transform_func (typeof (DateTime), typeof (string),
48           Utils.transform_date_time_to_string);
49     }
50
51   private static void transform_object_to_string (Value src,
52       out Value dest)
53     {
54       var output = "%p".printf (src.get_object ());
55       dest = (owned) output;
56     }
57
58   private static void transform_persona_store_to_string (Value src,
59       out Value dest)
60     {
61       var store = (Folks.PersonaStore) src;
62       var output = "%p: %s, %s (%s)".printf (store, store.type_id,
63           store.id, store.display_name);
64       dest = (owned) output;
65     }
66
67   private static void transform_string_array_to_string (Value src,
68       out Value dest)
69     {
70       unowned string[] array = (string[]) src;
71       string output = "{ ";
72       bool first = true;
73       foreach (var element in array)
74         {
75           if (first == false)
76             output += ", ";
77           output += "'%s'".printf (element);
78           first = false;
79         }
80       output += " }";
81       dest = (owned) output;
82     }
83
84   private static void transform_date_time_to_string (Value src, out Value dest)
85     {
86       unowned DateTime? date_time = (DateTime?) src;
87       string output = "(null)";
88       if (date_time != null)
89         {
90           output = ((!) date_time).format ("%FT%T%z");
91         }
92
93       dest = (owned) output;
94     }
95
96   public static void indent ()
97     {
98       /* We indent in increments of two spaces */
99       Utils.indentation += 2;
100       Utils.indentation_string = string.nfill (Utils.indentation, ' ');
101     }
102
103   public static void unindent ()
104     {
105       Utils.indentation -= 2;
106       Utils.indentation_string = string.nfill (Utils.indentation, ' ');
107     }
108
109   [PrintfFormat ()]
110   public static void print_line (string format, ...)
111     {
112       /* FIXME: store the va_list temporarily to work around bgo#638308 */
113       var valist = va_list ();
114       string output = format.vprintf (valist);
115       var str = "%s%s\n".printf (Utils.indentation_string, output);
116       Utils.output_filestream.printf (str);
117     }
118
119   public static void print_individual (Individual individual,
120       bool show_personas)
121     {
122       Utils.print_line ("Individual '%s' with %u personas:",
123           individual.id, individual.personas.size);
124
125       /* List the Individual's properties */
126       unowned ParamSpec[] properties =
127           individual.get_class ().list_properties ();
128
129       Utils.indent ();
130       foreach (unowned ParamSpec pspec in properties)
131         {
132           Value prop_value;
133           string output_string;
134
135           /* Ignore the personas property if we're printing the personas out */
136           if (show_personas == true && pspec.get_name () == "personas")
137             continue;
138
139           prop_value = Value (pspec.value_type);
140           individual.get_property (pspec.get_name (), ref prop_value);
141
142           output_string = Utils.property_to_string (individual.get_type (),
143               pspec.get_name (), prop_value);
144
145           Utils.print_line ("%-20s  %s", pspec.get_nick (), output_string);
146         }
147
148       if (show_personas == true)
149         {
150           Utils.print_line ("");
151           Utils.print_line ("Personas:");
152
153           Utils.indent ();
154           foreach (Persona persona in individual.personas)
155             Utils.print_persona (persona);
156           Utils.unindent ();
157         }
158       Utils.unindent ();
159     }
160
161   public static void print_persona (Persona persona)
162     {
163       Utils.print_line ("Persona '%s':", persona.uid);
164
165       /* List the Persona's properties */
166       unowned ParamSpec[] properties =
167           persona.get_class ().list_properties ();
168
169       Utils.indent ();
170       foreach (unowned ParamSpec pspec in properties)
171         {
172           Value prop_value;
173           string output_string;
174
175           prop_value = Value (pspec.value_type);
176           persona.get_property (pspec.get_name (), ref prop_value);
177
178           output_string = Utils.property_to_string (persona.get_type (),
179               pspec.get_name (), prop_value);
180
181           Utils.print_line ("%-20s  %s", pspec.get_nick (), output_string);
182         }
183       Utils.unindent ();
184     }
185
186   public static void print_persona_store (PersonaStore store,
187       bool show_personas)
188     {
189       if (store.is_prepared == false)
190         {
191           Utils.print_line ("Persona store '%s':", store.id);
192           Utils.indent ();
193           Utils.print_line ("Not prepared.");
194           Utils.unindent ();
195
196           return;
197         }
198
199       Utils.print_line ("Persona store '%s' with %u personas:",
200           store.id, store.personas.size);
201
202       /* List the store's properties */
203       unowned ParamSpec[] properties =
204           store.get_class ().list_properties ();
205
206       Utils.indent ();
207       foreach (unowned ParamSpec pspec in properties)
208         {
209           Value prop_value;
210           string output_string;
211
212           /* Ignore the personas property if we're printing the personas out */
213           if (show_personas == true && pspec.get_name () == "personas")
214             continue;
215
216           prop_value = Value (pspec.value_type);
217           store.get_property (pspec.get_name (), ref prop_value);
218
219           output_string = Utils.property_to_string (store.get_type (),
220               pspec.get_name (), prop_value);
221
222           Utils.print_line ("%-20s  %s", pspec.get_nick (), output_string);
223         }
224
225       if (show_personas == true)
226         {
227           Utils.print_line ("");
228           Utils.print_line ("Personas:");
229
230           Utils.indent ();
231           foreach (var persona in store.personas.values)
232             {
233               Utils.print_persona (persona);
234             }
235           Utils.unindent ();
236         }
237       Utils.unindent ();
238     }
239
240   private static string property_to_string (Type object_type,
241       string prop_name,
242       Value prop_value)
243     {
244       string output_string;
245
246       /* Overrides for various known properties */
247       if (object_type.is_a (typeof (Individual)) && prop_name == "personas")
248         {
249           Set<Persona> personas = (Set<Persona>) prop_value.get_object ();
250           return "List of %u personas".printf (personas.size);
251         }
252       else if (object_type.is_a (typeof (PersonaStore)) &&
253           prop_name == "personas")
254         {
255           Map<string, Persona> personas =
256               (Map<string, Persona>) prop_value.get_object ();
257           return "Set of %u personas".printf (personas.size);
258         }
259       else if (prop_name == "groups" ||
260                prop_name == "local-ids" ||
261                prop_name == "supported-fields" ||
262                prop_name == "anti-links")
263         {
264           Set<string> groups = (Set<string>) prop_value.get_object ();
265           output_string = "{ ";
266           bool first = true;
267
268           foreach (var group in groups)
269             {
270               if (first == false)
271                 output_string += ", ";
272               output_string += "'%s'".printf (group);
273               first = false;
274             }
275
276           output_string += " }";
277           return output_string;
278         }
279       else if (prop_name == "avatar")
280         {
281           string ret = null;
282           LoadableIcon? avatar = (LoadableIcon) prop_value.get_object ();
283
284           if (avatar != null &&
285               avatar is FileIcon && ((FileIcon) avatar).get_file () != null)
286             {
287               ret = "%p (file: %s)".printf (avatar,
288                   ((FileIcon) avatar).get_file ().get_uri ());
289             }
290           else if (avatar != null)
291             {
292               ret = "%p".printf (avatar);
293             }
294
295           return ret;
296         }
297       else if (prop_name == "file")
298         {
299           string ret = null;
300           File? file = (File) prop_value.get_object ();
301
302           if (file != null)
303             {
304               ret = "%p (file: %s)".printf (file, file.get_uri ());
305             }
306
307           return ret;
308         }
309       else if (prop_name == "im-addresses" ||
310                prop_name == "web-service-addresses")
311         {
312           var prop_list =
313               (MultiMap<string, AbstractFieldDetails<string>>)
314                   prop_value.get_object ();
315           output_string = "{ ";
316           bool first = true;
317
318           foreach (var k in prop_list.get_keys ())
319             {
320               if (first == false)
321                 output_string += ", ";
322               output_string += "'%s' : { ".printf (k);
323               first = false;
324
325               var v = prop_list.get (k);
326               bool _first = true;
327               foreach (var a in v)
328                 {
329                   if (_first == false)
330                     output_string += ", ";
331                   output_string += "'%s'".printf (a.value);
332                   _first = false;
333                 }
334
335               output_string += " }";
336             }
337
338           output_string += " }";
339           return output_string;
340         }
341       else if (prop_name == "email-addresses" ||
342                prop_name == "phone-numbers" ||
343                prop_name == "urls")
344         {
345           output_string = "{ ";
346           bool first = true;
347           var prop_list =
348               (Set<AbstractFieldDetails<string>>) prop_value.get_object ();
349
350           foreach (var p in prop_list)
351             {
352               if (!first)
353                 {
354                   output_string += ", ";
355                 }
356               output_string +=  p.value;
357               first = false;
358             }
359             output_string += " }";
360
361             return output_string;
362         }
363       else if (prop_name == "birthday")
364         {
365           unowned DateTime dobj = (DateTime) prop_value.get_boxed ();
366           if (dobj != null)
367             return dobj.to_string ();
368           else
369             return "";
370         }
371       else if (prop_name == "postal-addresses")
372         {
373           output_string = "{ ";
374           bool first = true;
375           var prop_list =
376               (Set<PostalAddressFieldDetails>) prop_value.get_object ();
377
378           foreach (var p in prop_list)
379             {
380               if (!first)
381                 {
382                   output_string += ". ";
383                 }
384               output_string +=  p.value.to_string ();
385               first = false;
386             }
387             output_string += " }";
388
389             return output_string;
390         }
391       else if (prop_name == "notes")
392         {
393           Set<NoteFieldDetails> notes =
394               prop_value.get_object () as Set<NoteFieldDetails>;
395
396           output_string = "{ ";
397           bool first = true;
398
399           foreach (var note in notes)
400             {
401               if (!first)
402                 {
403                   output_string += ", ";
404                 }
405               output_string += note.id;
406               first = false;
407             }
408             output_string += " }";
409
410             return output_string;
411         }
412       else if (prop_name == "roles")
413         {
414           var roles = (Set<RoleFieldDetails>) prop_value.get_object ();
415
416           output_string = "{ ";
417           bool first = true;
418
419           foreach (var role in roles)
420             {
421               if (!first)
422                 {
423                   output_string += ", ";
424                 }
425               output_string += role.value.to_string ();
426               first = false;
427             }
428             output_string += " }";
429
430             return output_string;
431         }
432       else if (prop_name == "structured-name")
433         {
434           unowned StructuredName sn = (StructuredName) prop_value.get_object ();
435           string ret = null;
436           if (sn != null)
437             ret = sn.to_string ();
438           return ret;
439         }
440
441       return Utils.transform_value_to_string (prop_value);
442     }
443
444   public static string transform_value_to_string (Value prop_value)
445     {
446       if (Value.type_transformable (prop_value.type (), typeof (string)))
447         {
448           /* Convert to a string value */
449           Value string_value = Value (typeof (string));
450           prop_value.transform (ref string_value);
451           return string_value.get_string ();
452         }
453       else
454         {
455           /* Can't convert the property value to a string */
456           return "Can't convert from type '%s' to '%s'".printf (
457               prop_value.type ().name (), typeof (string).name ());
458         }
459     }
460
461   /* FIXME: This can't be in the command_completion_cb() function because Vala
462    * doesn't allow static local variables. Erk. */
463   private static MapIterator<string, Command>? command_name_iter = null;
464
465   /* Complete a command name, starting with @word. */
466   public static string? command_name_completion_cb (string word,
467       int state)
468     {
469       /* Initialise state. Whoever wrote the readline API should be shot. */
470       if (state == 0)
471         Utils.command_name_iter = main_client.commands.map_iterator ();
472
473       while (Utils.command_name_iter.next () == true)
474         {
475           string command_name = Utils.command_name_iter.get_key ();
476           if (command_name.has_prefix (word))
477             return command_name;
478         }
479
480       /* Clean up */
481       Utils.command_name_iter = null;
482       return null;
483     }
484
485   /* FIXME: This can't be in the individual_id_completion_cb() function because
486    * Vala doesn't allow static local variables. Erk. */
487   private static MapIterator<string, Individual>? individual_id_iter = null;
488
489   /* Complete an individual's ID, starting with @word. */
490   public static string? individual_id_completion_cb (string word,
491       int state)
492     {
493       /* Initialise state. Whoever wrote the readline API should be shot. */
494       if (state == 0)
495         {
496           Utils.individual_id_iter =
497               main_client.aggregator.individuals.map_iterator ();
498         }
499
500       while (Utils.individual_id_iter.next () == true)
501         {
502           var id = Utils.individual_id_iter.get_key ();
503           if (id.has_prefix (word))
504             return id;
505         }
506
507       /* Clean up */
508       Utils.individual_id_iter = null;
509       return null;
510     }
511
512   /* FIXME: This can't be in the individual_id_completion_cb() function because
513    * Vala doesn't allow static local variables. Erk. */
514   private static Iterator<Persona>? persona_uid_iter = null;
515
516   /* Complete an individual's ID, starting with @word. */
517   public static string? persona_uid_completion_cb (string word,
518       int state)
519     {
520       /* Initialise state. Whoever wrote the readline API should be shot. */
521       if (state == 0)
522         {
523           Utils.individual_id_iter =
524               main_client.aggregator.individuals.map_iterator ();
525           Utils.persona_uid_iter = null;
526         }
527
528       while (Utils.persona_uid_iter != null ||
529           Utils.individual_id_iter.next () == true)
530         {
531           var individual = Utils.individual_id_iter.get_value ();
532
533           if (Utils.persona_uid_iter == null)
534             {
535               assert (individual != null);
536               Utils.persona_uid_iter = individual.personas.iterator ();
537             }
538
539           while (Utils.persona_uid_iter.next ())
540             {
541               var persona = Utils.persona_uid_iter.get ();
542               if (persona.uid.has_prefix (word))
543                 return persona.uid;
544             }
545
546           /* Clean up */
547           Utils.persona_uid_iter = null;
548         }
549
550       /* Clean up */
551       Utils.individual_id_iter = null;
552       return null;
553     }
554
555   /* FIXME: This can't be in the backend_name_completion_cb() function because
556    * Vala doesn't allow static local variables. Erk. */
557   private static Iterator<Backend>? backend_name_iter = null;
558
559   /* Complete an individual's ID, starting with @word. */
560   public static string? backend_name_completion_cb (string word,
561       int state)
562     {
563       /* Initialise state. Whoever wrote the readline API should be shot. */
564       if (state == 0)
565         {
566           Utils.backend_name_iter =
567               main_client.backend_store.list_backends ().iterator ();
568         }
569
570       while (Utils.backend_name_iter.next () == true)
571         {
572           Backend backend = Utils.backend_name_iter.get ();
573           if (backend.name.has_prefix (word))
574             return backend.name;
575         }
576
577       /* Clean up */
578       Utils.backend_name_iter = null;
579       return null;
580     }
581
582   /* FIXME: This can't be in the persona_store_id_completion_cb() function
583    * because Vala doesn't allow static local variables. Erk. */
584   private static MapIterator<string, PersonaStore>? persona_store_id_iter =
585       null;
586
587   /* Complete a persona store's ID, starting with @word. */
588   public static string? persona_store_id_completion_cb (string word,
589       int state)
590     {
591       /* Initialise state. Whoever wrote the readline API should be shot. */
592       if (state == 0)
593         {
594           Utils.backend_name_iter =
595               main_client.backend_store.list_backends ().iterator ();
596           Utils.persona_store_id_iter = null;
597         }
598
599       while (Utils.persona_store_id_iter != null ||
600           Utils.backend_name_iter.next () == true)
601         {
602           if (Utils.persona_store_id_iter == null)
603             {
604               Backend backend = Utils.backend_name_iter.get ();
605               Utils.persona_store_id_iter =
606                   backend.persona_stores.map_iterator ();
607             }
608
609           while (Utils.persona_store_id_iter.next () == true)
610             {
611               var id = Utils.persona_store_id_iter.get_key ();
612               if (id.has_prefix (word))
613                 return id;
614             }
615
616           /* Clean up */
617           Utils.persona_store_id_iter = null;
618         }
619
620       /* Clean up */
621       Utils.backend_name_iter = null;
622       return null;
623     }
624 }