Post-release version bump
[platform/upstream/folks.git] / folks / postal-address-details.vala
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  * Copyright (C) 2011 Philip Withnall
4  *
5  * This library is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 2.1 of the License, or
8  * (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Authors:
19  *       Marco Barisione <marco.barisione@collabora.co.uk>
20  *       Raul Gutierrez Segales <raul.gutierrez.segales@collabora.co.uk>
21  *       Philip Withnall <philip@tecnocode.co.uk>
22  */
23
24 using GLib;
25 using Gee;
26
27 /**
28  * Object representing a postal mail address.
29  * The components of the address are never null, an empty string
30  * indicates that a property is not set.
31  */
32 public class Folks.PostalAddress : Object
33 {
34   private string _po_box = "";
35   /**
36    * The PO Box.
37    *
38    * The PO Box (also known as Postal office box or Postal box).
39    */
40   public string po_box
41     {
42       get { return _po_box; }
43       construct set { _po_box = (value != null ? value : ""); }
44     }
45
46   private string _extension = "";
47   /**
48    * The address extension.
49    *
50    * Any additional part of the address, for instance a flat number.
51    */
52   public string extension
53     {
54       get { return _extension; }
55       construct set { _extension = (value != null ? value : ""); }
56     }
57
58   private string _street = "";
59   /**
60    * The street name and number.
61    *
62    * The street name including the optional building number.
63    * The number can be before or after the street name based on the
64    * language and country.
65    */
66   public string street
67     {
68       get { return _street; }
69       construct set { _street = (value != null ? value : ""); }
70     }
71
72   private string _locality = "";
73   /**
74    * The locality.
75    *
76    * The locality, for instance the city name.
77    */
78   public string locality
79     {
80       get { return _locality; }
81       construct set { _locality = (value != null ? value : ""); }
82     }
83
84   private string _region = "";
85   /**
86    * The region.
87    *
88    * The region, for instance the name of the state or province.
89    */
90   public string region
91     {
92       get { return _region; }
93       construct set { _region = (value != null ? value : ""); }
94     }
95
96   private string _postal_code = "";
97   /**
98    * The postal code.
99    *
100    * The postal code (also known as post code, postcode or ZIP code).
101    */
102   public string postal_code
103     {
104       get { return _postal_code; }
105       construct set { _postal_code = (value != null ? value : ""); }
106     }
107
108   private string _country = "";
109   /**
110    * The country.
111    *
112    * The name of the country.
113    */
114   public string country
115     {
116       get { return _country; }
117       construct set { _country = (value != null ? value : ""); }
118     }
119
120   private string _address_format = "";
121   /**
122    * The address format.
123    *
124    * The two letter country code that determines the format or exact
125    * meaning of the other fields.
126    */
127   public string address_format
128     {
129       get { return _address_format; }
130       construct set { _address_format = (value != null ? value : ""); }
131     }
132
133   private string _uid = "";
134   /**
135    * The UID of the Postal Address (if any).
136    */
137   [Deprecated (since = "0.6.5", replacement = "AbstractFieldDetails.id")]
138   public string uid
139     {
140       get { return _uid; }
141       construct set { _uid = (value != null ? value : ""); }
142     }
143
144   /**
145    * Create a PostalAddress.
146    *
147    * You can pass `null` if a component is not set.
148    *
149    * @param po_box the PO Box
150    * @param extension the address extension
151    * @param street the street name and number
152    * @param locality the locality (city, town or village) name
153    * @param region the region (state or province) name
154    * @param postal_code the postal code
155    * @param country the country name
156    * @param address_format the address format
157    * @param types set of types for the address (such as "personal" or "work")
158    * @param uid external UID for the address instance
159    * @since 0.5.1
160    */
161   public PostalAddress (string? po_box, string? extension, string? street,
162       string? locality, string? region, string? postal_code, string? country,
163       string? address_format, string? uid)
164     {
165       Object (po_box:         po_box,
166               extension:      extension,
167               street:         street,
168               locality:       locality,
169               region:         region,
170               postal_code:    postal_code,
171               country:        country,
172               address_format: address_format,
173               uid:            uid);
174     }
175
176   /**
177    * Whether none of the components is set.
178    *
179    * @return `true` if all the components are the empty string, `false`
180    * otherwise.
181    *
182    * @since 0.6.7
183    */
184   public bool is_empty ()
185     {
186       return this.po_box == "" &&
187              this.extension == "" &&
188              this.street == "" &&
189              this.locality == "" &&
190              this.region == "" &&
191              this.postal_code == "" &&
192              this.country == "" &&
193              this.address_format == "";
194     }
195
196   /**
197    * Compare if two postal addresses are equal. Addresses are equal if all their
198    * components are equal (where `null` compares equal only with `null`) and
199    * they have the same set of types (or both have no types).
200    *
201    * This does not factor in the {@link PostalAddress.uid}.
202    *
203    * @param with another postal address to compare with
204    * @return `true` if the addresses are equal, `false` otherwise
205    */
206   public bool equal (PostalAddress with)
207     {
208       if (this.po_box != with.po_box ||
209           this.extension != with.extension ||
210           this.street != with.street ||
211           this.locality != with.locality ||
212           this.region != with.region ||
213           this.postal_code != with.postal_code ||
214           this.country != with.country ||
215           this.address_format != with.address_format)
216         return false;
217
218       return true;
219     }
220
221   /**
222    * Get a formatted version of the address. The format is localised, and by
223    * default is comma-separated.
224    *
225    * @return a formatted address.
226    *
227    * @since 0.4.0
228    */
229   public string to_string ()
230     {
231       var str = _("%s, %s, %s, %s, %s, %s, %s");
232       return str.printf (this.po_box, this.extension, this.street,
233           this.locality, this.region, this.postal_code, this.country);
234     }
235 }
236
237 /**
238  * Object representing a PostalAddress value that can have some parameters
239  * associated with it.
240  *
241  * See {@link Folks.AbstractFieldDetails} for details on common parameter names
242  * and values.
243  *
244  * @since 0.6.0
245  */
246 public class Folks.PostalAddressFieldDetails :
247     AbstractFieldDetails<PostalAddress>
248 {
249   private string _id;
250   /**
251    * {@inheritDoc}
252    */
253   public override string id
254     {
255       get { return this._id; }
256       set
257         {
258           this._id = (value != null ? value : "");
259
260           /* Keep the PostalAddress.uid sync'd from our id */
261           if (this._id != this.value.uid)
262             this.value.uid = this._id;
263         }
264     }
265
266   /**
267    * Create a new PostalAddressFieldDetails.
268    *
269    * @param value the value of the field, a non-empty {@link PostalAddress}
270    * @param parameters initial parameters. See
271    * {@link AbstractFieldDetails.parameters}. A `null` value is equivalent to an
272    * empty map of parameters.
273    *
274    *
275    * @return a new PostalAddressFieldDetails
276    *
277    * @since 0.6.0
278    */
279   public PostalAddressFieldDetails (PostalAddress value,
280       MultiMap<string, string>? parameters = null)
281     {
282       if (value.is_empty ())
283         {
284           warning ("Empty postal address passed to PostalAddressFieldDetails.");
285         }
286
287       /* We keep id and value.uid synchronised in both directions. */
288       Object (value: value,
289               parameters: parameters,
290               id: value.uid);
291     }
292
293   construct
294     {
295       /* Keep the PostalAddress.uid sync'd to our id */
296       this.value.notify["uid"].connect ((s, p) =>
297         {
298           if (this.id != this.value.uid)
299             this.id = this.value.uid;
300         });
301     }
302
303   /**
304    * {@inheritDoc}
305    *
306    * @since 0.6.0
307    */
308   public override bool equal (AbstractFieldDetails<PostalAddress> that)
309     {
310       if (!base.parameters_equal (that))
311         return false;
312
313       /* This is fairly-dumb but smart matching is an i10n nightmare. */
314       return this.value.to_string () == that.value.to_string ();
315     }
316
317   /**
318    * {@inheritDoc}
319    *
320    * @since 0.6.0
321    */
322   public override uint hash ()
323     {
324       /* This is basic because smart matching is very hard (see equal()). */
325       return str_hash (this.value.to_string ());
326     }
327 }
328
329 /**
330  * Interface for classes that can provide postal addresses, such as
331  * {@link Persona} and {@link Individual}.
332  */
333 public interface Folks.PostalAddressDetails : Object
334 {
335   /**
336    * The postal addresses of the contact.
337    *
338    * A list of postal addresses associated to the contact.
339    *
340    * @since 0.5.1
341    */
342   public abstract Set<PostalAddressFieldDetails> postal_addresses { get; set; }
343
344   /**
345    * Change the contact's postal addresses.
346    *
347    * It's preferred to call this rather than setting
348    * {@link PostalAddressDetails.postal_addresses} directly, as this method
349    * gives error notification and will only return once the addresses have been
350    * written to the relevant backing store (or the operation's failed).
351    *
352    * @param postal_addresses the set of postal addresses
353    * @throws PropertyError if setting the addresses failed
354    * @since 0.6.2
355    */
356   public virtual async void change_postal_addresses (
357       Set<PostalAddressFieldDetails> postal_addresses) throws PropertyError
358     {
359       /* Default implementation. */
360       throw new PropertyError.NOT_WRITEABLE (
361           _("Postal addresses are not writeable on this contact."));
362     }
363 }