syncevolution/src/dbus/server/pim/folks.h

385 lines
12 KiB
C++

/*
* Copyright (C) 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* The classes in this file implement sorting, searching and
* configuring of the unified address book based on libfolks.
*
* This is pure C++ code. The D-Bus IPC binding for it is
* implemented separately in pim-manager.h/cpp.
*/
#ifndef INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
#define INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS
#include <folks/folks.h>
#include "locale-factory.h"
#include "../dbus-callbacks.h"
#include "../timeout.h"
#include <syncevo/GLibSupport.h>
#include <syncevo/GeeSupport.h>
#include <syncevo/GValueSupport.h>
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/signals2.hpp>
SE_GOBJECT_TYPE(FolksIndividualAggregator)
SE_GOBJECT_TYPE(FolksIndividual)
SE_GOBJECT_TYPE(FolksEmailFieldDetails)
SE_GOBJECT_TYPE(FolksBackendStore)
SE_GOBJECT_TYPE(FolksBackend)
SE_GOBJECT_TYPE(FolksPersonaStore)
SE_GOBJECT_TYPE(FolksAbstractFieldDetails)
SE_GOBJECT_TYPE(FolksRoleFieldDetails)
SE_GOBJECT_TYPE(FolksRole)
SE_GOBJECT_TYPE(FolksPostalAddress)
SE_GOBJECT_TYPE(FolksNoteFieldDetails)
SE_GOBJECT_TYPE(FolksPostalAddressFieldDetails)
SE_GOBJECT_TYPE(FolksPersona)
SE_GOBJECT_TYPE(FolksLocation)
SE_GOBJECT_TYPE(GeeHashSet)
#include <syncevo/declarations.h>
SE_BEGIN_CXX
class PersonaDetails;
/**
* Abstract interface for comparing two FolksIndividual instances.
* The properties of a folks individual may change at any time.
* Therefore the key properties which determine the sort order
* must be copied from the individual. They will be updated when
* the individual changes.
*
* The other advantage is that complex, derived keys only need
* to be computed once instead of each time during a comparison.
* For example, boost::locale::collator::transform() can be used
* to generate the keys.
*/
class IndividualCompare
{
public:
static boost::shared_ptr<IndividualCompare> defaultCompare();
virtual ~IndividualCompare() {}
typedef std::vector<std::string> Criteria_t;
/**
* Calculate an ordered set of criteria for comparing
* individuals. The default comparison will start with the initial
* criteria and move on until a difference is found.
*
* This is necessary because a single string of "Doe, John" is
* treated differently in a collation than the pair of strings
* "Doe" and "John".
*
* @param individual the individual for which sort keys are to be created
* @retval criteria cleared before the call, filled afterwards
*/
virtual void createCriteria(FolksIndividual *individual, Criteria_t &criteria) const = 0;
/**
* Partial sort order: true if a smaller than b.
*
* Default implementation uses normal std::string::compare().
*/
virtual bool compare(const Criteria_t &a, const Criteria_t &b) const;
};
/**
* A FolksIndividual plus its sort criteria and search cache.
*/
struct IndividualData
{
/**
* Sets all members to match the given individual, using the
* compare instance to compute values. Both compare and locale may
* be NULL.
*
* Returns true if the precomputed values changed.
*/
bool init(const IndividualCompare *compare,
const LocaleFactory *locale,
FolksIndividual *individual);
FolksIndividualCXX m_individual;
IndividualCompare::Criteria_t m_criteria;
LocaleFactory::Precomputed m_precomputed;
};
/**
* wraps an IndividualCompare for std algorithms on IndividualData
*/
class IndividualDataCompare : public std::binary_function<IndividualData, IndividualData, bool>
{
boost::shared_ptr<IndividualCompare> m_compare;
public:
IndividualDataCompare(const boost::shared_ptr<IndividualCompare> &compare) :
m_compare(compare)
{}
IndividualDataCompare(const IndividualDataCompare &other) :
m_compare(other.m_compare)
{}
bool operator () (const IndividualData &a, const IndividualData &b) const
{
return m_compare->compare(a.m_criteria, b.m_criteria);
}
IndividualDataCompare & operator = (const IndividualDataCompare &other)
{
m_compare = other.m_compare;
return *this;
}
};
/**
* Abstract interface for filtering (aka searching) FolksIndividual
* instances.
*/
class IndividualFilter
{
int m_maxResults;
public:
IndividualFilter() : m_maxResults(-1) {}
virtual ~IndividualFilter() {}
/** Maximum number of results. -1 for unlimited. */
int getMaxResults() const { return m_maxResults; }
void setMaxResults(int maxResults) { m_maxResults = maxResults; }
/**
* True if within the number of expected results.
*/
bool isIncluded(size_t index) const { return m_maxResults == -1 || index < (size_t)m_maxResults; }
/**
* The corresponding EBook query string
* (http://developer.gnome.org/libebook/stable/libebook-e-book-query.html#e-book-query-to-string)
* for the filter, if there is one. Empty if not.
*/
virtual std::string getEBookFilter() const { return ""; }
/** true if the contact matches the filter */
virtual bool matches(const IndividualData &data) const = 0;
};
/**
* A filter which just enforces a maximum number of results,
* something that FullView cannot do.
*/
class MatchAll : public IndividualFilter
{
public:
virtual bool matches(const IndividualData &data) const { return true; }
};
/**
* A fake filter which just carries the maximum result parameter.
* Separate type because the dynamic_cast<> can be used to detect
* this special case.
*/
class ParamFilter : public MatchAll
{
};
class FullView;
/**
* Is a normal FolksIndividualAggregator and adds sorting, searching
* and browsing to it. At least the full sorted view always exists.
*/
class IndividualAggregator
{
/** empty when not started yet */
boost::shared_ptr<FullView> m_view;
boost::shared_ptr<IndividualCompare> m_compare;
boost::shared_ptr<LocaleFactory> m_locale;
boost::weak_ptr<IndividualAggregator> m_self;
FolksIndividualAggregatorCXX m_folks;
FolksBackendStoreCXX m_backendStore;
/**
* NULL when backends haven't been loaded yet.
* Set by backendsLoaded().
*/
FolksBackendCXX m_eds;
/**
* Set by backendsLoaded(), if possible. If m_eds != NULL
* and m_systemStore == NULL, no system address book is
* available. If m_eds == NULL, hook into m_backendsLoadedSignal
* to be notified.
*/
FolksPersonaStoreCXX m_systemStore;
boost::signals2::signal<void()> m_backendsLoadedSignal;
/**
* The set of enabled EDS databases, referenced by the UUID.
* Empty by default.
*/
GeeHashSetCXX m_databases;
/** string representation for debugging */
std::string dumpDatabases();
IndividualAggregator(const boost::shared_ptr<LocaleFactory> &locale);
void init(boost::shared_ptr<IndividualAggregator> &self);
/**
* Called when backend store is prepared. At that point, backends
* can be disabled or enabled and loading them can be kicked of.
*/
void storePrepared();
/**
* Called when all Folks backends are loaded, before the
* aggregator does its work. Now is the right time to initialize
* the set of databases and prepare the aggregator, if start() was
* already called.
*/
void backendsLoaded();
/**
* Executes the given operation when the EDS system address book
* is prepared. The operation may throw an exception, which (like
* all other errors) is reported as failure for the asynchronous
* operation.
*/
void runWithAddressBook(const boost::function<void ()> &operation,
const ErrorCb_t &onError) throw();
void runWithAddressBookHaveEDS(const boost::signals2::connection &conn,
const boost::function<void ()> &operation,
const ErrorCb_t &onError) throw();
void runWithAddressBookPrepared(const GError *gerror,
const boost::function<void ()> &operation,
const ErrorCb_t &onError) throw();
/**
* Executes the given operation after looking up the FolksPersona
* in the system address book, which must be prepared and loaded
* at that point.
*/
void runWithPersona(const boost::function<void (FolksPersona *)> &operation,
const std::string &localID,
const ErrorCb_t &onError) throw();
void doRunWithPersona(const boost::function<void (FolksPersona *)> &operation,
const std::string &localID,
const ErrorCb_t &onError) throw();
/** the operation for runWithAddressBook() */
void doAddContact(const Result<void (const std::string &)> &result,
const PersonaDetails &details);
/** handle result of adding contact */
void addContactDone(const GError *gerror,
FolksPersona *persona,
const Result<void (const std::string &)> &result) throw();
void doModifyContact(const Result<void ()> &result,
FolksPersona *persona,
const PersonaDetails &details) throw();
void doRemoveContact(const Result<void ()> &result,
FolksPersona *persona) throw();
void removeContactDone(const GError *gerror,
const Result<void ()> &result) throw();
public:
/**
* Creates an idle IndividualAggregator. Configure it and
* subscribe to signals, then call start().
*/
static boost::shared_ptr<IndividualAggregator> create(const boost::shared_ptr<LocaleFactory> &locale);
/**
* Access to FolksIndividualAggregator which is owned by
* the aggregator.
*/
FolksIndividualAggregator *getFolks() const { return m_folks.get(); }
/**
* Set sorting without starting the view just yet.
*/
void setCompare(const boost::shared_ptr<IndividualCompare> &compare);
/**
* Change current locale. Must be followed by setCompare() to update
* any pre-computed data.
*/
void setLocale(const boost::shared_ptr<LocaleFactory> &locale);
/**
* Starts pulling and sorting of contacts.
* Creates m_view and starts populating it.
* Can be called multiple times.
*
* See also org.01.pim.contacts.Manager.Start().
*/
void start();
/**
* start() was called, or something caused it to be called.
*/
bool isRunning() const;
/**
* configure active databases
*
* @param set of EDS database UUIDs, empty string for the default
* system address book
*/
void setDatabases(std::set<std::string> &databases);
/**
* Each aggregator has exactly one full view on the data. This
* method grants access to it and its change signals.
*
* @return never empty, start() will be called if necessary
*/
boost::shared_ptr<FullView> getMainView();
/**
* Add contact to system address book. Returns new local ID
* as result.
*/
void addContact(const Result<void (const std::string &)> &result,
const PersonaDetails &details);
/**
* Modify contact in system address book.
*/
void modifyContact(const Result<void ()> &result,
const std::string &localID,
const PersonaDetails &details);
/**
* Remove contact in system address book.
*/
void removeContact(const Result<void ()> &result,
const std::string &localID);
};
SE_END_CXX
#endif // INCL_SYNCEVO_DBUS_SERVER_IVI_FOLKS