PIM: locale-aware sorting and searching
Change the --enable-dbus-service-pim parameter into one which takes a parameter that specifies how locale-aware sorting and searching is to be implemented. The default implementation uses boost::locale. It is expected to get replaced or augemented by OEMs which want to implement more complex sorting or searching (like ignoring Tussenvoegsel in the Netherlands). The LocaleFactory instance takes the current locale from the environment. Making it and its users aware of locale changes at runtime might be needed at some point but is not part of the API at the moment. The Manager class uses the factory to handle sorting and searching requests coming in via D-Bus. Right now, that is not functional yet because the boost::locale implementation is just a stub. It only compiles and links. FullView::setSortOrder is now functional. Clean up view code a bit: - All views delay populating their content until the caller asks for it. For the FullView this will only happen once, so the caller must be able to handle an already populated view, which was missing in ViewResource. Still need a test for this. - Use init(<smart pointer) consistently.
This commit is contained in:
parent
8b5644ad0f
commit
f13956bd4b
47
configure.ac
47
configure.ac
|
@ -61,6 +61,11 @@ dnl check for programs.
|
|||
AC_PROG_CXX
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
# Boost headers: boost/foreach.hpp is needed (1.33/Debian Etch
|
||||
# doesn't have it, 1.34/Ubuntu 8.10 Hardy does). 1.35 is available
|
||||
# as Debian Etch backport.
|
||||
AX_BOOST_BASE(1.34)
|
||||
|
||||
# TODO: Fix code to pass with -pedantic -Wextra.
|
||||
# -Wno-unknown-pragmas needed because icalstrdup.h
|
||||
# currently uses the "#pragma }" trick. Should remove that.
|
||||
|
@ -517,21 +522,48 @@ if test $enable_dbus_service = "yes"; then
|
|||
AC_DEFINE(DBUS_SERVICE, 1, [define if dbus service is enabled])
|
||||
|
||||
AC_ARG_ENABLE(dbus-service-pim,
|
||||
AS_HELP_STRING([--enable-dbus-service-pim],
|
||||
[enable implementation of org._01.pim D-Bus APIs (depends on libfolks)]),
|
||||
AS_HELP_STRING([--enable-dbus-service-pim[=<locale>]],
|
||||
[Enable implementation of org._01.pim D-Bus APIs (depends on libfolks),
|
||||
using src/dbus/server/pim/locale-factory-<locale>.cpp to implement sorting
|
||||
and searching. The default is <locale>=boost, which uses boost::locale.]),
|
||||
[ enable_dbus_pim="$enableval" ],
|
||||
[ enable_dbus_pim="no" ])
|
||||
case "$enable_dbus_pim" in
|
||||
no) ;;
|
||||
yes)
|
||||
*)
|
||||
if test "$enable_dbus_pim" = "yes"; then
|
||||
enable_dbus_pim=boost
|
||||
fi
|
||||
if ! test -r "$srcdir/src/dbus/server/pim/locale-factory-$enable_dbus_pim.cpp"; then
|
||||
AC_MSG_ERROR([invalid value '$enable_dbus_pim' for --enable-dbus-service-pim, $srcdir/src/dbus/server/pim/locale-factory-$enable_dbus_pim.cpp does not exist or is not readable])
|
||||
fi
|
||||
PKG_CHECK_MODULES(FOLKS, [folks])
|
||||
AC_DEFINE(ENABLE_DBUS_PIM, 1, [org._01.pim D-Bus API enabled])
|
||||
DBUS_PIM_PLUGIN=$enable_dbus_pim
|
||||
AC_SUBST(DBUS_PIM_PLUGIN)
|
||||
|
||||
case "$enable_dbus_pim" in
|
||||
boost)
|
||||
AX_BOOST_LOCALE
|
||||
# AX_BOOST_LOCALE incorrectly puts -L/... into LDFLAGS.
|
||||
# That's broken because it then overrides the search path
|
||||
# for *all* libraries in a link, not just for boost. Fix
|
||||
# this by putting the LDFLAGS before the lib and leaving
|
||||
# DBUS_PIM_PLUGIN_LDFLAGS empty (for now - might have to
|
||||
# be revised if there ever are any boost flags which need
|
||||
# to go to the start of the link line).
|
||||
DBUS_PIM_PLUGIN_LIBS='$(BOOST_LDFLAGS) $(BOOST_LOCALE_LIB)'
|
||||
DBUS_PIM_PLUGIN_LDFLAGS=
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(DBUS_PIM_PLUGIN_CFLAGS)
|
||||
AC_SUBST(DBUS_PIM_PLUGIN_LIBS)
|
||||
AC_SUBST(DBUS_PIM_PLUGIN_LDFLAGS)
|
||||
;;
|
||||
*) AC_MSG_ERROR([invalid value for --enable-dbus-service-pim: '$enable_dbus_pim']);;
|
||||
esac
|
||||
fi
|
||||
AM_CONDITIONAL([NOTIFY_COMPATIBILITY], [test "$enable_notify_compat" = "yes"])
|
||||
AM_CONDITIONAL([COND_DBUS_PIM], [test "$enable_dbus_pim" = "yes"])
|
||||
AM_CONDITIONAL([COND_DBUS_PIM], [test "$enable_dbus_pim" != "no"])
|
||||
|
||||
AC_SUBST(DBUS_CFLAGS)
|
||||
AC_SUBST(DBUS_LIBS)
|
||||
|
@ -623,11 +655,6 @@ AC_SUBST(GUI_LIBS)
|
|||
AC_SUBST(GUI_PROGRAMS)
|
||||
AC_SUBST(GUI_DESKTOP_FILES)
|
||||
|
||||
# Boost headers: boost/foreach.hpp is needed (1.33/Debian Etch
|
||||
# doesn't have it, 1.34/Ubuntu 8.10 Hardy does). 1.35 is available
|
||||
# as Debian Etch backport.
|
||||
AX_BOOST_BASE(1.34)
|
||||
|
||||
# C++ regular expression support is required often enough to make it
|
||||
# mandatory.
|
||||
PKG_CHECK_MODULES(PCRECPP, libpcrecpp)
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_boost_locale.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_LOCALE
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for System library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_LOCALE_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_LOCALE
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2012 Xiyue Deng <manphiz@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 1
|
||||
|
||||
AC_DEFUN([AX_BOOST_LOCALE],
|
||||
[
|
||||
AC_ARG_WITH([boost-locale],
|
||||
AS_HELP_STRING([--with-boost-locale@<:@=special-lib@:>@],
|
||||
[use the Locale library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-locale=boost_locale-gcc-mt ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_locale_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_locale_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::Locale library is available,
|
||||
ax_cv_boost_locale,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/locale.hpp>]],
|
||||
[[boost::locale::generator gen;
|
||||
std::locale::global(gen(""));]])],
|
||||
ax_cv_boost_locale=yes, ax_cv_boost_locale=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_locale" = "xyes"; then
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
|
||||
AC_DEFINE(HAVE_BOOST_LOCALE,,[define if the Boost::Locale library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
if test "x$ax_boost_user_locale_lib" = "x"; then
|
||||
for libextension in `ls $BOOSTLIBDIR/libboost_locale*.so* $BOOSTLIBDIR/libboost_locale*.dylib* $BOOSTLIBDIR/libboost_locale*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_locale.*\)\.so.*$;\1;' -e 's;^lib\(boost_locale.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_locale.*\)\.a.*$;\1;'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_LOCALE_LIB="-l$ax_lib"; AC_SUBST(BOOST_LOCALE_LIB) link_locale="yes"; break],
|
||||
[link_locale="no"])
|
||||
done
|
||||
if test "x$link_locale" != "xyes"; then
|
||||
for libextension in `ls $BOOSTLIBDIR/boost_locale*.dll* $BOOSTLIBDIR/boost_locale*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_locale.*\)\.dll.*$;\1;' -e 's;^\(boost_locale.*\)\.a.*$;\1;'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_LOCALE_LIB="-l$ax_lib"; AC_SUBST(BOOST_LOCALE_LIB) link_locale="yes"; break],
|
||||
[link_locale="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_locale_lib boost_locale-$ax_boost_user_locale_lib; do
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_LOCALE_LIB="-l$ax_lib"; AC_SUBST(BOOST_LOCALE_LIB) link_locale="yes"; break],
|
||||
[link_locale="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the library!)
|
||||
fi
|
||||
if test "x$link_locale" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
|
@ -87,6 +87,14 @@ void IndividualData::init(const boost::shared_ptr<IndividualCompare> &compare,
|
|||
compare->createCriteria(individual, m_criteria);
|
||||
}
|
||||
|
||||
void IndividualView::start()
|
||||
{
|
||||
if (!m_started) {
|
||||
m_started = true;
|
||||
doStart();
|
||||
}
|
||||
}
|
||||
|
||||
void IndividualView::readContacts(int start, int count, std::vector<FolksIndividualCXX> &contacts)
|
||||
{
|
||||
contacts.clear();
|
||||
|
@ -138,7 +146,12 @@ FullView::FullView(const FolksIndividualAggregatorCXX &folks) :
|
|||
{
|
||||
}
|
||||
|
||||
void FullView::init()
|
||||
void FullView::init(const boost::shared_ptr<FullView> &self)
|
||||
{
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
void FullView::doStart()
|
||||
{
|
||||
// Populate view from current set of data. Usually FullView
|
||||
// gets instantiated when the aggregator is idle, in which
|
||||
|
@ -162,9 +175,14 @@ void FullView::init()
|
|||
}
|
||||
individuals.sort(IndividualDataCompare(m_compare));
|
||||
|
||||
// Copy the sorted data into the view. No slots are called,
|
||||
// because nothing can be connected at the moment.
|
||||
// Copy the sorted data into the view in one go.
|
||||
m_entries.insert(m_entries.begin(), individuals.begin(), individuals.end());
|
||||
// Avoid loop if no-one is listening.
|
||||
if (!m_addedSignal.empty()) {
|
||||
for (size_t index = 0; index < m_entries.size(); index++) {
|
||||
m_addedSignal(index, m_entries[index].m_individual);
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to changes. Aggregator might live longer than we do, so
|
||||
// bind to weak pointer and check our existence at runtime.
|
||||
|
@ -181,13 +199,14 @@ void FullView::init()
|
|||
GParamSpec *pspec)>("notify::is-quiescent",
|
||||
boost::bind(&FullView::quiesenceChanged,
|
||||
m_self));
|
||||
|
||||
|
||||
}
|
||||
|
||||
boost::shared_ptr<FullView> FullView::create(const FolksIndividualAggregatorCXX &folks)
|
||||
{
|
||||
boost::shared_ptr<FullView> view(new FullView(folks));
|
||||
view->m_self = view;
|
||||
view->init();
|
||||
view->init(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -353,22 +372,74 @@ void FullView::waitForIdle()
|
|||
|
||||
void FullView::setCompare(const boost::shared_ptr<IndividualCompare> &compare)
|
||||
{
|
||||
// TODO
|
||||
if (!compare) {
|
||||
// Fall back to debug ordering.
|
||||
m_compare.reset(new CompareFormattedName());
|
||||
} else {
|
||||
m_compare = compare;
|
||||
}
|
||||
|
||||
// Reorder a copy of the current data.
|
||||
Entries_t entries(m_entries);
|
||||
BOOST_FOREACH (IndividualData &data, entries) {
|
||||
data.init(m_compare, data.m_individual);
|
||||
}
|
||||
std::sort(entries.begin(), entries.end(), IndividualDataCompare(m_compare));
|
||||
|
||||
// Now update real array.
|
||||
for (size_t index = 0; index < entries.size(); index++) {
|
||||
IndividualData &previous = m_entries[index],
|
||||
¤t = entries[index];
|
||||
if (previous.m_individual != current.m_individual) {
|
||||
// Contact at the index changed. Don't try to find out
|
||||
// where it came from now. The effect is that temporarily
|
||||
// the same contact might be shown at two different
|
||||
// indices.
|
||||
m_modifiedSignal(index, current.m_individual);
|
||||
}
|
||||
// Ensure that m_entries is up-to-date, whatever the change
|
||||
// may have been.
|
||||
std::swap(previous, current);
|
||||
}
|
||||
|
||||
// Current status is stable again, send out all modifications.
|
||||
m_quiesenceSignal();
|
||||
}
|
||||
|
||||
FilteredView::FilteredView(const boost::shared_ptr<IndividualView> &parent,
|
||||
const boost::shared_ptr<IndividualFilter> &filter) :
|
||||
m_parent(parent),
|
||||
m_filter(filter)
|
||||
{
|
||||
}
|
||||
|
||||
void FilteredView::init(const boost::shared_ptr<FilteredView> &self)
|
||||
{
|
||||
m_self = self;
|
||||
m_parent->m_quiesenceSignal.connect(QuiesenceSignal_t::slot_type(boost::bind(boost::cref(m_quiesenceSignal))).track(m_self));
|
||||
}
|
||||
|
||||
boost::shared_ptr<FilteredView> FilteredView::create(const boost::shared_ptr<IndividualView> &parent,
|
||||
const boost::shared_ptr<IndividualFilter> &filter)
|
||||
{
|
||||
boost::shared_ptr<FilteredView> view(new FilteredView);
|
||||
view->m_self = view;
|
||||
view->m_parent = parent;
|
||||
parent->m_quiesenceSignal.connect(QuiesenceSignal_t::slot_type(boost::bind(boost::cref(view->m_quiesenceSignal))).track(view->m_self));
|
||||
// TODO
|
||||
boost::shared_ptr<FilteredView> view(new FilteredView(parent, filter));
|
||||
view->init(view);
|
||||
return view;
|
||||
}
|
||||
void FilteredView::start()
|
||||
|
||||
void FilteredView::doStart()
|
||||
{
|
||||
// TODO
|
||||
// Add initial content. Our processing of the new contact must not
|
||||
// cause changes to the parent view, otherwise the result will not
|
||||
// be inconsistent.
|
||||
for (int index = 0; index < m_parent->size(); index++) {
|
||||
addIndividual(index, m_parent->getContact(index));
|
||||
}
|
||||
|
||||
// Start listening to signals.
|
||||
m_parent->m_addedSignal.connect(ChangeSignal_t::slot_type(boost::bind(&FilteredView::addIndividual, this, _1, _2)).track(m_self));
|
||||
m_parent->m_modifiedSignal.connect(ChangeSignal_t::slot_type(boost::bind(&FilteredView::modifyIndividual, this, _1, _2)).track(m_self));
|
||||
m_parent->m_removedSignal.connect(ChangeSignal_t::slot_type(boost::bind(&FilteredView::removeIndividual, this, _1, _2)).track(m_self));
|
||||
}
|
||||
void FilteredView::addIndividual(int parentIndex, FolksIndividual *individual)
|
||||
{
|
||||
|
@ -378,7 +449,7 @@ void FilteredView::removeIndividual(int parentIndex, FolksIndividual *individual
|
|||
{
|
||||
// TODO
|
||||
}
|
||||
void FilteredView::changeIndividual(int parentIndex, FolksIndividual *individual)
|
||||
void FilteredView::modifyIndividual(int parentIndex, FolksIndividual *individual)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
@ -500,7 +571,7 @@ void IndividualAggregator::start()
|
|||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<IndividualView> IndividualAggregator::getMainView()
|
||||
boost::shared_ptr<FullView> IndividualAggregator::getMainView()
|
||||
{
|
||||
if (!m_view) {
|
||||
start();
|
||||
|
|
|
@ -151,6 +151,8 @@ class IndividualAggregator;
|
|||
*/
|
||||
class IndividualView
|
||||
{
|
||||
Bool m_started;
|
||||
|
||||
public:
|
||||
typedef boost::signals2::signal<void (int, FolksIndividual *)> ChangeSignal_t;
|
||||
typedef boost::signals2::signal<void (void)> QuiesenceSignal_t;
|
||||
|
@ -182,6 +184,12 @@ class IndividualView
|
|||
*/
|
||||
ChangeSignal_t m_modifiedSignal;
|
||||
|
||||
/**
|
||||
* Start filling the view. Gives the user a chance to connect
|
||||
* to the signals first. May be called multiple times.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/** current number of entries */
|
||||
virtual int size() const = 0;
|
||||
|
||||
|
@ -190,6 +198,12 @@ class IndividualView
|
|||
|
||||
/** returns access to one individual or an empty pointer if outside of the current range */
|
||||
virtual FolksIndividualCXX getContact(int index) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Start filling the view. Will only be called once by start().
|
||||
*/
|
||||
virtual void doStart() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -215,7 +229,7 @@ class FullView : public IndividualView
|
|||
boost::shared_ptr<IndividualCompare> m_compare;
|
||||
|
||||
FullView(const FolksIndividualAggregatorCXX &folks);
|
||||
void init();
|
||||
void init(const boost::shared_ptr<FullView> &self);
|
||||
|
||||
/**
|
||||
* Run via m_waitForIdle if (and only if) something
|
||||
|
@ -281,10 +295,13 @@ class FullView : public IndividualView
|
|||
* Set new sort method. Reorders current set of entries on the
|
||||
* fly. Default is lexicographical comparison of the single-string
|
||||
* full name.
|
||||
*
|
||||
* @param compare the new ordering or NULL for the builtin default (last/first with ASCII lexicographic comparison)
|
||||
*/
|
||||
void setCompare(const boost::shared_ptr<IndividualCompare> &compare);
|
||||
|
||||
// from IndividualView
|
||||
virtual void doStart();
|
||||
virtual int size() const { return (int)m_entries.size(); }
|
||||
virtual FolksIndividualCXX getContact(int index) { return (index >= 0 && (unsigned)index < m_entries.size()) ? m_entries[index].m_individual : FolksIndividualCXX(); }
|
||||
};
|
||||
|
@ -297,8 +314,8 @@ class FullView : public IndividualView
|
|||
class FilteredView : public IndividualView
|
||||
{
|
||||
boost::weak_ptr<FilteredView> m_self;
|
||||
boost::shared_ptr<IndividualFilter> m_filter;
|
||||
boost::shared_ptr<IndividualView> m_parent;
|
||||
boost::shared_ptr<IndividualFilter> m_filter;
|
||||
|
||||
/**
|
||||
* Maps local indices to indices in parent view. Could be be
|
||||
|
@ -307,6 +324,10 @@ class FilteredView : public IndividualView
|
|||
*/
|
||||
std::vector<int> m_local2parent;
|
||||
|
||||
FilteredView(const boost::shared_ptr<IndividualView> &parent,
|
||||
const boost::shared_ptr<IndividualFilter> &filter);
|
||||
void init(const boost::shared_ptr<FilteredView> &self);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an idle IndividualAggregator. Configure it and
|
||||
|
@ -315,12 +336,6 @@ class FilteredView : public IndividualView
|
|||
static boost::shared_ptr<FilteredView> create(const boost::shared_ptr<IndividualView> &parent,
|
||||
const boost::shared_ptr<IndividualFilter> &filter);
|
||||
|
||||
/**
|
||||
* Populates view from current content of parent, then
|
||||
* updates it based on incoming signals.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Add a FolksIndividual if it matches the filter. Tracking of
|
||||
* changes to individuals is done in parent view.
|
||||
|
@ -335,9 +350,10 @@ class FilteredView : public IndividualView
|
|||
/**
|
||||
* Check whether a changed individual still belongs into the view.
|
||||
*/
|
||||
void changeIndividual(int parentIndex, FolksIndividual *individual);
|
||||
void modifyIndividual(int parentIndex, FolksIndividual *individual);
|
||||
|
||||
// from IndividualView
|
||||
virtual void doStart();
|
||||
virtual int size() const { return (int)m_local2parent.size(); }
|
||||
virtual FolksIndividualCXX getContact(int index) { return (index >= 0 && (unsigned)index < m_local2parent.size()) ? m_parent->getContact(m_local2parent[index]) : FolksIndividualCXX(); }
|
||||
};
|
||||
|
@ -414,7 +430,7 @@ class IndividualAggregator
|
|||
*
|
||||
* @return never empty, start() will be called if necessary
|
||||
*/
|
||||
boost::shared_ptr<IndividualView> getMainView();
|
||||
boost::shared_ptr<FullView> getMainView();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 boost::locale based implementation of locale-factory.h.
|
||||
*/
|
||||
|
||||
#include "locale-factory.h"
|
||||
#include "folks.h"
|
||||
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
SE_BEGIN_CXX
|
||||
|
||||
class LocaleFactoryBoost : public LocaleFactory
|
||||
{
|
||||
std::locale m_locale;
|
||||
|
||||
public:
|
||||
LocaleFactoryBoost() :
|
||||
m_locale(boost::locale::generator()(""))
|
||||
{}
|
||||
|
||||
virtual boost::shared_ptr<IndividualCompare> createCompare(const std::string &order)
|
||||
{
|
||||
SE_THROW("not implemented");
|
||||
}
|
||||
|
||||
virtual boost::shared_ptr<IndividualFilter> createFilter(const StringMap &filter)
|
||||
{
|
||||
SE_THROW("not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
boost::shared_ptr<LocaleFactory> LocaleFactory::createFactory()
|
||||
{
|
||||
return boost::shared_ptr<LocaleFactory>(new LocaleFactoryBoost());
|
||||
}
|
||||
|
||||
SE_END_CXX
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract definition of sorting and searching plugin. Used
|
||||
* by folks.cpp, must be provided by exactly one implementation
|
||||
* which is chosen at compile time.
|
||||
*/
|
||||
|
||||
#ifndef INCL_SYNCEVO_DBUS_SERVER_PIM_LOCALE_FACTORY
|
||||
#define INCL_SYNCEVO_DBUS_SERVER_PIM_LOCALE_FACTORY
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <syncevo/util.h>
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
SE_BEGIN_CXX
|
||||
|
||||
class IndividualCompare;
|
||||
class IndividualFilter;
|
||||
|
||||
/**
|
||||
* Factory for everything related to the current locale: sorting and
|
||||
* searching.
|
||||
*/
|
||||
class LocaleFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Exactly one factory can be created, chosen at compile time.
|
||||
*/
|
||||
static boost::shared_ptr<LocaleFactory> createFactory();
|
||||
|
||||
/**
|
||||
* Creates a compare instance or throws an error when that is not
|
||||
* possible.
|
||||
*
|
||||
* @param order factory-specific string which chooses one of
|
||||
* the orderings supported by the factory
|
||||
* @return a valid instance, must not be NULL
|
||||
*/
|
||||
virtual boost::shared_ptr<IndividualCompare> createCompare(const std::string &order) = 0;
|
||||
|
||||
/**
|
||||
* An array of search terms which all must match. Each search term
|
||||
* itself is again an array of strings, with the first one choosing
|
||||
* the search criteria and the rest providing parameters for that
|
||||
* search term.
|
||||
*/
|
||||
typedef std::vector< std::vector<std::string> > Filter_t;
|
||||
|
||||
/**
|
||||
* Creates a filter instance or throws an error when that is not
|
||||
* possible.
|
||||
*
|
||||
* @param order factory-specific string which chooses one of
|
||||
* the search criteria supported by the factory
|
||||
* @return a valid instance, must not be NULL
|
||||
*/
|
||||
virtual boost::shared_ptr<IndividualFilter> createFilter(const Filter_t &filter) = 0;
|
||||
};
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
#endif // INCL_SYNCEVO_DBUS_SERVER_PIM_LOCALE_FACTORY
|
|
@ -60,7 +60,8 @@ Manager::Manager(const boost::shared_ptr<Server> &server) :
|
|||
DBusObjectHelper(server->getConnection(),
|
||||
MANAGER_PATH,
|
||||
MANAGER_IFACE),
|
||||
m_server(server)
|
||||
m_server(server),
|
||||
m_locale(LocaleFactory::createFactory())
|
||||
{
|
||||
// Prevent automatic shut down during idle times, because we need
|
||||
// to keep our unified address book available.
|
||||
|
@ -78,7 +79,7 @@ Manager::~Manager()
|
|||
void Manager::init()
|
||||
{
|
||||
// TODO: restore sort order
|
||||
m_sortOrder = "first/last";
|
||||
m_sortOrder = ""; // use default sorting in FullView
|
||||
initFolks();
|
||||
initSorting();
|
||||
|
||||
|
@ -110,8 +111,15 @@ void Manager::initFolks()
|
|||
|
||||
void Manager::initSorting()
|
||||
{
|
||||
// TODO: mirror m_sortOrder in m_folks main view
|
||||
|
||||
// Mirror m_sortOrder in m_folks main view.
|
||||
// Empty string passes NULL pointer to setCompare(),
|
||||
// which chooses the builtin sorting in folks.cpp,
|
||||
// independent of the locale plugin.
|
||||
boost::shared_ptr<IndividualCompare> compare;
|
||||
if (!m_sortOrder.empty()) {
|
||||
compare = m_locale->createCompare(m_sortOrder);
|
||||
}
|
||||
m_folks->getMainView()->setCompare(compare);
|
||||
}
|
||||
|
||||
boost::shared_ptr<Manager> Manager::create(const boost::shared_ptr<Server> &server)
|
||||
|
@ -388,6 +396,14 @@ class ViewResource : public Resource, public GDBusCXX::DBusObjectHelper
|
|||
add(this, &ViewResource::refineSearch, "RefineSearch");
|
||||
activate();
|
||||
|
||||
// The view might have been started already, for example when
|
||||
// reconnecting a ViewResource to the persistent full view.
|
||||
// Therefore tell the agent about the current content before
|
||||
// starting, then connect to signals, and finally start.
|
||||
int size = m_view->size();
|
||||
if (size) {
|
||||
sendChange(m_contactsAdded, 0, size);
|
||||
}
|
||||
m_view->m_quiesenceSignal.connect(IndividualView::QuiesenceSignal_t::slot_type(&ViewResource::flushChanges,
|
||||
this).track(self));
|
||||
m_view->m_modifiedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::handleChange,
|
||||
|
@ -405,7 +421,7 @@ class ViewResource : public Resource, public GDBusCXX::DBusObjectHelper
|
|||
boost::cref(m_contactsRemoved),
|
||||
_1,
|
||||
1).track(self));
|
||||
|
||||
m_view->start();
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -478,8 +494,11 @@ GDBusCXX::DBusObject_t Manager::search(const GDBusCXX::Caller_t &ID,
|
|||
boost::shared_ptr<Client> client = m_server->addClient(ID, watch);
|
||||
|
||||
boost::shared_ptr<IndividualView> view;
|
||||
// TODO: parse filter
|
||||
view = m_folks->getMainView();
|
||||
if (!filter.empty()) {
|
||||
boost::shared_ptr<IndividualFilter> individualFilter = m_locale->createFilter(filter);
|
||||
view = FilteredView::create(view, individualFilter);
|
||||
}
|
||||
|
||||
boost::shared_ptr<ViewResource> viewResource(ViewResource::create(view,
|
||||
client,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
|
||||
|
||||
#include "folks.h"
|
||||
#include "locale-factory.h"
|
||||
#include "../server.h"
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
|
@ -39,6 +40,7 @@ class Manager : public GDBusCXX::DBusObjectHelper
|
|||
boost::weak_ptr<Manager> m_self;
|
||||
boost::shared_ptr<Server> m_server;
|
||||
boost::shared_ptr<IndividualAggregator> m_folks;
|
||||
boost::shared_ptr<LocaleFactory> m_locale;
|
||||
std::string m_sortOrder;
|
||||
/**
|
||||
* Contains the EDS UUIDs of all address books contributing to the current
|
||||
|
|
|
@ -43,8 +43,11 @@ src_dbus_server_libsyncevodbusserver_la_SOURCES = \
|
|||
$(src_dbus_server_server_cpp_files) \
|
||||
src/dbus/server/main.cpp
|
||||
|
||||
nodist_src_dbus_server_libsyncevodbusserver_la_SOURCES =
|
||||
|
||||
dist_pkgdata_DATA += src/dbus/server/bluetooth_products.ini
|
||||
|
||||
src_dbus_server_libsyncevodbusserver_la_LDFLAGS =
|
||||
src_dbus_server_libsyncevodbusserver_la_LIBADD = $(LIBNOTIFY_LIBS) $(MLITE_LIBS) $(DBUS_LIBS)
|
||||
src_dbus_server_libsyncevodbusserver_la_CPPFLAGS = -DHAVE_CONFIG_H -DSYNCEVOLUTION_LOCALEDIR=\"${SYNCEVOLUTION_LOCALEDIR}\" -I$(top_srcdir)/src -I$(top_srcdir)/test -I$(top_srcdir) -I$(gdbus_dir) $(BACKEND_CPPFLAGS)
|
||||
src_dbus_server_libsyncevodbusserver_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) $(CORE_CXXFLAGS) $(SYNTHESIS_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) $(LIBNOTIFY_CFLAGS) $(MLITE_CFLAGS) $(SYNCEVO_WFLAGS)
|
||||
|
@ -54,10 +57,23 @@ src_dbus_server_server_cpp_files += \
|
|||
src/dbus/server/pim/individual-traits.cpp \
|
||||
src/dbus/server/pim/folks.cpp \
|
||||
src/dbus/server/pim/manager.cpp
|
||||
src_dbus_server_libsyncevodbusserver_la_LIBADD += $(FOLKS_LIBS)
|
||||
src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS)
|
||||
|
||||
src_dbus_server_server_h_files += \
|
||||
src/dbus/server/pim/locale-factory.h
|
||||
|
||||
nodist_src_dbus_server_libsyncevodbusserver_la_SOURCES += \
|
||||
src/dbus/server/pim/locale-factory-@DBUS_PIM_PLUGIN@.cpp
|
||||
|
||||
src_dbus_server_libsyncevodbusserver_la_LDFLAGS += $(DBUS_PIM_PLUGIN_LDFLAGS)
|
||||
src_dbus_server_libsyncevodbusserver_la_LIBADD += $(FOLKS_LIBS) $(DBUS_PIM_PLUGIN_LIBS)
|
||||
src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS) $(DBUS_PIM_PLUGIN_CFLAGS)
|
||||
endif
|
||||
|
||||
# Need to list all plugins here and not include the active one in the regular
|
||||
# source list above, because "make dist" would only include the configured one.
|
||||
EXTRA_DIST += \
|
||||
src/dbus/server/pim/locale-factory-boost.cpp
|
||||
|
||||
# Session helper: syncevo-dbus-helper
|
||||
noinst_LTLIBRARIES += src/dbus/server/libsyncevodbushelper.la
|
||||
|
||||
|
|
Loading…
Reference in New Issue