lib Library API Documentation

koDocumentInfoDlg.cc

00001 /* This file is part of the KDE project
00002    Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
00003 
00004    $Id: koDocumentInfoDlg.cc 421021 2005-06-01 23:33:00Z fedemar $
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <koDocumentInfoDlg.h>
00023 #include <koDocumentInfo.h>
00024 #include <koGlobal.h>
00025 #include <koStore.h>
00026 
00027 #include <sys/stat.h>
00028 #include <unistd.h>
00029 #include <assert.h>
00030 
00031 #include <qlabel.h>
00032 #include <qlineedit.h>
00033 #include <qmultilineedit.h>
00034 #include <qbuffer.h>
00035 #include <qdom.h>
00036 #include <qdir.h>
00037 #include <qpushbutton.h>
00038 
00039 #include <kabc/addressee.h>
00040 #include <kabc/stdaddressbook.h>
00041 #include <kdeversion.h>
00042 #include <klocale.h>
00043 #include <kmessagebox.h>
00044 #include <ktar.h>
00045 #include <kdebug.h>
00046 #include <ktempfile.h>
00047 #include <kmimetype.h>
00048 #include <qlayout.h>
00049 #include <qgrid.h>
00050 #include <kfilterdev.h>
00051 
00052 class KoDocumentInfoDlg::KoDocumentInfoDlgPrivate
00053 {
00054 public:
00055   KoDocumentInfoDlgPrivate()
00056   {
00057   }
00058   ~KoDocumentInfoDlgPrivate()
00059   {
00060   }
00061 
00062   KoDocumentInfo *m_info;
00063 
00064   QLineEdit *m_leFullName;
00065   QLineEdit *m_leInitial;
00066   QLineEdit *m_leAuthorTitle;
00067   QLineEdit *m_leCompany;
00068   QLineEdit *m_leEmail;
00069   QLineEdit *m_leTelephoneWork;
00070   QLineEdit *m_leTelephoneHome;
00071   QLineEdit *m_leFax;
00072   QLineEdit *m_leCountry;
00073   QLineEdit *m_lePostalCode;
00074   QLineEdit *m_leCity;
00075   QLineEdit *m_leStreet;
00076   QPushButton *m_pbLoadKABC;
00077 
00078   QLineEdit *m_leDocTitle;
00079   QMultiLineEdit *m_meAbstract;
00080     QLineEdit *m_leDocSubject;
00081     QLineEdit *m_leDocKeywords;
00082     QLineEdit *m_leAuthorPosition;
00083 
00084 
00085   bool m_bDeleteDialog;
00086   KDialogBase *m_dialog;
00087 };
00088 
00089 KoDocumentInfoDlg::KoDocumentInfoDlg( KoDocumentInfo *docInfo, QWidget *parent, const char *name,
00090                                       KDialogBase *dialog )
00091 : QObject( parent, "docinfodlg" )
00092 {
00093   d = new KoDocumentInfoDlgPrivate;
00094   d->m_info = docInfo;
00095 
00096   d->m_dialog = dialog;
00097   d->m_bDeleteDialog = false;
00098 
00099   if ( !dialog )
00100   {
00101     d->m_dialog = new KDialogBase( KDialogBase::Tabbed,
00102                                    i18n( "Document Information" ),
00103                                    KDialogBase::Ok | KDialogBase::Cancel,
00104                                    KDialogBase::Ok, parent, name, true, true );
00105     d->m_bDeleteDialog = true;
00106   }
00107 
00108   QStringList pages = docInfo->pages();
00109   QStringList::ConstIterator it = pages.begin();
00110   QStringList::ConstIterator end = pages.end();
00111   for (; it != end; ++it )
00112   {
00113     KoDocumentInfoPage *pg = docInfo->page( *it );
00114     if ( pg->inherits( "KoDocumentInfoAuthor" ) )
00115       addAuthorPage( static_cast<KoDocumentInfoAuthor *>( pg ) );
00116     else if ( pg->inherits( "KoDocumentInfoAbout" ) )
00117       addAboutPage( static_cast<KoDocumentInfoAbout *>( pg ) );
00118   }
00119 }
00120 
00121 KoDocumentInfoDlg::~KoDocumentInfoDlg()
00122 {
00123   if ( d->m_bDeleteDialog )
00124     delete d->m_dialog;
00125 
00126   delete d;
00127 }
00128 
00129 int KoDocumentInfoDlg::exec()
00130 {
00131   return d->m_dialog->exec();
00132 }
00133 
00134 KDialogBase *KoDocumentInfoDlg::dialog() const
00135 {
00136   return d->m_dialog;
00137 }
00138 
00139 void KoDocumentInfoDlg::loadFromKABC()
00140 {
00141   KABC::StdAddressBook *ab = static_cast<KABC::StdAddressBook*>
00142                              ( KABC::StdAddressBook::self() );
00143 
00144   if ( !ab )
00145     return;
00146 
00147   KABC::Addressee addr = ab->whoAmI();
00148   if ( addr.isEmpty() )
00149   {
00150     KMessageBox::sorry( 0L, i18n( "No personal contact data set, please use the option \
00151                                   \"Set as Personal Contact Data\" from the \"Edit\" menu in KAddressbook to set one." ) );
00152     return;
00153   }
00154 
00155   d->m_leFullName->setText( addr.formattedName() );
00156   d->m_leInitial->setText( addr.givenName()[ 0 ] + ". " +
00157                            addr.familyName()[ 0 ] + "." );
00158   d->m_leAuthorTitle->setText( addr.title() );
00159   d->m_leCompany->setText( addr.organization() );
00160   d->m_leEmail->setText( addr.preferredEmail() );
00161 
00162   KABC::PhoneNumber phone = addr.phoneNumber( KABC::PhoneNumber::Home );
00163   d->m_leTelephoneHome->setText( phone.number() );
00164   phone = addr.phoneNumber( KABC::PhoneNumber::Work );
00165   d->m_leTelephoneWork->setText( phone.number() );
00166 
00167   phone = addr.phoneNumber( KABC::PhoneNumber::Fax );
00168   d->m_leFax->setText( phone.number() );
00169 
00170   KABC::Address a = addr.address( KABC::Address::Home );
00171   d->m_leCountry->setText( a.country() );
00172   d->m_lePostalCode->setText( a.postalCode() );
00173   d->m_leCity->setText( a.locality() );
00174   d->m_leStreet->setText( a.street() );
00175 
00176   emit changed();
00177 }
00178 
00179 void KoDocumentInfoDlg::addAuthorPage( KoDocumentInfoAuthor *authorInfo )
00180 {
00181   QFrame *page = d->m_dialog->addPage( i18n( "Author" ) );
00182   QGridLayout *layout = new QGridLayout( page, 11, 2, KDialog::marginHint(),
00183                                          KDialog::spacingHint() );
00184 
00185   layout->addWidget( new QLabel( i18n( "Name:" ), page ), 0, 0 );
00186   d->m_leFullName = new QLineEdit( authorInfo->fullName(), page );
00187   layout->addWidget( d->m_leFullName, 0, 1 );
00188 
00189 
00190   layout->addWidget( new QLabel( i18n( "Initials:" ), page ), 1, 0 );
00191   d->m_leInitial = new QLineEdit( authorInfo->initial(), page );
00192   layout->addWidget( d->m_leInitial, 1, 1 );
00193 
00194   layout->addWidget( new QLabel( i18n( "Title:" ), page ), 2, 0 );
00195   d->m_leAuthorTitle = new QLineEdit( authorInfo->title(), page );
00196   layout->addWidget( d->m_leAuthorTitle, 2, 1 );
00197 
00198   layout->addWidget( new QLabel( i18n( "Position:" ), page ), 3, 0 );
00199   d->m_leAuthorPosition = new QLineEdit( authorInfo->position(), page );
00200   layout->addWidget( d->m_leAuthorPosition, 3, 1 );
00201 
00202 
00203   layout->addWidget( new QLabel( i18n( "Company:" ), page ), 4, 0 );
00204   d->m_leCompany = new QLineEdit( authorInfo->company(), page );
00205   layout->addWidget( d->m_leCompany, 4, 1 );
00206 
00207 
00208   layout->addWidget( new QLabel( i18n( "Email:" ), page ), 5, 0 );
00209   d->m_leEmail = new QLineEdit( authorInfo->email(), page );
00210   layout->addWidget( d->m_leEmail, 5, 1 );
00211 
00212 
00213   layout->addWidget( new QLabel( i18n( "Telephone (Home):" ), page ), 6, 0 );
00214   d->m_leTelephoneHome = new QLineEdit( authorInfo->telephoneHome(), page );
00215   layout->addWidget( d->m_leTelephoneHome, 6, 1 );
00216 
00217   layout->addWidget( new QLabel( i18n( "Telephone (Work):" ), page ), 7, 0 );
00218   d->m_leTelephoneWork = new QLineEdit( authorInfo->telephoneWork(), page );
00219   layout->addWidget( d->m_leTelephoneWork, 7, 1 );
00220 
00221   layout->addWidget( new QLabel( i18n( "Fax:" ), page ), 8, 0 );
00222   d->m_leFax = new QLineEdit( authorInfo->fax(), page );
00223   layout->addWidget( d->m_leFax, 8, 1 );
00224 
00225   layout->addWidget( new QLabel( i18n( "Street:" ), page ), 9, 0 );
00226   d->m_leStreet = new QLineEdit( authorInfo->street(), page );
00227   layout->addWidget( d->m_leStreet, 9, 1 );
00228 
00229   layout->addWidget( new QLabel( i18n( "Postal code:" ), page ), 10, 0 );
00230   d->m_lePostalCode = new QLineEdit( authorInfo->postalCode(), page );
00231   layout->addWidget( d->m_lePostalCode, 10, 1 );
00232 
00233   layout->addWidget( new QLabel( i18n( "City:" ), page ), 11, 0 );
00234   d->m_leCity = new QLineEdit( authorInfo->city(), page );
00235   layout->addWidget( d->m_leCity, 11, 1 );
00236 
00237   layout->addWidget( new QLabel( i18n( "Country:" ), page ), 12, 0 );
00238   d->m_leCountry = new QLineEdit( authorInfo->country(), page );
00239   layout->addWidget( d->m_leCountry, 12, 1 );
00240 
00241   d->m_pbLoadKABC = new QPushButton( i18n( "Load From Address Book" ), page );
00242   layout->addMultiCellWidget( d->m_pbLoadKABC, 13, 13, 0, 1 );
00243 
00244   connect( d->m_leFullName, SIGNAL( textChanged( const QString & ) ),
00245            this, SIGNAL( changed() ) );
00246   connect( d->m_leInitial, SIGNAL( textChanged( const QString & ) ),
00247            this, SIGNAL( changed() ) );
00248 
00249   connect( d->m_leAuthorTitle, SIGNAL( textChanged( const QString & ) ),
00250            this, SIGNAL( changed() ) );
00251   connect( d->m_leCompany, SIGNAL( textChanged( const QString & ) ),
00252            this, SIGNAL( changed() ) );
00253   connect( d->m_leEmail, SIGNAL( textChanged( const QString & ) ),
00254            this, SIGNAL( changed() ) );
00255   connect( d->m_leTelephoneWork, SIGNAL( textChanged( const QString & ) ),
00256            this, SIGNAL( changed() ) );
00257   connect( d->m_leTelephoneHome, SIGNAL( textChanged( const QString & ) ),
00258            this, SIGNAL( changed() ) );
00259   connect( d->m_leFax, SIGNAL( textChanged( const QString & ) ),
00260            this, SIGNAL( changed() ) );
00261   connect( d->m_leCountry, SIGNAL( textChanged( const QString & ) ),
00262            this, SIGNAL( changed() ) );
00263   connect( d->m_lePostalCode, SIGNAL( textChanged( const QString & ) ),
00264            this, SIGNAL( changed() ) );
00265   connect( d->m_leCity, SIGNAL( textChanged( const QString & ) ),
00266            this, SIGNAL( changed() ) );
00267   connect( d->m_leStreet, SIGNAL( textChanged( const QString & ) ),
00268            this, SIGNAL( changed() ) );
00269   connect( d->m_leAuthorPosition, SIGNAL( textChanged( const QString & ) ),
00270            this, SIGNAL( changed() ) );
00271   connect( d->m_pbLoadKABC, SIGNAL( clicked() ),
00272            this, SLOT( loadFromKABC() ) );
00273 }
00274 
00275 void KoDocumentInfoDlg::addAboutPage( KoDocumentInfoAbout *aboutInfo )
00276 {
00277   QFrame *page = d->m_dialog->addPage( i18n("about the document", "Document") );
00278   QGridLayout *grid = new QGridLayout( page, 6, 2, KDialog::marginHint(), KDialog::spacingHint() );
00279 
00280   grid->addWidget( new QLabel( i18n( "Title:" ), page ), 0, 0);
00281   d->m_leDocTitle = new QLineEdit( aboutInfo->title(), page );
00282   grid->addWidget(d->m_leDocTitle, 0, 1);
00283 
00284   grid->addWidget( new QLabel( i18n( "Subject:" ), page ), 1, 0);
00285   d->m_leDocSubject = new QLineEdit( aboutInfo->subject(), page );
00286   grid->addWidget(d->m_leDocSubject, 1, 1);
00287 
00288   grid->addWidget( new QLabel( i18n( "Keywords:" ), page ), 2, 0);
00289   d->m_leDocKeywords = new QLineEdit( aboutInfo->keywords(), page );
00290   grid->addWidget(d->m_leDocKeywords, 2, 1);
00291 
00292 
00293   grid->addWidget(new QLabel( i18n( "Abstract:" ), page ), 3, 0, Qt::AlignTop );
00294 
00295   d->m_meAbstract = new QMultiLineEdit( page );
00296   d->m_meAbstract->setText( aboutInfo->abstract() );
00297   grid->addMultiCellWidget(d->m_meAbstract, 3, 5, 1, 1);
00298 
00299   connect( d->m_leDocTitle, SIGNAL( textChanged( const QString & ) ),
00300            this, SIGNAL( changed() ) );
00301   connect( d->m_meAbstract, SIGNAL( textChanged() ),
00302            this, SIGNAL( changed() ) );
00303   connect( d->m_leDocSubject, SIGNAL( textChanged( const QString & ) ),
00304            this, SIGNAL( changed() ) );
00305   connect( d->m_leDocKeywords, SIGNAL( textChanged( const QString & ) ),
00306            this, SIGNAL( changed() ) );
00307 }
00308 
00309 void KoDocumentInfoDlg::save()
00310 {
00311   QStringList pages = d->m_info->pages();
00312   QStringList::ConstIterator it = pages.begin();
00313   QStringList::ConstIterator end = pages.end();
00314   bool saveInfo=false;
00315   for (; it != end; ++it )
00316   {
00317     KoDocumentInfoPage *pg = d->m_info->page( *it );
00318     if ( pg->inherits( "KoDocumentInfoAuthor" ) )
00319     {
00320         saveInfo=true;
00321         save( static_cast<KoDocumentInfoAuthor *>( pg ) );
00322     }
00323     else if ( pg->inherits( "KoDocumentInfoAbout" ) )
00324     {
00325         saveInfo=true;
00326         save( static_cast<KoDocumentInfoAbout *>( pg ) );
00327     }
00328   }
00329   if(saveInfo)
00330       d->m_info->documentInfochanged();
00331 }
00332 
00333 void KoDocumentInfoDlg::save( KoDocumentInfoAuthor *authorInfo )
00334 {
00335   authorInfo->setFullName( d->m_leFullName->text() );
00336   authorInfo->setInitial( d->m_leInitial->text() );
00337   authorInfo->setTitle( d->m_leAuthorTitle->text() );
00338   authorInfo->setCompany( d->m_leCompany->text() );
00339   authorInfo->setEmail( d->m_leEmail->text() );
00340   authorInfo->setTelephoneWork( d->m_leTelephoneWork->text() );
00341   authorInfo->setTelephoneHome( d->m_leTelephoneHome->text() );
00342   authorInfo->setFax( d->m_leFax->text() );
00343   authorInfo->setCountry( d->m_leCountry->text() );
00344   authorInfo->setPostalCode( d->m_lePostalCode->text() );
00345   authorInfo->setCity( d->m_leCity->text() );
00346   authorInfo->setStreet( d->m_leStreet->text() );
00347   authorInfo->setPosition( d->m_leAuthorPosition->text() );
00348 
00349   KConfig* config = KoGlobal::kofficeConfig();
00350   KConfigGroupSaver cgs( config, "Author" );
00351   config->writeEntry("telephone", d->m_leTelephoneHome->text());
00352   config->writeEntry("telephone-work", d->m_leTelephoneWork->text());
00353   config->writeEntry("fax", d->m_leFax->text());
00354   config->writeEntry("country",d->m_leCountry->text());
00355   config->writeEntry("postal-code",d->m_lePostalCode->text());
00356   config->writeEntry("city",  d->m_leCity->text());
00357   config->writeEntry("street", d->m_leStreet->text());
00358   config->sync();
00359 }
00360 
00361 void KoDocumentInfoDlg::save( KoDocumentInfoAbout *aboutInfo )
00362 {
00363   aboutInfo->setTitle( d->m_leDocTitle->text() );
00364   aboutInfo->setSubject( d->m_leDocSubject->text() );
00365   aboutInfo->setKeywords( d->m_leDocKeywords->text() );
00366   aboutInfo->setAbstract( d->m_meAbstract->text() );
00367 }
00368 
00369 class KoDocumentInfoPropsPage::KoDocumentInfoPropsPagePrivate
00370 {
00371 public:
00372   KoDocumentInfo *m_info;
00373   KoDocumentInfoDlg *m_dlg;
00374   KURL m_url;
00375   KTarGz *m_src;
00376   KTarGz *m_dst;
00377 
00378   const KTarFile *m_docInfoFile;
00379 };
00380 
00381 KoDocumentInfoPropsPage::KoDocumentInfoPropsPage( KPropertiesDialog *props,
00382                                                   const char *,
00383                                                   const QStringList & )
00384 : KPropsDlgPlugin( props )
00385 {
00386   d = new KoDocumentInfoPropsPagePrivate;
00387   d->m_info = new KoDocumentInfo( this, "docinfo" );
00388   d->m_url = props->item()->url();
00389   d->m_dlg = 0;
00390 
00391   if ( !d->m_url.isLocalFile() )
00392     return;
00393 
00394   d->m_dst = 0;
00395 
00396 #ifdef __GNUC__
00397 #warning TODO port this to KoStore !!!
00398 #endif
00399   d->m_src = new KTarGz( d->m_url.path(), "application/x-gzip" );
00400 
00401   if ( !d->m_src->open( IO_ReadOnly ) )
00402     return;
00403 
00404   const KTarDirectory *root = d->m_src->directory();
00405   if ( !root )
00406     return;
00407 
00408   const KTarEntry *entry = root->entry( "documentinfo.xml" );
00409 
00410   if ( entry && entry->isFile() )
00411   {
00412     d->m_docInfoFile = static_cast<const KTarFile *>( entry );
00413 
00414     QBuffer buffer( d->m_docInfoFile->data() );
00415     buffer.open( IO_ReadOnly );
00416 
00417     QDomDocument doc;
00418     doc.setContent( &buffer );
00419 
00420     d->m_info->load( doc );
00421   }
00422 
00423   d->m_dlg = new KoDocumentInfoDlg( d->m_info, 0, 0, props );
00424   connect( d->m_dlg, SIGNAL( changed() ),
00425            this, SIGNAL( changed() ) );
00426 }
00427 
00428 KoDocumentInfoPropsPage::~KoDocumentInfoPropsPage()
00429 {
00430   delete d->m_info;
00431   delete d->m_src;
00432   delete d->m_dst;
00433   delete d->m_dlg;
00434   delete d;
00435 }
00436 
00437 void KoDocumentInfoPropsPage::applyChanges()
00438 {
00439   const KTarDirectory *root = d->m_src->directory();
00440   if ( !root )
00441     return;
00442 
00443   struct stat statBuff;
00444 
00445   if ( stat( QFile::encodeName( d->m_url.path() ), &statBuff ) != 0 )
00446     return;
00447 
00448   KTempFile tempFile( d->m_url.path(), QString::null, statBuff.st_mode );
00449 
00450   tempFile.setAutoDelete( true );
00451 
00452   if ( tempFile.status() != 0 )
00453     return;
00454 
00455   if ( !tempFile.close() )
00456     return;
00457 
00458   d->m_dst = new KTarGz( tempFile.name(), "application/x-gzip" );
00459 
00460   if ( !d->m_dst->open( IO_WriteOnly ) )
00461     return;
00462 
00463   KMimeType::Ptr mimeType = KMimeType::findByURL( d->m_url, 0, true );
00464   if ( mimeType && dynamic_cast<KFilterDev *>( d->m_dst->device() ) != 0 )
00465   {
00466       QCString appIdentification( "KOffice " ); // We are limited in the number of chars.
00467       appIdentification += mimeType->name().latin1();
00468       appIdentification += '\004'; // Two magic bytes to make the identification
00469       appIdentification += '\006'; // more reliable (DF)
00470       d->m_dst->setOrigFileName( appIdentification );
00471   }
00472 
00473   bool docInfoSaved = false;
00474 
00475   QStringList entries = root->entries();
00476   QStringList::ConstIterator it = entries.begin();
00477   QStringList::ConstIterator end = entries.end();
00478   for (; it != end; ++it )
00479   {
00480     const KTarEntry *entry = root->entry( *it );
00481 
00482     assert( entry );
00483 
00484     if ( entry->name() == "documentinfo.xml" ||
00485          ( !docInfoSaved && !entries.contains( "documentinfo.xml" ) ) )
00486     {
00487       d->m_dlg->save();
00488 
00489       QBuffer buffer;
00490       buffer.open( IO_WriteOnly );
00491       QTextStream str( &buffer );
00492       str << d->m_info->save();
00493       buffer.close();
00494 
00495       kdDebug( 30003 ) << "writing documentinfo.xml" << endl;
00496       d->m_dst->writeFile( "documentinfo.xml", entry->user(), entry->group(), buffer.buffer().size(),
00497                            buffer.buffer().data() );
00498 
00499       docInfoSaved = true;
00500     }
00501     else
00502       copy( QString::null, entry );
00503   }
00504 
00505   d->m_dst->close();
00506 
00507   QDir dir;
00508   dir.rename( tempFile.name(), d->m_url.path() );
00509 
00510   delete d->m_dst;
00511   d->m_dst = 0;
00512 }
00513 
00514 void KoDocumentInfoPropsPage::copy( const QString &path, const KArchiveEntry *entry )
00515 {
00516   kdDebug( 30003 ) << "copy " << entry->name() << endl;
00517   if ( entry->isFile() )
00518   {
00519     const KTarFile *file = static_cast<const KTarFile *>( entry );
00520     kdDebug( 30003 ) << "file :" << entry->name() << endl;
00521     kdDebug( 30003 ) << "full path is: " << path << entry->name() << endl;
00522     d->m_dst->writeFile( path + entry->name(), entry->user(), entry->group(),
00523                          file->size(),
00524                          file->data().data() );
00525   }
00526   else
00527   {
00528     const KTarDirectory *dir = static_cast<const KTarDirectory *>( entry );
00529     kdDebug( 30003 ) << "dir : " << entry->name() << endl;
00530     kdDebug( 30003 ) << "full path is: " << path << entry->name() << endl;
00531 
00532     QString p = path + entry->name();
00533     if ( p != "/" )
00534     {
00535       d->m_dst->writeDir( p, entry->user(), entry->group() );
00536       p.append( "/" );
00537     }
00538 
00539     QStringList entries = dir->entries();
00540     QStringList::ConstIterator it = entries.begin();
00541     QStringList::ConstIterator end = entries.end();
00542     for (; it != end; ++it )
00543       copy( p, dir->entry( *it ) );
00544   }
00545 }
00546 
00547 /* vim: sw=2 et
00548  */
00549 
00550 #include <koDocumentInfoDlg.moc>
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:40:00 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003