summaryrefslogtreecommitdiffabout
path: root/kabc/address.cpp
Unidiff
Diffstat (limited to 'kabc/address.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--kabc/address.cpp630
1 files changed, 630 insertions, 0 deletions
diff --git a/kabc/address.cpp b/kabc/address.cpp
new file mode 100644
index 0000000..26e0b6a
--- a/dev/null
+++ b/kabc/address.cpp
@@ -0,0 +1,630 @@
1/*
2 This file is part of libkabc.
3 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/*
22Enhanced Version of the file for platform independent KDE tools.
23Copyright (c) 2004 Ulf Schenk
24
25$Id$
26*/
27
28//US added kglobal.h
29#include <kglobal.h>
30
31#include <kapplication.h>
32#include <kdebug.h>
33#include <klocale.h>
34#include <ksimpleconfig.h>
35#include <kstandarddirs.h>
36
37#include <qfile.h>
38
39#include "address.h"
40
41using namespace KABC;
42
43QMap<QString, QString> Address::mISOMap;
44
45Address::Address() :
46 mEmpty( true ), mType( 0 )
47{
48 mId = KApplication::randomString( 10 );
49}
50
51Address::Address( int type ) :
52 mEmpty( true ), mType( type )
53{
54 mId = KApplication::randomString( 10 );
55}
56
57bool Address::operator==( const Address &a ) const
58{
59 if ( mPostOfficeBox != a.mPostOfficeBox ) return false;
60 if ( mExtended != a.mExtended ) return false;
61 if ( mStreet != a.mStreet ) return false;
62 if ( mLocality != a.mLocality ) return false;
63 if ( mRegion != a.mRegion ) return false;
64 if ( mPostalCode != a.mPostalCode ) return false;
65 if ( mCountry != a.mCountry ) return false;
66 if ( mLabel != a.mLabel ) return false;
67
68 return true;
69}
70
71bool Address::operator!=( const Address &a ) const
72{
73 return !( a == *this );
74}
75
76bool Address::isEmpty() const
77{
78 if ( mPostOfficeBox.isEmpty() &&
79 mExtended.isEmpty() &&
80 mStreet.isEmpty() &&
81 mLocality.isEmpty() &&
82 mRegion.isEmpty() &&
83 mPostalCode.isEmpty() &&
84 mCountry.isEmpty() &&
85 mLabel.isEmpty() ) {
86 return true;
87 }
88 return false;
89}
90
91void Address::clear()
92{
93 *this = Address();
94}
95
96void Address::setId( const QString &id )
97{
98 mEmpty = false;
99
100 mId = id;
101}
102
103QString Address::id() const
104{
105 return mId;
106}
107
108void Address::setType( int type )
109{
110 mEmpty = false;
111
112 mType = type;
113}
114
115int Address::type() const
116{
117 return mType;
118}
119
120QString Address::typeLabel() const
121{
122 QString label;
123 bool first = true;
124
125 TypeList list = typeList();
126
127 TypeList::Iterator it;
128 for ( it = list.begin(); it != list.end(); ++it ) {
129 if ( ( type() & (*it) ) && ( (*it) != Pref ) ) {
130 label.append( ( first ? "" : "/" ) + typeLabel( *it ) );
131 if ( first )
132 first = false;
133 }
134 }
135
136 return label;
137}
138
139void Address::setPostOfficeBox( const QString &s )
140{
141 mEmpty = false;
142
143 mPostOfficeBox = s;
144}
145
146QString Address::postOfficeBox() const
147{
148 return mPostOfficeBox;
149}
150
151QString Address::postOfficeBoxLabel()
152{
153 return i18n("Post Office Box");
154}
155
156
157void Address::setExtended( const QString &s )
158{
159 mEmpty = false;
160
161 mExtended = s;
162}
163
164QString Address::extended() const
165{
166 return mExtended;
167}
168
169QString Address::extendedLabel()
170{
171 return i18n("Extended Address Information");
172}
173
174
175void Address::setStreet( const QString &s )
176{
177 mEmpty = false;
178
179 mStreet = s;
180}
181
182QString Address::street() const
183{
184 return mStreet;
185}
186
187QString Address::streetLabel()
188{
189 return i18n("Street");
190}
191
192
193void Address::setLocality( const QString &s )
194{
195 mEmpty = false;
196
197 mLocality = s;
198}
199
200QString Address::locality() const
201{
202 return mLocality;
203}
204
205QString Address::localityLabel()
206{
207 return i18n("Locality");
208}
209
210
211void Address::setRegion( const QString &s )
212{
213 mEmpty = false;
214
215 mRegion = s;
216}
217
218QString Address::region() const
219{
220 return mRegion;
221}
222
223QString Address::regionLabel()
224{
225 return i18n("Region");
226}
227
228
229void Address::setPostalCode( const QString &s )
230{
231 mEmpty = false;
232
233 mPostalCode = s;
234}
235
236QString Address::postalCode() const
237{
238 return mPostalCode;
239}
240
241QString Address::postalCodeLabel()
242{
243 return i18n("Postal Code");
244}
245
246
247void Address::setCountry( const QString &s )
248{
249 mEmpty = false;
250
251 mCountry = s;
252}
253
254QString Address::country() const
255{
256 return mCountry;
257}
258
259QString Address::countryLabel()
260{
261 return i18n("Country");
262}
263
264
265void Address::setLabel( const QString &s )
266{
267 mEmpty = false;
268
269 mLabel = s;
270}
271
272QString Address::label() const
273{
274 return mLabel;
275}
276
277QString Address::labelLabel()
278{
279 return i18n("Delivery Label");
280}
281
282Address::TypeList Address::typeList()
283{
284 TypeList list;
285
286 list << Dom << Intl << Postal << Parcel << Home << Work << Pref;
287
288 return list;
289}
290
291QString Address::typeLabel( int type )
292{
293 switch ( type ) {
294 case Dom:
295 return i18n("Domestic");
296 break;
297 case Intl:
298 return i18n("International");
299 break;
300 case Postal:
301 return i18n("Postal");
302 break;
303 case Parcel:
304 return i18n("Parcel");
305 break;
306 case Home:
307 return i18n("Home Address", "Home");
308 break;
309 case Work:
310 return i18n("Work Address", "Work");
311 break;
312 case Pref:
313 return i18n("Preferred Address");
314 break;
315 default:
316 return i18n("Other");
317 break;
318 }
319}
320
321void Address::dump() const
322{
323 qDebug("Address::dump() +++++++++++++++++ ");
324#if 0
325 kdDebug(5700) << " Address {" << endl;
326 kdDebug(5700) << " Id: " << id() << endl;
327 kdDebug(5700) << " Extended: " << extended() << endl;
328 kdDebug(5700) << " Street: " << street() << endl;
329 kdDebug(5700) << " Postal Code: " << postalCode() << endl;
330 kdDebug(5700) << " Locality: " << locality() << endl;
331 kdDebug(5700) << " }" << endl;
332#endif
333}
334
335
336QString Address::formattedAddress( const QString &realName
337 , const QString &orgaName ) const
338{
339 QString ciso;
340 QString addrTemplate;
341 QString ret;
342
343 // **************************************************************
344 // LR: currently we have no iso handling - we will format the address manually here
345
346 QString text;
347 if ( !street().isEmpty() )
348 text += street() + "\n";
349
350 if ( !postOfficeBox().isEmpty() )
351 text += postOfficeBox() + "\n";
352
353 text += locality() + QString(" ") + region();
354
355 if ( !postalCode().isEmpty() )
356 text += QString(", ") + postalCode();
357
358 text += "\n";
359
360 if ( !country().isEmpty() )
361 text += country() + "\n";
362
363 text += extended();
364
365
366 return text;
367 // **************************************************************
368
369 // FIXME: first check for iso-country-field and prefer that one
370 if ( !country().isEmpty() ) {
371 ciso = countryToISO( country() );
372 } else {
373 // fall back to our own country
374 ciso = KGlobal::locale()->country();
375 }
376 //qDebug("ciso %s ",ciso.latin1() );
377 KSimpleConfig entry( locate( "locale",
378 QString( "l10n/" ) + ciso + QString( "/entry.desktop" ) ) );
379 entry.setGroup( "KCM Locale" );
380
381 // decide whether this needs special business address formatting
382 if ( orgaName.isNull() ) {
383 addrTemplate = entry.readEntry( "AddressFormat" );
384 } else {
385 addrTemplate = entry.readEntry( "BusinessAddressFormat" );
386 if ( addrTemplate.isEmpty() )
387 addrTemplate = entry.readEntry( "AddressFormat" );
388 }
389
390 // in the case there's no format found at all, default to what we've always
391 // used:
392 if ( addrTemplate.isEmpty() ) {
393 qDebug("address format database incomplete****************** ");
394 kdWarning(5700) << "address format database incomplete "
395 << "(no format for locale " << ciso
396 << " found). Using default address formatting." << endl;
397 addrTemplate = "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z";
398 }
399
400 // scan
401 parseAddressTemplateSection( addrTemplate, ret, realName, orgaName );
402
403 // now add the country line if needed (formatting this time according to
404 // the rules of our own system country )
405 if ( !country().isEmpty() ) {
406 KSimpleConfig entry( locate( "locale", QString( "l10n/" )
407 + KGlobal::locale()->country() + QString( "/entry.desktop" ) ) );
408 entry.setGroup( "KCM Locale" );
409 QString cpos = entry.readEntry( "AddressCountryPosition" );
410 if ( "BELOW" == cpos || cpos.isEmpty() ) {
411 ret = ret + "\n\n" + country().upper();
412 } else if ( "below" == cpos ) {
413 ret = ret + "\n\n" + country();
414 } else if ( "ABOVE" == cpos ) {
415 ret = country().upper() + "\n\n" + ret;
416 } else if ( "above" == cpos ) {
417 ret = country() + "\n\n" + ret;
418 }
419 }
420
421 return ret;
422}
423
424bool Address::parseAddressTemplateSection( const QString &tsection,
425 QString &result, const QString &realName, const QString &orgaName ) const
426{
427 // This method first parses and substitutes any bracketed sections and
428 // after that replaces any tags with their values. If a bracketed section
429 // or a tag evaluate to zero, they are not just removed but replaced
430 // with a placeholder. This is because in the last step conditionals are
431 // resolved which depend on information about zero-evaluations.
432 result = tsection;
433 int stpos = 0;
434 bool ret = false;
435
436 // first check for brackets that have to be evaluated first
437 int fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
438 while ( -1 != fpos ) {
439 int bpos1 = fpos + KABC_FMTTAG_purgeempty.length();
440 int bpos2;
441 // expect opening bracket and find next balanced closing bracket. If
442 // next char is no opening bracket, continue parsing (no valid tag)
443 if ( '(' == result[bpos1] ) {
444 bpos2 = findBalancedBracket( result, bpos1 );
445 if ( -1 != bpos2 ) {
446 // we have balanced brackets, recursively parse:
447 QString rplstr;
448 bool purge = !parseAddressTemplateSection( result.mid( bpos1+1,
449 bpos2-bpos1-1 ), rplstr,
450 realName, orgaName );
451 if ( purge ) {
452 // purge -> remove all
453 // replace with !_P_!, so conditional tags work later
454 result.replace( fpos, bpos2 - fpos + 1, "!_P_!" );
455 // leave stpos as it is
456 } else {
457 // no purge -> replace with recursively parsed string
458 result.replace( fpos, bpos2 - fpos + 1, rplstr );
459 ret = true;
460 stpos = fpos + rplstr.length();
461 }
462 } else {
463 // unbalanced brackets: keep on parsing (should not happen
464 // and will result in bad formatting)
465 stpos = bpos1;
466 }
467 }
468 fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
469 }
470
471 // after sorting out all purge tags, we just search'n'replace the rest,
472 // keeping track of whether at least one tag evaluates to something.
473 // The following macro needs QString for R_FIELD
474 // It substitutes !_P_! for empty fields so conditional tags work later
475#define REPLTAG(R_TAG,R_FIELD) \
476 if ( result.contains(R_TAG, false) ) { \
477 QString rpl = R_FIELD.isEmpty() ? QString("!_P_!") : R_FIELD; \
478 result.replace( R_TAG, rpl ); \
479 if ( !R_FIELD.isEmpty() ) { \
480 ret = true; \
481 } \
482 }
483 REPLTAG( KABC_FMTTAG_realname, realName );
484 REPLTAG( KABC_FMTTAG_REALNAME, realName.upper() );
485 REPLTAG( KABC_FMTTAG_company, orgaName );
486 REPLTAG( KABC_FMTTAG_COMPANY, orgaName.upper() );
487 REPLTAG( KABC_FMTTAG_pobox, postOfficeBox() );
488 REPLTAG( KABC_FMTTAG_street, street() );
489 REPLTAG( KABC_FMTTAG_STREET, street().upper() );
490 REPLTAG( KABC_FMTTAG_zipcode, postalCode() );
491 REPLTAG( KABC_FMTTAG_location, locality() );
492 REPLTAG( KABC_FMTTAG_LOCATION, locality().upper() );
493 REPLTAG( KABC_FMTTAG_region, region() );
494 REPLTAG( KABC_FMTTAG_REGION, region().upper() );
495 result.replace( KABC_FMTTAG_newline, "\n" );
496#undef REPLTAG
497
498 // conditional comma
499 fpos = result.find( KABC_FMTTAG_condcomma, 0 );
500 while ( -1 != fpos ) {
501 QString str1 = result.mid( fpos - 5, 5 );
502 QString str2 = result.mid( fpos + 2, 5 );
503 if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
504 result.replace( fpos, 2, ", " );
505 } else {
506 result.remove( fpos, 2 );
507 }
508 fpos = result.find( KABC_FMTTAG_condcomma, fpos );
509 }
510 // conditional whitespace
511 fpos = result.find( KABC_FMTTAG_condwhite, 0 );
512 while ( -1 != fpos ) {
513 QString str1 = result.mid( fpos - 5, 5 );
514 QString str2 = result.mid( fpos + 2, 5 );
515 if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
516 result.replace( fpos, 2, " " );
517 } else {
518 result.remove( fpos, 2 );
519 }
520 fpos = result.find( KABC_FMTTAG_condwhite, fpos );
521 }
522
523 // remove purged:
524//US my QT version does not support remove. So lets do it the old fashioned way.
525//US result.remove( "!_P_!" );
526 int n = result.find("!_P_!");
527 if (n >= 0)
528 result.remove( n, 5 );
529
530 return ret;
531}
532
533int Address::findBalancedBracket( const QString &tsection, int pos ) const
534{
535 int balancecounter = 0;
536 for( unsigned int i = pos + 1; i < tsection.length(); i++ ) {
537 if ( ')' == tsection.at(i) && 0 == balancecounter ) {
538 // found end of brackets
539 return i;
540 } else
541 if ( '(' == tsection.at(i) ) {
542 // nested brackets
543 balancecounter++;
544 }
545 }
546 return -1;
547}
548
549QString Address::countryToISO( const QString &cname )
550{
551 // we search a map file for translations from country names to
552 // iso codes, storing caching things in a QMap for faster future
553 // access.
554/*US
555
556 QString isoCode = mISOMap[ cname ];
557 if ( !isoCode.isEmpty() )
558 return isoCode;
559
560 QString mapfile = KGlobal::dirs()->findResource( "data",
561 QString::fromLatin1( "kabc/countrytransl.map" ) );
562
563 QFile file( mapfile );
564 if ( file.open( IO_ReadOnly ) ) {
565 QTextStream s( &file );
566 QString strbuf = s.readLine();
567 while( !strbuf.isNull() ) {
568 if ( strbuf.startsWith( cname ) ) {
569 int index = strbuf.findRev('\t');
570 strbuf = strbuf.mid(index+1, 2);
571 file.close();
572 mISOMap[ cname ] = strbuf;
573 return strbuf;
574 }
575 strbuf = s.readLine();
576 }
577 file.close();
578 }
579*/
580 // fall back to system country
581 mISOMap[ cname ] = KGlobal::locale()->country();
582 return KGlobal::locale()->country();
583}
584
585QString Address::ISOtoCountry( const QString &ISOname )
586{
587/*US
588 // get country name from ISO country code (e.g. "no" -> i18n("Norway"))
589 QString mapfile = KGlobal::dirs()->findResource( "data",
590 QString::fromLatin1( "kabc/countrytransl.map" ) );
591
592kdWarning() << "MAPFILE : " << mapfile << endl;
593 QFile file( mapfile );
594 if ( file.open( IO_ReadOnly ) ) {
595 QTextStream s( &file );
596 QString searchStr = "\t" + ISOname.simplifyWhiteSpace().lower();
597kdWarning() << "Suche : " << searchStr << endl;
598 QString strbuf = s.readLine();
599 int pos;
600 while( !strbuf.isNull() ) {
601 if ( (pos=strbuf.find( searchStr )) != -1 ) {
602 file.close();
603 return i18n(strbuf.left(pos).utf8());
604 }
605 strbuf = s.readLine();
606 }
607 file.close();
608 }
609*/
610 return ISOname;
611}
612
613QDataStream &KABC::operator<<( QDataStream &s, const Address &addr )
614{
615 return s << addr.mId << addr.mType << addr.mPostOfficeBox <<
616 addr.mExtended << addr.mStreet << addr.mLocality <<
617 addr.mRegion << addr.mPostalCode << addr.mCountry <<
618 addr.mLabel;
619}
620
621QDataStream &KABC::operator>>( QDataStream &s, Address &addr )
622{
623 s >> addr.mId >> addr.mType >> addr.mPostOfficeBox >> addr.mExtended >>
624 addr.mStreet >> addr.mLocality >> addr.mRegion >>
625 addr.mPostalCode >> addr.mCountry >> addr.mLabel;
626
627 addr.mEmpty = false;
628
629 return s;
630}