1/*
2 This file is part of libkabc.
3 Copyright (c) 2002 Jost Schenck <jost@schenck.de>
4 2003 Tobias Koenig <tokoe@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "addresseelist.h"
23#include "field.h"
24#include "sortmode.h"
25
26#include <kdebug.h>
27
28#include <QtCore/QSharedData>
29
30using namespace KABC;
31
32//
33//
34// Traits
35//
36//
37
38SortingTraits::Uid::Uid()
39 : d( 0 )
40{
41}
42
43SortingTraits::Uid::~Uid()
44{
45}
46
47bool SortingTraits::Uid::eq( const Addressee &a1, const Addressee &a2 )
48{
49 // locale awareness doesn't make sense sorting ids
50 return QString::compare( a1.uid(), a2.uid() ) == 0;
51}
52
53bool SortingTraits::Uid::lt( const Addressee &a1, const Addressee &a2 )
54{
55 // locale awareness doesn't make sense sorting ids
56 return QString::compare( a1.uid(), a2.uid() ) < 0;
57}
58
59SortingTraits::Name::Name()
60 : d( 0 )
61{
62}
63
64SortingTraits::Name::~Name()
65{
66}
67
68bool SortingTraits::Name::eq( const Addressee &a1, const Addressee &a2 )
69{
70 return QString::localeAwareCompare( a1.name(), a2.name() ) == 0;
71}
72
73bool SortingTraits::Name::lt( const Addressee &a1, const Addressee &a2 )
74{
75 return QString::localeAwareCompare( a1.name(), a2.name() ) < 0;
76}
77
78SortingTraits::FormattedName::FormattedName()
79 : d( 0 )
80{
81}
82
83SortingTraits::FormattedName::~FormattedName()
84{
85}
86
87bool SortingTraits::FormattedName::eq( const Addressee &a1, const Addressee &a2 )
88{
89 return QString::localeAwareCompare( a1.formattedName(), a2.formattedName() ) == 0;
90}
91
92bool SortingTraits::FormattedName::lt( const Addressee &a1, const Addressee &a2 )
93{
94 return QString::localeAwareCompare( a1.formattedName(), a2.formattedName() ) < 0;
95}
96
97SortingTraits::FamilyName::FamilyName()
98 : d( 0 )
99{
100}
101
102SortingTraits::FamilyName::~FamilyName()
103{
104}
105
106bool SortingTraits::FamilyName::eq( const Addressee &a1, const Addressee &a2 )
107{
108 return
109 QString::localeAwareCompare( a1.familyName(), a2.familyName() ) == 0 &&
110 QString::localeAwareCompare( a1.givenName(), a2.givenName() ) == 0;
111}
112
113bool SortingTraits::FamilyName::lt( const Addressee &a1, const Addressee &a2 )
114{
115 int family = QString::localeAwareCompare( a1.familyName(), a2.familyName() );
116 if ( 0 == family ) {
117 return QString::localeAwareCompare( a1.givenName(), a2.givenName() ) < 0;
118 } else {
119 return family < 0;
120 }
121}
122
123SortingTraits::GivenName::GivenName()
124 : d( 0 )
125{
126}
127
128SortingTraits::GivenName::~GivenName()
129{
130}
131
132bool SortingTraits::GivenName::eq( const Addressee &a1, const Addressee &a2 )
133{
134 return
135 QString::localeAwareCompare( a1.givenName(), a2.givenName() ) == 0 &&
136 QString::localeAwareCompare( a1.familyName(), a2.familyName() ) == 0;
137}
138
139bool SortingTraits::GivenName::lt( const Addressee &a1, const Addressee &a2 )
140{
141 int given = QString::localeAwareCompare( a1.givenName(), a2.givenName() );
142 if ( 0 == given ) {
143 return QString::localeAwareCompare( a1.familyName(), a2.familyName() ) < 0;
144 } else {
145 return given < 0;
146 }
147}
148
149//
150//
151// AddresseeList
152//
153//
154
155static Field *sActiveField=0;
156
157class AddresseeList::Private : public QSharedData
158{
159 public:
160 Private()
161 : mReverseSorting( false ), mActiveSortingCriterion( FormattedName )
162 {
163 }
164
165 Private( const Private &other )
166 : QSharedData( other )
167 {
168 mReverseSorting = other.mReverseSorting;
169 mActiveSortingCriterion = other.mActiveSortingCriterion;
170 }
171
172 bool mReverseSorting;
173 SortingCriterion mActiveSortingCriterion;
174};
175
176AddresseeList::AddresseeList()
177 : QList<Addressee>(), d( new Private )
178{
179}
180
181AddresseeList::~AddresseeList()
182{
183}
184
185AddresseeList::AddresseeList( const AddresseeList &other )
186 : QList<Addressee>( other ), d( other.d )
187{
188}
189
190AddresseeList::AddresseeList( const QList<Addressee> &l )
191 : QList<Addressee>( l ), d( new Private )
192{
193}
194
195AddresseeList &AddresseeList::operator=( const AddresseeList &other )
196{
197 if ( this != &other ) {
198 QList<Addressee>::operator=( other );
199 d = other.d;
200 }
201
202 return *this;
203}
204
205QString AddresseeList::toString() const
206{
207 QString str;
208
209 str += QLatin1String( "AddresseeList {\n" );
210 str += QString::fromLatin1( " Reverse Order: %1\n" ).arg( d->mReverseSorting ?
211 QLatin1String( "true" ) :
212 QLatin1String( "false" ) );
213
214 QString crit;
215 if ( Uid == d->mActiveSortingCriterion ) {
216 crit = QLatin1String( "Uid" );
217 } else if ( Name == d->mActiveSortingCriterion ) {
218 crit = QLatin1String( "Name" );
219 } else if ( FormattedName == d->mActiveSortingCriterion ) {
220 crit = QLatin1String( "FormattedName" );
221 } else if ( FamilyName == d->mActiveSortingCriterion ) {
222 crit = QLatin1String( "FamilyName" );
223 } else if ( GivenName == d->mActiveSortingCriterion ) {
224 crit = QLatin1String( "GivenName" );
225 } else {
226 crit = QLatin1String( "unknown -- update dump method" );
227 }
228
229 str += QString::fromLatin1( " Sorting criterion: %1\n" ).arg( crit );
230#if 0 //code commented in loop => comment it too
231 for ( const_iterator it = begin(); it != end(); ++it ) {
232// str += (*it).toString();
233 }
234#endif
235
236 str += QLatin1String( "}\n" );
237
238 return str;
239}
240
241void AddresseeList::setReverseSorting( bool reverseSorting )
242{
243 d->mReverseSorting = reverseSorting;
244}
245
246bool AddresseeList::reverseSorting() const
247{
248 return d->mReverseSorting;
249}
250
251void AddresseeList::sortBy( SortingCriterion c )
252{
253 d->mActiveSortingCriterion = c;
254 if ( Uid == c ) {
255 sortByTrait<SortingTraits::Uid>();
256 } else if ( Name == c ) {
257 sortByTrait<SortingTraits::Name>();
258 } else if ( FormattedName == c ) {
259 sortByTrait<SortingTraits::FormattedName>();
260 } else if ( FamilyName == c ) {
261 sortByTrait<SortingTraits::FamilyName>();
262 } else if ( GivenName == c ) {
263 sortByTrait<SortingTraits::GivenName>();
264 } else {
265 kError( 5700 ) << "AddresseeList sorting criterion passed for which a trait is not known."
266 << "No sorting done.";
267 }
268}
269
270void AddresseeList::sort()
271{
272 sortBy( d->mActiveSortingCriterion );
273}
274
275template<class Trait>
276void AddresseeList::sortByTrait()
277{
278 // FIXME: better sorting algorithm, bubblesort is not acceptable for larger lists.
279 //
280 // for i := 1 to n - 1
281 // do for j := 1 to n - i
282 // do if A[j] > A[j+1]
283 // then temp := A[j]
284 // A[j] := A[j + 1]
285 // A[j + 1 ] := temp
286
287 iterator i1 = begin();
288 iterator endIt = end();
289 --endIt;
290 if ( i1 == endIt ) { // don't need sorting
291 return;
292 }
293
294 iterator i2 = endIt;
295 while ( i1 != endIt ) {
296 iterator j1 = begin();
297 iterator j2 = j1;
298 ++j2;
299 while ( j1 != i2 ) {
300 if ( ( !d->mReverseSorting && Trait::lt( *j2, *j1 ) ) ||
301 ( d->mReverseSorting && Trait::lt( *j1, *j2 ) ) ) {
302 qSwap( *j1, *j2 );
303 }
304 ++j1;
305 ++j2;
306 }
307 ++i1;
308 --i2;
309 }
310}
311
312void AddresseeList::sortByField( Field *field )
313{
314 if ( !field ) {
315 kWarning( 5700 ) << "sortByField called with no active sort field";
316 return;
317 }
318
319 sActiveField = field;
320
321 if ( count() == 0 ) {
322 return;
323 }
324
325 KABC::FieldSortMode *mode = new KABC::FieldSortMode( sActiveField, !d->mReverseSorting );
326
327 KABC::Addressee::setSortMode( mode );
328 qSort( *this );
329 KABC::Addressee::setSortMode( 0 );
330
331 delete mode;
332}
333
334void AddresseeList::sortByMode( SortMode *mode )
335{
336 if ( count() == 0 ) {
337 return;
338 }
339
340 KABC::Addressee::setSortMode( mode );
341 qSort( *this );
342 KABC::Addressee::setSortMode( 0 );
343}
344
345SortingCriterion AddresseeList::sortingCriterion() const
346{
347 return d->mActiveSortingCriterion;
348}
349
350Field *AddresseeList::sortingField() const
351{
352 return sActiveField;
353}
354