2 * Copyright (C) 2011 Collabora Ltd.
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.
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.
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/>.
18 * Marco Barisione <marco.barisione@collabora.co.uk>
19 * Travis Reitter <travis.reitter@collabora.co.uk>
26 * Object representing any type of value that can have some vCard-like
27 * parameters associated with it.
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')]``.
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.
42 * See [[http://www.ietf.org/rfc/rfc2426.txt|RFC2426]] for more details on
43 * pre-defined parameter names and values.
47 public abstract class Folks.AbstractFieldDetails<T> : Object
50 * Parameter name for classifying the type of value this field contains.
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
60 public static const string PARAM_TYPE = "type";
63 * Parameter value for home-related field values.
65 * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
69 public static const string PARAM_TYPE_HOME = "home";
72 * Parameter value for work-related field values.
74 * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
78 public static const string PARAM_TYPE_WORK = "work";
81 * Parameter value for miscellaneous field values.
83 * Value for a parameter with name {@link AbstractFieldDetails.PARAM_TYPE}.
87 public static const string PARAM_TYPE_OTHER = "other";
91 * The value of the field.
93 * The value of the field, the exact type and content of which depends on what
94 * the structure is used for.
98 public virtual T @value
100 get { return this._value; }
101 construct set { this._value = value; }
105 * The {@link GLib.Type} of the {@link AbstractFieldDetails.value}.
107 * This is particularly useful for treating collections of different types of
108 * {@link AbstractFieldDetails} in a uniform way without needing to name them
113 public Type value_type
115 get { return typeof (T); }
120 * A unique ID (if any) for this specific detail.
122 * This is primarily intended for {@link PersonaStore}s which need to track
123 * specific instances of details (because their backing store is wacky).
125 * In most cases, this will be an empty string.
127 * The content of this is opaque to all but the package which set it.
131 public virtual string id
133 get { return this._id; }
134 set { this._id = (value != null ? value : ""); }
137 private MultiMap<string, string> _parameters =
138 new HashMultiMap<string, string> ();
140 * The parameters associated with the value.
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.
148 public virtual MultiMap<string, string> parameters
150 get { return this._parameters; }
154 this._parameters.clear ();
156 this._parameters = value;
161 * Get the values for a parameter
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.
169 public Collection<string>? get_parameter_values (string parameter_name)
171 if (this.parameters.contains (parameter_name) == false)
176 return this.parameters.get (parameter_name).read_only_view;
180 * Add a new value for a parameter.
182 * If there is already a parameter called ``parameter_name`` then
183 * ``parameter_value`` is added to the existing ones.
185 * @param parameter_name the name of the parameter
186 * @param parameter_value the value to add
190 public void add_parameter (string parameter_name, string parameter_value)
192 this.parameters.set (parameter_name, parameter_value);
196 * Set the value of a parameter.
198 * Sets the parameter called ``parameter_name`` to be ``parameter_value``.
199 * If there were already parameters with the same name they are replaced.
201 * @param parameter_name the name of the parameter
202 * @param parameter_value the value to add
206 public void set_parameter (string parameter_name, string parameter_value)
208 this.parameters.remove_all (parameter_name);
209 this.parameters.set (parameter_name, parameter_value);
213 * Extend the existing parameters.
215 * Merge the parameters from ``additional`` into the existing ones.
217 * @param additional the parameters to add
221 public void extend_parameters (MultiMap<string, string> additional)
223 var iter = additional.map_iterator ();
226 this.add_parameter (iter.get_key (), iter.get_value ());
230 * Remove all instances of a parameter.
232 * @param parameter_name the name of the parameter
236 public void remove_parameter_all (string parameter_name)
238 this.parameters.remove_all (parameter_name);
242 * A fairly-strict equality function for {@link AbstractFieldDetails}.
244 * This function compares:
246 * * {@link AbstractFieldDetails.value}s
247 * * {@link AbstractFieldDetails.parameters}
249 * And does not compare:
251 * * {@link AbstractFieldDetails.id}s
253 * See the description of {@link AbstractFieldDetails.values_equal} for
254 * details on the value comparison.
256 * To check equality not including the parameters, see
257 * {@link AbstractFieldDetails.values_equal}.
259 * @param that another {@link AbstractFieldDetails}
261 * @return whether the elements are equal
263 * @see AbstractFieldDetails.parameters_equal
264 * @see AbstractFieldDetails.values_equal
267 public virtual bool equal (AbstractFieldDetails<T> that)
269 return (this.get_type () == that.get_type ()) &&
270 this.values_equal (that) &&
271 this.parameters_equal (that);
275 * Same as {@link AbstractFieldDetails.equal}, but static, so we can use
276 * libgee 0.8 without an API break.
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.
282 * @param left one {@link AbstractFieldDetails} to compare
283 * @param right another {@link AbstractFieldDetails} to compare
285 * @return whether the elemants are equal
289 public static bool equal_static (AbstractFieldDetails left,
290 AbstractFieldDetails right)
292 GLib.return_val_if_fail (left != null, false);
293 GLib.return_val_if_fail (right != null, false);
295 AbstractFieldDetails left_details = (AbstractFieldDetails) left;
296 AbstractFieldDetails right_details = (AbstractFieldDetails) right;
297 return left_details.equal (right_details);
301 * An equality function which only considers parameters.
303 * This function compares:
305 * * {@link AbstractFieldDetails.parameters}
307 * And does not compare:
309 * * {@link AbstractFieldDetails.value}s
310 * * {@link AbstractFieldDetails.id}s
312 * @param that another {@link AbstractFieldDetails}
314 * @return whether the elements' {@link AbstractFieldDetails.value}s are
317 * @see AbstractFieldDetails.equal
318 * @see AbstractFieldDetails.values_equal
321 public virtual bool parameters_equal (AbstractFieldDetails<T> that)
323 /* Check that the parameter names and their values match exactly in both
324 * AbstractFieldDetails objects. */
325 if (this.parameters.size != that.parameters.size)
328 foreach (var param in this.parameters.get_keys ())
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:
334 * this.parameters = {"foo": {"bar"}}
335 * that.parameters = {"foo": {"bar"}, "FOO": {"qux"}}
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).
341 * Note that parameter values can't be normalised in general, since
342 * they can be user-set labels.
344 if (!that.parameters.contains (param))
347 var this_param_values = this.parameters.get_values ();
348 var that_param_values = that.parameters.get_values ();
350 if (this_param_values.size != that_param_values.size)
353 foreach (var param_val in this.parameters.get_values ())
355 if (!that_param_values.contains (param_val))
364 * An equality function which does not consider parameters.
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.
371 * This function compares:
373 * * {@link AbstractFieldDetails.value}s
375 * And does not compare:
377 * * {@link AbstractFieldDetails.parameters}
378 * * {@link AbstractFieldDetails.id}s
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.
385 * @param that another {@link AbstractFieldDetails}
387 * @return whether the elements' {@link AbstractFieldDetails.value}s are
390 * @see AbstractFieldDetails.equal
391 * @see AbstractFieldDetails.parameters_equal
394 public virtual bool values_equal (AbstractFieldDetails<T> that)
396 EqualFunc equal_func = direct_equal;
398 if (typeof (T) == typeof (string))
399 equal_func = str_equal;
401 if ((this.get_type () != that.get_type ()) ||
402 !equal_func (this.value, that.value))
411 * A hash function for the {@link AbstractFieldDetails}.
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}.
417 * @return the hash value
421 public virtual uint hash ()
423 HashFunc hash_func = direct_hash;
425 if (typeof (T) == typeof (string))
426 hash_func = str_hash;
428 return hash_func (this.value);
432 * Same as {@link AbstractFieldDetails.hash}, but static, so we can use libgee
433 * 0.8 without an API break.
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.
439 * @param value the value to hash
441 * @return the hash value
445 public static uint hash_static (AbstractFieldDetails value)
447 GLib.return_val_if_fail (value != null, 0);
449 AbstractFieldDetails details = (AbstractFieldDetails) value;
450 return details.hash ();