2 * Copyright (C) 2012 Intel Corporation
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.
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.
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
21 * The classes in this file implement sorting, searching and
22 * configuring of the unified address book based on libfolks.
24 * This is pure C++ code. The D-Bus IPC binding for it is
25 * implemented separately in pim-manager.h/cpp.
28 #ifndef INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
29 #define INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
31 #include <folks/folks.h>
33 #include "locale-factory.h"
34 #include "../dbus-callbacks.h"
35 #include "../timeout.h"
37 #include <syncevo/GLibSupport.h>
38 #include <syncevo/GeeSupport.h>
39 #include <syncevo/GValueSupport.h>
41 #include <boost/shared_ptr.hpp>
42 #include <boost/ptr_container/ptr_vector.hpp>
43 #include <boost/signals2.hpp>
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)
62 #include <syncevo/declarations.h>
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.
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.
79 class IndividualCompare
82 static boost::shared_ptr<IndividualCompare> defaultCompare();
84 virtual ~IndividualCompare() {}
86 typedef std::vector<std::string> Criteria_t;
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.
93 * This is necessary because a single string of "Doe, John" is
94 * treated differently in a collation than the pair of strings
97 * @param individual the individual for which sort keys are to be created
98 * @retval criteria cleared before the call, filled afterwards
100 virtual void createCriteria(FolksIndividual *individual, Criteria_t &criteria) const = 0;
103 * Partial sort order: true if a smaller than b.
105 * Default implementation uses normal std::string::compare().
107 virtual bool compare(const Criteria_t &a, const Criteria_t &b) const;
111 * A FolksIndividual plus its sort criteria and search cache.
113 struct IndividualData
116 * Sets all members to match the given individual, using the
117 * compare instance to compute values. Both compare and locale may
120 * Returns true if the precomputed values changed.
122 bool init(const IndividualCompare *compare,
123 const LocaleFactory *locale,
124 FolksIndividual *individual);
126 FolksIndividualCXX m_individual;
127 IndividualCompare::Criteria_t m_criteria;
128 LocaleFactory::Precomputed m_precomputed;
132 * wraps an IndividualCompare for std algorithms on IndividualData
134 class IndividualDataCompare : public std::binary_function<IndividualData, IndividualData, bool>
136 boost::shared_ptr<IndividualCompare> m_compare;
139 IndividualDataCompare(const boost::shared_ptr<IndividualCompare> &compare) :
142 IndividualDataCompare(const IndividualDataCompare &other) :
143 m_compare(other.m_compare)
146 bool operator () (const IndividualData &a, const IndividualData &b) const
148 return m_compare->compare(a.m_criteria, b.m_criteria);
153 * Abstract interface for filtering (aka searching) FolksIndividual
156 class IndividualFilter
161 IndividualFilter() : m_maxResults(-1) {}
162 virtual ~IndividualFilter() {}
164 /** Maximum number of results. -1 for unlimited. */
165 int getMaxResults() const { return m_maxResults; }
166 void setMaxResults(int maxResults) { m_maxResults = maxResults; }
169 * True if within the number of expected results.
171 bool isIncluded(size_t index) const { return m_maxResults == -1 || index < (size_t)m_maxResults; }
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.
178 virtual std::string getEBookFilter() const { return ""; }
180 /** true if the contact matches the filter */
181 virtual bool matches(const IndividualData &data) const = 0;
185 * A filter which just enforces a maximum number of results,
186 * something that FullView cannot do.
188 class MatchAll : public IndividualFilter
191 virtual bool matches(const IndividualData &data) const { return true; }
195 * A fake filter which just carries the maximum result parameter.
196 * Separate type because the dynamic_cast<> can be used to detect
199 class ParamFilter : public MatchAll
206 * Is a normal FolksIndividualAggregator and adds sorting, searching
207 * and browsing to it. At least the full sorted view always exists.
209 class IndividualAggregator
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;
219 * NULL when backends haven't been loaded yet.
220 * Set by backendsLoaded().
222 FolksBackendCXX m_eds;
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
229 FolksPersonaStoreCXX m_systemStore;
231 boost::signals2::signal<void()> m_backendsLoadedSignal;
234 * The set of enabled EDS databases, referenced by the UUID.
237 GeeHashSetCXX m_databases;
238 /** string representation for debugging */
239 std::string dumpDatabases();
241 IndividualAggregator(const boost::shared_ptr<LocaleFactory> &locale);
242 void init(boost::shared_ptr<IndividualAggregator> &self);
245 * Called when backend store is prepared. At that point, backends
246 * can be disabled or enabled and loading them can be kicked of.
248 void storePrepared();
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
256 void backendsLoaded();
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
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();
274 * Executes the given operation after looking up the FolksPersona
275 * in the system address book, which must be prepared and loaded
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();
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();
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();
303 * Creates an idle IndividualAggregator. Configure it and
304 * subscribe to signals, then call start().
306 static boost::shared_ptr<IndividualAggregator> create(const boost::shared_ptr<LocaleFactory> &locale);
309 * Access to FolksIndividualAggregator which is owned by
312 FolksIndividualAggregator *getFolks() const { return m_folks.get(); }
315 * Set sorting without starting the view just yet.
317 void setCompare(const boost::shared_ptr<IndividualCompare> &compare);
320 * Change current locale. Must be followed by setCompare() to update
321 * any pre-computed data.
323 void setLocale(const boost::shared_ptr<LocaleFactory> &locale);
326 * Starts pulling and sorting of contacts.
327 * Creates m_view and starts populating it.
328 * Can be called multiple times.
330 * See also org.01.pim.contacts.Manager.Start().
335 * start() was called, or something caused it to be called.
337 bool isRunning() const;
340 * configure active databases
342 * @param set of EDS database UUIDs, empty string for the default
343 * system address book
345 void setDatabases(std::set<std::string> &databases);
348 * Each aggregator has exactly one full view on the data. This
349 * method grants access to it and its change signals.
351 * @return never empty, start() will be called if necessary
353 boost::shared_ptr<FullView> getMainView();
356 * Add contact to system address book. Returns new local ID
359 void addContact(const Result<void (const std::string &)> &result,
360 const PersonaDetails &details);
363 * Modify contact in system address book.
365 void modifyContact(const Result<void ()> &result,
366 const std::string &localID,
367 const PersonaDetails &details);
370 * Remove contact in system address book.
372 void removeContact(const Result<void ()> &result,
373 const std::string &localID);
379 #endif // INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS