changes: update to 0.9.5 + vala compatibility patch
[platform/upstream/folks.git] / folks / abstract-field-details.vala
1 /*
2  * Copyright (C) 2011 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  *       Marco Barisione <marco.barisione@collabora.co.uk>
19  *       Travis Reitter <travis.reitter@collabora.co.uk>
20  */
21
22 using GLib;
23 using Gee;
24
25 /**
26  * Object representing any type of value that can have some vCard-like
27  * parameters associated with it.
28  *
29  * Some contact details, like phone numbers or URLs, can have some
30  * extra details associated with them.
31  * For instance, a phone number expressed in vcard notation as
32  * ``tel;type=work,voice:(111) 555-1234`` would be represented as
33  * a AbstractFieldDetails with value "(111) 555-1234" and with parameters
34  * ``['type': ('work', 'voice')]``.
35  *
36  * The parameter name "type" with values "work", "home", or "other" are common
37  * amongst most vCard attributes (and thus most AbstractFieldDetails-derived
38  * classes). A "type" of "pref" may be used to indicate a preferred
39  * {@link AbstractFieldDetails.value} amongst many. See specific classes for
40  * information on additional parameters and values specific to that class.
41  *
42  * See [[http://www.ietf.org/rfc/rfc2426.txt|RFC2426]] for more details on
43  * pre-defined parameter names and values.
44  *
45  * @since 0.6.0
46  */
47 public abstract class Folks.AbstractFieldDetails<T> : Object
48 {
49   /**
50    * Parameter name for classifying the type of value this field contains.
51    *
52    * For example, the value could be relevant to the contact's home life, or to
53    * their work life; values of {@link AbstractFieldDetails.PARAM_TYPE_HOME}
54    * and {@link AbstractFieldDetails.PARAM_TYPE_WORK} would be used for the
55    * {@link AbstractFieldDetails.PARAM_TYPE} parameter, respectively, in those
56    * cases.
57    *
58    * @since 0.6.3
59    */
60   public static const string PARAM_TYPE = "type";
61
62   /**
63    * Parameter value for home-related field values.
64    *
65    * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
66    *
67    * @since 0.6.3
68    */
69   public static const string PARAM_TYPE_HOME = "home";
70
71   /**
72    * Parameter value for work-related field values.
73    *
74    * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
75    *
76    * @since 0.6.3
77    */
78   public static const string PARAM_TYPE_WORK = "work";
79
80   /**
81    * Parameter value for miscellaneous field values.
82    *
83    * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
84    *
85    * @since 0.6.3
86    */
87   public static const string PARAM_TYPE_OTHER = "other";
88
89   private T _value;
90   /**
91    * The value of the field.
92    *
93    * The value of the field, the exact type and content of which depends on what
94    * the structure is used for.
95    *
96    * @since 0.6.0
97    */
98   public virtual T @value
99     {
100       get { return this._value; }
101       construct set { this._value = value; }
102     }
103
104   /**
105    * The {@link GLib.Type} of the {@link AbstractFieldDetails.value}.
106    *
107    * This is particularly useful for treating collections of different types of
108    * {@link AbstractFieldDetails} in a uniform way without needing to name them
109    * explicitly.
110    *
111    * @since 0.6.5
112    */
113   public Type value_type
114     {
115       get { return typeof (T); }
116     }
117
118   private string _id;
119   /**
120    * A unique ID (if any) for this specific detail.
121    *
122    * This is primarily intended for {@link PersonaStore}s which need to track
123    * specific instances of details (because their backing store is wacky).
124    *
125    * In most cases, this will be an empty string.
126    *
127    * The content of this is opaque to all but the package which set it.
128    *
129    * @since 0.6.5
130    */
131   public virtual string id
132     {
133       get { return this._id; }
134       set { this._id = (value != null ? value : ""); }
135     }
136
137   private MultiMap<string, string> _parameters =
138       new HashMultiMap<string, string> ();
139   /**
140    * The parameters associated with the value.
141    *
142    * A multi-map of the parameters associated with
143    * {@link Folks.AbstractFieldDetails.value}. The keys are the names of
144    * the parameters, while the values are a list of strings.
145    *
146    * @since 0.6.0
147    */
148   public virtual MultiMap<string, string> parameters
149     {
150       get { return this._parameters; }
151       construct set
152         {
153           if (value == null)
154             this._parameters.clear ();
155           else
156             this._parameters = value;
157         }
158     }
159
160   /**
161    * Get the values for a parameter
162    *
163    * @param parameter_name the parameter name
164    * @return a collection of values for ``parameter_name`` or ``null`` (i.e. no
165    * collection) if there are no such parameters.
166    *
167    * @since 0.6.0
168    */
169   public Collection<string>? get_parameter_values (string parameter_name)
170     {
171       if (this.parameters.contains (parameter_name) == false)
172         {
173           return null;
174         }
175
176       return this.parameters.get (parameter_name).read_only_view;
177     }
178
179   /**
180    * Add a new value for a parameter.
181    *
182    * If there is already a parameter called ``parameter_name`` then
183    * ``parameter_value`` is added to the existing ones.
184    *
185    * @param parameter_name the name of the parameter
186    * @param parameter_value the value to add
187    *
188    * @since 0.6.0
189    */
190   public void add_parameter (string parameter_name, string parameter_value)
191     {
192       this.parameters.set (parameter_name, parameter_value);
193     }
194
195   /**
196    * Set the value of a parameter.
197    *
198    * Sets the parameter called ``parameter_name`` to be ``parameter_value``.
199    * If there were already parameters with the same name they are replaced.
200    *
201    * @param parameter_name the name of the parameter
202    * @param parameter_value the value to add
203    *
204    * @since 0.6.0
205    */
206   public void set_parameter (string parameter_name, string parameter_value)
207     {
208       this.parameters.remove_all (parameter_name);
209       this.parameters.set (parameter_name, parameter_value);
210     }
211
212   /**
213    * Extend the existing parameters.
214    *
215    * Merge the parameters from ``additional`` into the existing ones.
216    *
217    * @param additional the parameters to add
218    *
219    * @since 0.6.0
220    */
221   public void extend_parameters (MultiMap<string, string> additional)
222     {
223       var iter = additional.map_iterator ();
224
225       while (iter.next ())
226         this.add_parameter (iter.get_key (), iter.get_value ());
227     }
228
229   /**
230    * Remove all instances of a parameter.
231    *
232    * @param parameter_name the name of the parameter
233    *
234    * @since 0.6.0
235    */
236   public void remove_parameter_all (string parameter_name)
237     {
238       this.parameters.remove_all (parameter_name);
239     }
240
241   /**
242    * A fairly-strict equality function for {@link AbstractFieldDetails}.
243    *
244    * This function compares:
245    *
246    *  * {@link AbstractFieldDetails.value}s
247    *  * {@link AbstractFieldDetails.parameters}
248    *
249    * And does not compare:
250    *
251    *  * {@link AbstractFieldDetails.id}s
252    *
253    * See the description of {@link AbstractFieldDetails.values_equal} for
254    * details on the value comparison.
255    *
256    * To check equality not including the parameters, see
257    * {@link AbstractFieldDetails.values_equal}.
258    *
259    * @param that another {@link AbstractFieldDetails}
260    *
261    * @return whether the elements are equal
262    *
263    * @see AbstractFieldDetails.parameters_equal
264    * @see AbstractFieldDetails.values_equal
265    * @since 0.6.0
266    */
267   public virtual bool equal (AbstractFieldDetails<T> that)
268     {
269       return (this.get_type () == that.get_type ()) &&
270         this.values_equal (that) &&
271         this.parameters_equal (that);
272     }
273
274   /**
275    * Same as {@link AbstractFieldDetails.equal}, but static, so we can use
276    * libgee 0.8 without an API break.
277    *
278    * See [[https://bugzilla.gnome.org/show_bug.cgi?id=673918|673918]]
279    * This can and should be removed next time we break the API.
280    * Note: This uses Gee.EqualDataFunc signature, to avoid having to cast.
281    *
282    * @param left one {@link AbstractFieldDetails} to compare
283    * @param right another {@link AbstractFieldDetails} to compare
284    *
285    * @return whether the elemants are equal
286    *
287    * @since 0.9.0
288    */
289   public static bool equal_static (AbstractFieldDetails left,
290                                    AbstractFieldDetails right)
291     {
292       GLib.return_val_if_fail (left != null, false);
293       GLib.return_val_if_fail (right != null, false);
294
295       AbstractFieldDetails left_details = (AbstractFieldDetails) left;
296       AbstractFieldDetails right_details = (AbstractFieldDetails) right;
297       return left_details.equal (right_details);
298     }
299
300   /**
301    * An equality function which only considers parameters.
302    *
303    * This function compares:
304    *
305    *  * {@link AbstractFieldDetails.parameters}
306    *
307    * And does not compare:
308    *
309    *  * {@link AbstractFieldDetails.value}s
310    *  * {@link AbstractFieldDetails.id}s
311    *
312    * @param that another {@link AbstractFieldDetails}
313    *
314    * @return whether the elements' {@link AbstractFieldDetails.value}s are
315    * equal.
316    *
317    * @see AbstractFieldDetails.equal
318    * @see AbstractFieldDetails.values_equal
319    * @since 0.6.5
320    */
321   public virtual bool parameters_equal (AbstractFieldDetails<T> that)
322     {
323       /* Check that the parameter names and their values match exactly in both
324        * AbstractFieldDetails objects. */
325       if (this.parameters.size != that.parameters.size)
326         return false;
327
328       foreach (var param in this.parameters.get_keys ())
329         {
330           /* Since these parameters are meant to model vCard parameters, we
331            * should compare on a case-insensitive basis. However, this leads to
332            * ambiguity in the case:
333            *
334            *   this.parameters = {"foo": {"bar"}}
335            *   that.parameters = {"foo": {"bar"}, "FOO": {"qux"}}
336            *
337            * So parameter names should normalised elsewhere (either in the
338            * insertion functions (with a big warning for the clients) or in the
339            * clients themselves).
340            *
341            * Note that parameter values can't be normalised in general, since
342            * they can be user-set labels.
343            */
344           if (!that.parameters.contains (param))
345             return false;
346
347           var this_param_values = this.parameters.get_values ();
348           var that_param_values = that.parameters.get_values ();
349
350           if (this_param_values.size != that_param_values.size)
351             return false;
352
353           foreach (var param_val in this.parameters.get_values ())
354             {
355               if (!that_param_values.contains (param_val))
356                 return false;
357             }
358         }
359
360       return true;
361     }
362
363   /**
364    * An equality function which does not consider parameters.
365    *
366    * Specific classes may override this function to provide "smart" value
367    * comparisons (eg, considering the phone number values "+1 555 123 4567" and
368    * "123-4567" equal). If you wish to do strict comparisons, simply compare the
369    * {@link AbstractFieldDetails.value}s directly.
370    *
371    * This function compares:
372    *
373    *  * {@link AbstractFieldDetails.value}s
374    *
375    * And does not compare:
376    *
377    *  * {@link AbstractFieldDetails.parameters}
378    *  * {@link AbstractFieldDetails.id}s
379    *
380    * This defaults to string comparison of the
381    * {@link AbstractFieldDetails.value}s if the generic type is string;
382    * otherwise, direct pointer comparison of the
383    * {@link AbstractFieldDetails.value}s.
384    *
385    * @param that another {@link AbstractFieldDetails}
386    *
387    * @return whether the elements' {@link AbstractFieldDetails.value}s are
388    * equal.
389    *
390    * @see AbstractFieldDetails.equal
391    * @see AbstractFieldDetails.parameters_equal
392    * @since 0.6.5
393    */
394   public virtual bool values_equal (AbstractFieldDetails<T> that)
395     {
396       EqualFunc equal_func = direct_equal;
397
398       if (typeof (T) == typeof (string))
399         equal_func = str_equal;
400
401       if ((this.get_type () != that.get_type ()) ||
402           !equal_func (this.value, that.value))
403         {
404           return false;
405         }
406
407       return true;
408     }
409
410   /**
411    * A hash function for the {@link AbstractFieldDetails}.
412    *
413    * This defaults to a string hash of the
414    * {@link AbstractFieldDetails.value} if the generic type is string;
415    * otherwise, direct hash of the {@link AbstractFieldDetails.value}.
416    *
417    * @return the hash value
418    *
419    * @since 0.6.0
420    */
421   public virtual uint hash ()
422     {
423       HashFunc hash_func = direct_hash;
424
425       if (typeof (T) == typeof (string))
426         hash_func = str_hash;
427
428       return hash_func (this.value);
429     }
430
431   /**
432    * Same as {@link AbstractFieldDetails.hash}, but static, so we can use libgee
433    * 0.8 without an API break.
434    *
435    * See [[https://bugzilla.gnome.org/show_bug.cgi?id=673918|673918]]
436    * This can and should be removed next time we break the API.
437    * Note: This uses Gee.HashDataFunc signature, to avoid having to cast.
438    *
439    * @param value the value to hash
440    *
441    * @return the hash value
442    *
443    * @since 0.9.0
444    */
445   public static uint hash_static (AbstractFieldDetails value)
446     {
447       GLib.return_val_if_fail (value != null, 0);
448
449       AbstractFieldDetails details = (AbstractFieldDetails) value;
450       return details.hash ();
451     }
452 }