Imported Upstream version 1.3.99.5_20131030_SE_05e5911_SYSYNC_69de386
[platform/upstream/syncevolution.git] / src / dbus / server / pim / folks.h
1 /*
2  * Copyright (C) 2012 Intel Corporation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) version 3.
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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301  USA
18  */
19
20 /**
21  * The classes in this file implement sorting, searching and
22  * configuring of the unified address book based on libfolks.
23  *
24  * This is pure C++ code. The D-Bus IPC binding for it is
25  * implemented separately in pim-manager.h/cpp.
26  */
27
28 #ifndef INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
29 #define INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
30
31 #include <folks/folks.h>
32
33 #include "locale-factory.h"
34 #include "../dbus-callbacks.h"
35 #include "../timeout.h"
36
37 #include <syncevo/GLibSupport.h>
38 #include <syncevo/GeeSupport.h>
39 #include <syncevo/GValueSupport.h>
40
41 #include <boost/shared_ptr.hpp>
42 #include <boost/ptr_container/ptr_vector.hpp>
43 #include <boost/signals2.hpp>
44
45 SE_GOBJECT_TYPE(FolksIndividualAggregator)
46 SE_GOBJECT_TYPE(FolksIndividual)
47 SE_GOBJECT_TYPE(FolksEmailFieldDetails)
48 SE_GOBJECT_TYPE(FolksBackendStore)
49 SE_GOBJECT_TYPE(FolksBackend)
50 SE_GOBJECT_TYPE(FolksPersonaStore)
51 SE_GOBJECT_TYPE(FolksAbstractFieldDetails)
52 SE_GOBJECT_TYPE(FolksRoleFieldDetails)
53 SE_GOBJECT_TYPE(FolksRole)
54 SE_GOBJECT_TYPE(FolksPostalAddress)
55 SE_GOBJECT_TYPE(FolksNoteFieldDetails)
56 SE_GOBJECT_TYPE(FolksPostalAddressFieldDetails)
57 SE_GOBJECT_TYPE(FolksPersona)
58 SE_GOBJECT_TYPE(FolksLocation)
59 SE_GOBJECT_TYPE(GeeHashSet)
60 SE_GLIB_TYPE(GHashTable, g_hash_table)
61
62 #include <syncevo/declarations.h>
63 SE_BEGIN_CXX
64
65 class PersonaDetails;
66
67 /**
68  * Abstract interface for comparing two FolksIndividual instances.
69  * The properties of a folks individual may change at any time.
70  * Therefore the key properties which determine the sort order
71  * must be copied from the individual. They will be updated when
72  * the individual changes.
73  *
74  * The other advantage is that complex, derived keys only need
75  * to be computed once instead of each time during a comparison.
76  * For example, boost::locale::collator::transform() can be used
77  * to generate the keys.
78  */
79 class IndividualCompare
80 {
81  public:
82     static boost::shared_ptr<IndividualCompare> defaultCompare();
83
84     virtual ~IndividualCompare() {}
85
86     typedef std::vector<std::string> Criteria_t;
87
88     /**
89      * Calculate an ordered set of criteria for comparing
90      * individuals. The default comparison will start with the initial
91      * criteria and move on until a difference is found.
92      *
93      * This is necessary because a single string of "Doe, John" is
94      * treated differently in a collation than the pair of strings
95      * "Doe" and "John".
96      *
97      * @param individual    the individual for which sort keys are to be created
98      * @retval criteria     cleared before the call, filled afterwards
99      */
100     virtual void createCriteria(FolksIndividual *individual, Criteria_t &criteria) const = 0;
101
102     /**
103      * Partial sort order: true if a smaller than b.
104      *
105      * Default implementation uses normal std::string::compare().
106      */
107     virtual bool compare(const Criteria_t &a, const Criteria_t &b) const;
108 };
109
110 /**
111  * A FolksIndividual plus its sort criteria and search cache.
112  */
113 struct IndividualData
114 {
115     /**
116      * Sets all members to match the given individual, using the
117      * compare instance to compute values. Both compare and locale may
118      * be NULL.
119      *
120      * Returns true if the precomputed values changed.
121      */
122     bool init(const IndividualCompare *compare,
123               const LocaleFactory *locale,
124               FolksIndividual *individual);
125
126     FolksIndividualCXX m_individual;
127     IndividualCompare::Criteria_t m_criteria;
128     LocaleFactory::Precomputed m_precomputed;
129 };
130
131 /**
132  * wraps an IndividualCompare for std algorithms on IndividualData
133  */
134 class IndividualDataCompare : public std::binary_function<IndividualData, IndividualData, bool>
135 {
136     boost::shared_ptr<IndividualCompare> m_compare;
137
138  public:
139     IndividualDataCompare(const boost::shared_ptr<IndividualCompare> &compare) :
140        m_compare(compare)
141     {}
142     IndividualDataCompare(const IndividualDataCompare &other) :
143        m_compare(other.m_compare)
144     {}
145
146     bool operator () (const IndividualData &a, const IndividualData &b) const
147     {
148         return m_compare->compare(a.m_criteria, b.m_criteria);
149     }
150 };
151
152 /**
153  * Abstract interface for filtering (aka searching) FolksIndividual
154  * instances.
155  */
156 class IndividualFilter
157 {
158     int m_maxResults;
159
160  public:
161     IndividualFilter() : m_maxResults(-1) {}
162     virtual ~IndividualFilter() {}
163
164     /** Maximum number of results. -1 for unlimited. */
165     int getMaxResults() const { return m_maxResults; }
166     void setMaxResults(int maxResults) { m_maxResults = maxResults; }
167
168     /**
169      * True if within the number of expected results.
170      */
171     bool isIncluded(size_t index) const { return m_maxResults == -1 || index < (size_t)m_maxResults; }
172
173     /**
174      * The corresponding EBook query string
175      * (http://developer.gnome.org/libebook/stable/libebook-e-book-query.html#e-book-query-to-string)
176      * for the filter, if there is one. Empty if not.
177      */
178     virtual std::string getEBookFilter() const { return ""; }
179
180     /** true if the contact matches the filter */
181     virtual bool matches(const IndividualData &data) const = 0;
182 };
183
184 /**
185  * A filter which just enforces a maximum number of results,
186  * something that FullView cannot do.
187  */
188 class MatchAll : public IndividualFilter
189 {
190  public:
191     virtual bool matches(const IndividualData &data) const { return true; }
192 };
193
194 /**
195  * A fake filter which just carries the maximum result parameter.
196  * Separate type because the dynamic_cast<> can be used to detect
197  * this special case.
198  */
199 class ParamFilter : public MatchAll
200 {
201 };
202
203 class FullView;
204
205 /**
206  * Is a normal FolksIndividualAggregator and adds sorting, searching
207  * and browsing to it. At least the full sorted view always exists.
208  */
209 class IndividualAggregator
210 {
211     /** empty when not started yet */
212     boost::shared_ptr<FullView> m_view;
213     boost::shared_ptr<IndividualCompare> m_compare;
214     boost::shared_ptr<LocaleFactory> m_locale;
215     boost::weak_ptr<IndividualAggregator> m_self;
216     FolksIndividualAggregatorCXX m_folks;
217     FolksBackendStoreCXX m_backendStore;
218     /**
219      * NULL when backends haven't been loaded yet.
220      * Set by backendsLoaded().
221      */
222     FolksBackendCXX m_eds;
223     /**
224      * Set by backendsLoaded(), if possible. If m_eds != NULL
225      * and m_systemStore == NULL, no system address book is
226      * available. If m_eds == NULL, hook into m_backendsLoadedSignal
227      * to be notified.
228      */
229     FolksPersonaStoreCXX m_systemStore;
230
231     boost::signals2::signal<void()> m_backendsLoadedSignal;
232
233     /**
234      * The set of enabled EDS databases, referenced by the UUID.
235      * Empty by default.
236      */
237     GeeHashSetCXX m_databases;
238     /** string representation for debugging */
239     std::string dumpDatabases();
240
241     IndividualAggregator(const boost::shared_ptr<LocaleFactory> &locale);
242     void init(boost::shared_ptr<IndividualAggregator> &self);
243
244     /**
245      * Called when backend store is prepared. At that point, backends
246      * can be disabled or enabled and loading them can be kicked of.
247      */
248     void storePrepared();
249
250     /**
251      * Called when all Folks backends are loaded, before the
252      * aggregator does its work. Now is the right time to initialize
253      * the set of databases and prepare the aggregator, if start() was
254      * already called.
255      */
256     void backendsLoaded();
257
258     /**
259      * Executes the given operation when the EDS system address book
260      * is prepared. The operation may throw an exception, which (like
261      * all other errors) is reported as failure for the asynchronous
262      * operation.
263      */
264     void runWithAddressBook(const boost::function<void ()> &operation,
265                             const ErrorCb_t &onError) throw();
266     void runWithAddressBookHaveEDS(const boost::signals2::connection &conn,
267                                    const boost::function<void ()> &operation,
268                                    const ErrorCb_t &onError) throw();
269     void runWithAddressBookPrepared(const GError *gerror,
270                                     const boost::function<void ()> &operation,
271                                     const ErrorCb_t &onError) throw();
272
273     /**
274      * Executes the given operation after looking up the FolksPersona
275      * in the system address book, which must be prepared and loaded
276      * at that point.
277      */
278     void runWithPersona(const boost::function<void (FolksPersona *)> &operation,
279                         const std::string &localID,
280                         const ErrorCb_t &onError) throw();
281     void doRunWithPersona(const boost::function<void (FolksPersona *)> &operation,
282                           const std::string &localID,
283                           const ErrorCb_t &onError) throw();
284
285     /** the operation for runWithAddressBook() */
286     void doAddContact(const Result<void (const std::string &)> &result,
287                       const PersonaDetails &details);
288     /** handle result of adding contact */
289     void addContactDone(const GError *gerror,
290                         FolksPersona *persona,
291                         const Result<void (const std::string &)> &result) throw();
292
293    void doModifyContact(const Result<void ()> &result,
294                         FolksPersona *persona,
295                         const PersonaDetails &details) throw();
296    void doRemoveContact(const Result<void ()> &result,
297                         FolksPersona *persona) throw();
298    void removeContactDone(const GError *gerror,
299                           const Result<void ()> &result) throw();
300
301  public:
302     /**
303      * Creates an idle IndividualAggregator. Configure it and
304      * subscribe to signals, then call start().
305      */
306     static boost::shared_ptr<IndividualAggregator> create(const boost::shared_ptr<LocaleFactory> &locale);
307
308     /**
309      * Access to FolksIndividualAggregator which is owned by
310      * the aggregator.
311      */
312     FolksIndividualAggregator *getFolks() const { return m_folks.get(); }
313
314     /**
315      * Set sorting without starting the view just yet.
316      */
317     void setCompare(const boost::shared_ptr<IndividualCompare> &compare);
318
319     /**
320      * Change current locale. Must be followed by setCompare() to update
321      * any pre-computed data.
322      */
323     void setLocale(const boost::shared_ptr<LocaleFactory> &locale);
324
325     /**
326      * Starts pulling and sorting of contacts.
327      * Creates m_view and starts populating it.
328      * Can be called multiple times.
329      *
330      * See also org.01.pim.contacts.Manager.Start().
331      */
332     void start();
333
334     /**
335      * start() was called, or something caused it to be called.
336      */
337     bool isRunning() const;
338
339     /**
340      * configure active databases
341      *
342      * @param set of EDS database UUIDs, empty string for the default
343      * system address book
344      */
345     void setDatabases(std::set<std::string> &databases);
346
347     /**
348      * Each aggregator has exactly one full view on the data. This
349      * method grants access to it and its change signals.
350      *
351      * @return never empty, start() will be called if necessary
352      */
353     boost::shared_ptr<FullView> getMainView();
354
355     /**
356      * Add contact to system address book. Returns new local ID
357      * as result.
358      */
359    void addContact(const Result<void (const std::string &)> &result,
360                    const PersonaDetails &details);
361
362    /**
363     * Modify contact in system address book.
364     */
365    void modifyContact(const Result<void ()> &result,
366                       const std::string &localID,
367                       const PersonaDetails &details);
368
369    /**
370     * Remove contact in system address book.
371     */
372    void removeContact(const Result<void ()> &result,
373                       const std::string &localID);
374 };
375
376
377 SE_END_CXX
378
379 #endif // INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS