build: Release version 0.6.3
[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       set { this._value = value; }
102     }
103
104   private MultiMap<string, string> _parameters =
105       new HashMultiMap<string, string> ();
106   /**
107    * The parameters associated with the value.
108    *
109    * A multi-map of the parameters associated with
110    * {@link Folks.AbstractFieldDetails.value}. The keys are the names of
111    * the parameters, while the values are a list of strings.
112    *
113    * @since 0.6.0
114    */
115   public virtual MultiMap<string, string> parameters
116     {
117       get { return this._parameters; }
118       set
119         {
120           if (value == null)
121             this._parameters.clear ();
122           else
123             this._parameters = value;
124         }
125     }
126
127   /**
128    * Get the values for a parameter
129    *
130    * @param parameter_name the parameter name
131    * @return a collection of values for `parameter_name` or `null` (i.e. no
132    * collection) if there are no such parameters.
133    *
134    * @since 0.6.0
135    */
136   public Collection<string>? get_parameter_values (string parameter_name)
137     {
138       if (this.parameters.contains (parameter_name) == false)
139         {
140           return null;
141         }
142
143       return this.parameters.get (parameter_name).read_only_view;
144     }
145
146   /**
147    * Add a new value for a parameter.
148    *
149    * If there is already a parameter called `parameter_name` then
150    * `parameter_value` is added to the existing ones.
151    *
152    * @param parameter_name the name of the parameter
153    * @param parameter_value the value to add
154    *
155    * @since 0.6.0
156    */
157   public void add_parameter (string parameter_name, string parameter_value)
158     {
159       this.parameters.set (parameter_name, parameter_value);
160     }
161
162   /**
163    * Set the value of a parameter.
164    *
165    * Sets the parameter called `parameter_name` to be `parameter_value`.
166    * If there were already parameters with the same name they are replaced.
167    *
168    * @param parameter_name the name of the parameter
169    * @param parameter_value the value to add
170    *
171    * @since 0.6.0
172    */
173   public void set_parameter (string parameter_name, string parameter_value)
174     {
175       this.parameters.remove_all (parameter_name);
176       this.parameters.set (parameter_name, parameter_value);
177     }
178
179   /**
180    * Extend the existing parameters.
181    *
182    * Merge the parameters from `additional` into the existing ones.
183    *
184    * @param additional the parameters to add
185    *
186    * @since 0.6.0
187    */
188   public void extend_parameters (MultiMap<string, string> additional)
189     {
190       foreach (var name in additional.get_keys ())
191         {
192           var values = additional.get (name);
193           foreach (var val in values)
194             {
195               this.add_parameter (name, val);
196             }
197         }
198     }
199
200   /**
201    * Remove all instances of a parameter.
202    *
203    * @param parameter_name the name of the parameter
204    *
205    * @since 0.6.0
206    */
207   public void remove_parameter_all (string parameter_name)
208     {
209       this.parameters.remove_all (parameter_name);
210     }
211
212   /**
213    * An equality function for {@link AbstractFieldDetails}.
214    *
215    * This defaults to string comparison of the
216    * {@link AbstractFieldDetails.value}s if the generic type is string;
217    * otherwise, direct pointer comparison of the
218    * {@link AbstractFieldDetails.value}s.
219    *
220    * @param that another {@link AbstractFieldDetails}
221    *
222    * @return whether the elements are equal
223    *
224    * @since 0.6.0
225    */
226   public virtual bool equal (AbstractFieldDetails<T> that)
227     {
228       EqualFunc equal_func = direct_equal;
229
230       if (typeof (T) == typeof (string))
231         equal_func = str_equal;
232
233       if ((this.get_type () != that.get_type ()) ||
234           !equal_func (this.value, that.value))
235         {
236           return false;
237         }
238
239       /* Check that the parameter names and their values match exactly in both
240        * AbstractFieldDetails objects. */
241       if (this.parameters.size != that.parameters.size)
242         return false;
243
244       foreach (var param in this.parameters.get_keys ())
245         {
246           /* Since these parameters are meant to model vCard parameters, we
247            * should compare on a case-insensitive basis. However, this leads to
248            * ambiguity in the case:
249            *
250            *   this.parameters = {"foo": {"bar"}}
251            *   that.parameters = {"foo": {"bar"}, "FOO": {"qux"}}
252            *
253            * So parameter names should normalised elsewhere (either in the
254            * insertion functions (with a big warning for the clients) or in the
255            * clients themselves).
256            *
257            * Note that parameter values can't be normalised in general, since
258            * they can be user-set labels.
259            */
260           if (!that.parameters.contains (param))
261             return false;
262
263           var this_param_values = this.parameters.get_values ();
264           var that_param_values = that.parameters.get_values ();
265
266           if (this_param_values.size != that_param_values.size)
267             return false;
268
269           foreach (var param_val in this.parameters.get_values ())
270             {
271               if (!that_param_values.contains (param_val))
272                 return false;
273             }
274         }
275
276       return true;
277     }
278
279   /**
280    * A hash function for the {@link AbstractFieldDetails}.
281    *
282    * This defaults to a string hash of the
283    * {@link AbstractFieldDetails.value} if the generic type is string;
284    * otherwise, direct hash of the {@link AbstractFieldDetails.value}.
285    *
286    * @return the hash value
287    *
288    * @since 0.6.0
289    */
290   public virtual uint hash ()
291     {
292       HashFunc hash_func = direct_hash;
293
294       if (typeof (T) == typeof (string))
295         hash_func = str_hash;
296
297       return hash_func (this.value);
298     }
299 }