core: Nullability fixes
[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       foreach (var name in additional.get_keys ())
224         {
225           var values = additional.get (name);
226           foreach (var val in values)
227             {
228               this.add_parameter (name, val);
229             }
230         }
231     }
232
233   /**
234    * Remove all instances of a parameter.
235    *
236    * @param parameter_name the name of the parameter
237    *
238    * @since 0.6.0
239    */
240   public void remove_parameter_all (string parameter_name)
241     {
242       this.parameters.remove_all (parameter_name);
243     }
244
245   /**
246    * A fairly-strict equality function for {@link AbstractFieldDetails}.
247    *
248    * This function compares:
249    *
250    *  * {@link AbstractFieldDetails.value}s
251    *  * {@link AbstractFieldDetails.parameters}
252    *
253    * And does not compare:
254    *
255    *  * {@link AbstractFieldDetails.id}s
256    *
257    * See the description of {@link AbstractFieldDetails.values_equal} for
258    * details on the value comparison.
259    *
260    * To check equality not including the parameters, see
261    * {@link AbstractFieldDetails.values_equal}.
262    *
263    * @param that another {@link AbstractFieldDetails}
264    *
265    * @return whether the elements are equal
266    *
267    * @see AbstractFieldDetails.parameters_equal
268    * @see AbstractFieldDetails.values_equal
269    * @since 0.6.0
270    */
271   public virtual bool equal (AbstractFieldDetails<T> that)
272     {
273       return (this.get_type () == that.get_type ()) &&
274         this.values_equal (that) &&
275         this.parameters_equal (that);
276     }
277
278   /**
279    * An equality function which only considers parameters.
280    *
281    * This function compares:
282    *
283    *  * {@link AbstractFieldDetails.parameters}
284    *
285    * And does not compare:
286    *
287    *  * {@link AbstractFieldDetails.value}s
288    *  * {@link AbstractFieldDetails.id}s
289    *
290    * @param that another {@link AbstractFieldDetails}
291    *
292    * @return whether the elements' {@link AbstractFieldDetails.value}s are
293    * equal.
294    *
295    * @see AbstractFieldDetails.equal
296    * @see AbstractFieldDetails.values_equal
297    * @since 0.6.5
298    */
299   public virtual bool parameters_equal (AbstractFieldDetails<T> that)
300     {
301       /* Check that the parameter names and their values match exactly in both
302        * AbstractFieldDetails objects. */
303       if (this.parameters.size != that.parameters.size)
304         return false;
305
306       foreach (var param in this.parameters.get_keys ())
307         {
308           /* Since these parameters are meant to model vCard parameters, we
309            * should compare on a case-insensitive basis. However, this leads to
310            * ambiguity in the case:
311            *
312            *   this.parameters = {"foo": {"bar"}}
313            *   that.parameters = {"foo": {"bar"}, "FOO": {"qux"}}
314            *
315            * So parameter names should normalised elsewhere (either in the
316            * insertion functions (with a big warning for the clients) or in the
317            * clients themselves).
318            *
319            * Note that parameter values can't be normalised in general, since
320            * they can be user-set labels.
321            */
322           if (!that.parameters.contains (param))
323             return false;
324
325           var this_param_values = this.parameters.get_values ();
326           var that_param_values = that.parameters.get_values ();
327
328           if (this_param_values.size != that_param_values.size)
329             return false;
330
331           foreach (var param_val in this.parameters.get_values ())
332             {
333               if (!that_param_values.contains (param_val))
334                 return false;
335             }
336         }
337
338       return true;
339     }
340
341   /**
342    * An equality function which does not consider parameters.
343    *
344    * Specific classes may override this function to provide "smart" value
345    * comparisons (eg, considering the phone number values "+1 555 123 4567" and
346    * "123-4567" equal). If you wish to do strict comparisons, simply compare the
347    * {@link AbstractFieldDetails.value}s directly.
348    *
349    * This function compares:
350    *
351    *  * {@link AbstractFieldDetails.value}s
352    *
353    * And does not compare:
354    *
355    *  * {@link AbstractFieldDetails.parameters}
356    *  * {@link AbstractFieldDetails.id}s
357    *
358    * This defaults to string comparison of the
359    * {@link AbstractFieldDetails.value}s if the generic type is string;
360    * otherwise, direct pointer comparison of the
361    * {@link AbstractFieldDetails.value}s.
362    *
363    * @param that another {@link AbstractFieldDetails}
364    *
365    * @return whether the elements' {@link AbstractFieldDetails.value}s are
366    * equal.
367    *
368    * @see AbstractFieldDetails.equal
369    * @see AbstractFieldDetails.parameters_equal
370    * @since 0.6.5
371    */
372   public virtual bool values_equal (AbstractFieldDetails<T> that)
373     {
374       EqualFunc equal_func = direct_equal;
375
376       if (typeof (T) == typeof (string))
377         equal_func = str_equal;
378
379       if ((this.get_type () != that.get_type ()) ||
380           !equal_func (this.value, that.value))
381         {
382           return false;
383         }
384
385       return true;
386     }
387
388   /**
389    * A hash function for the {@link AbstractFieldDetails}.
390    *
391    * This defaults to a string hash of the
392    * {@link AbstractFieldDetails.value} if the generic type is string;
393    * otherwise, direct hash of the {@link AbstractFieldDetails.value}.
394    *
395    * @return the hash value
396    *
397    * @since 0.6.0
398    */
399   public virtual uint hash ()
400     {
401       HashFunc hash_func = direct_hash;
402
403       if (typeof (T) == typeof (string))
404         hash_func = str_hash;
405
406       return hash_func (this.value);
407     }
408 }