00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qtopia/private/categories.h>
00021 #include <qtopia/stringutil.h>
00022 #include <qfile.h>
00023 #include <qcstring.h>
00024 #include <qtextstream.h>
00025
00026 using namespace Qtopia;
00027
00028
00029
00030
00031
00032
00033
00034 #ifdef PALMTOPCENTER
00035 UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter );
00036 #else
00037 UidGen CategoryGroup::sUidGen( UidGen::Qtopia );
00038 #endif
00039
00058 int CategoryGroup::add( const QString &label )
00059 {
00060 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
00061 return 0;
00062
00063 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
00064 if ( findIt != mLabelIdMap.end() )
00065 return 0;
00066 int newUid = uidGen().generate();
00067 insert( newUid, label );
00068 return newUid;
00069 }
00070
00071 void CategoryGroup::insert( int uid, const QString &label )
00072 {
00073 uidGen().store( uid );
00074 mIdLabelMap[uid] = label;
00075 mLabelIdMap[label] = uid;
00076 }
00077
00080 bool CategoryGroup::add( int uid, const QString &label )
00081 {
00082 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
00083 return FALSE;
00084
00085 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
00086 if ( labelIt != mLabelIdMap.end() )
00087 return FALSE;
00088 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
00089 if ( idIt != mIdLabelMap.end() )
00090 return FALSE;
00091 insert( uid, label );
00092 return TRUE;
00093 }
00094
00098 bool CategoryGroup::remove( const QString &label )
00099 {
00100 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
00101 if ( findIt == mLabelIdMap.end() )
00102 return FALSE;
00103
00104 mIdLabelMap.remove( *findIt );
00105 mLabelIdMap.remove( findIt );
00106
00107 return TRUE;
00108 }
00109
00113 bool CategoryGroup::remove( int uid )
00114 {
00115 QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid );
00116 if ( idIt == mIdLabelMap.end() )
00117 return FALSE;
00118
00119 mLabelIdMap.remove( *idIt );
00120 mIdLabelMap.remove( idIt );
00121
00122 return TRUE;
00123 }
00124
00127 bool CategoryGroup::rename( int uid, const QString &newLabel )
00128 {
00129 if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") )
00130 return FALSE;
00131
00132 QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid );
00133 if ( idIt == mIdLabelMap.end() )
00134 return FALSE;
00135
00136 mLabelIdMap.remove( *idIt );
00137 mLabelIdMap[newLabel] = uid;
00138 *idIt = newLabel;
00139
00140 return TRUE;
00141 }
00142
00145 bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel )
00146 {
00147 return rename( id(oldLabel), newLabel );
00148 }
00149
00151 bool CategoryGroup::contains(int uid) const
00152 {
00153 return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() );
00154 }
00155
00157 bool CategoryGroup::contains(const QString &label) const
00158 {
00159 return ( mLabelIdMap.find( label ) != mLabelIdMap.end() );
00160 }
00161
00165 const QString &CategoryGroup::label(int uid) const
00166 {
00167 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
00168 if ( idIt == mIdLabelMap.end() )
00169 return QString::null;
00170 return *idIt;
00171 }
00172
00174 int CategoryGroup::id(const QString &label) const
00175 {
00176 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
00177 if ( labelIt == mLabelIdMap.end() )
00178 return 0;
00179 return *labelIt;
00180 }
00181
00183 QStringList CategoryGroup::labels() const
00184 {
00185 QStringList labels;
00186 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
00187 it != mIdLabelMap.end(); ++it )
00188 labels += *it;
00189
00190
00191 return labels;
00192 }
00193
00195 QStringList CategoryGroup::labels(const QArray<int> &catids ) const
00196 {
00197 QStringList labels;
00198 if ( catids.count() == 0 )
00199 return labels;
00200 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
00201 it != mIdLabelMap.end(); ++it )
00202 if ( catids.find( it.key() ) != -1 )
00203 labels += *it;
00204 return labels;
00205 }
00206
00207
00208
00209
00210
00211
00212
00256 int Categories::addCategory( const QString &appname,
00257 const QString &catname,
00258 int uid )
00259 {
00260 if ( mGlobalCats.contains(catname) )
00261 return 0;
00262
00263 QMap< QString, CategoryGroup >::Iterator
00264 appIt = mAppCats.find( appname );
00265
00266 if ( appIt == mAppCats.end() ) {
00267 CategoryGroup newgroup;
00268 newgroup.add( uid, catname );
00269 mAppCats.insert( appname, newgroup );
00270 emit categoryAdded( *this, appname, uid );
00271 return uid;
00272 }
00273
00274 CategoryGroup &cats = *appIt;
00275 cats.add( uid, catname );
00276 emit categoryAdded( *this, appname, uid );
00277 return uid;
00278 }
00279
00285 int Categories::addCategory( const QString &appname,
00286 const QString &catname )
00287 {
00288 if ( mGlobalCats.contains(catname) )
00289 return 0;
00290
00291 QMap< QString, CategoryGroup >::Iterator
00292 appIt = mAppCats.find( appname );
00293
00294 if ( appIt == mAppCats.end() ) {
00295 CategoryGroup newgroup;
00296 int uid = newgroup.add( catname );
00297 mAppCats.insert( appname, newgroup );
00298 emit categoryAdded( *this, appname, uid );
00299 return uid;
00300 }
00301
00302 CategoryGroup &cats = *appIt;
00303 int uid = cats.add( catname );
00304 if ( !uid )
00305 return 0;
00306 emit categoryAdded( *this, appname, uid );
00307 return uid;
00308 }
00309
00313 int Categories::addGlobalCategory( const QString &catname, int uid )
00314 {
00315 mGlobalCats.add( uid, catname );
00316 emit categoryAdded( *this, QString::null, uid );
00317 return uid;
00318 }
00319
00326 int Categories::addGlobalCategory( const QString &catname )
00327 {
00328 int uid = mGlobalCats.add( catname );
00329 if ( !uid )
00330 return 0;
00331 emit categoryAdded( *this, QString::null, uid );
00332 return uid;
00333 }
00334
00341 bool Categories::removeCategory( const QString &appname,
00342 const QString &catname,
00343 bool checkGlobal )
00344 {
00345 QMap< QString, CategoryGroup >::Iterator
00346 appIt = mAppCats.find( appname );
00347 if ( appIt != mAppCats.end() ) {
00348 CategoryGroup &cats = *appIt;
00349 int uid = cats.id( catname );
00350 if ( cats.remove( uid ) ) {
00351 emit categoryRemoved( *this, appname, uid );
00352 return TRUE;
00353 }
00354 }
00355 if ( !checkGlobal )
00356 return FALSE;
00357 return removeGlobalCategory( catname );
00358 }
00359
00360
00365 bool Categories::removeCategory( const QString &appname, int uid )
00366 {
00367 QMap< QString, CategoryGroup >::Iterator
00368 appIt = mAppCats.find( appname );
00369 if ( appIt != mAppCats.end() ) {
00370 CategoryGroup &cats = *appIt;
00371 if ( cats.remove( uid ) ) {
00372 emit categoryRemoved( *this, appname, uid );
00373 return TRUE;
00374 }
00375 }
00376 return FALSE;
00377 }
00378
00383 bool Categories::removeGlobalCategory( const QString &catname )
00384 {
00385 int uid = mGlobalCats.id( catname );
00386 if ( mGlobalCats.remove( uid ) ) {
00387 emit categoryRemoved( *this, QString::null, uid );
00388 return TRUE;
00389 }
00390 return FALSE;
00391 }
00392
00397 bool Categories::removeGlobalCategory( int uid )
00398 {
00399 if ( mGlobalCats.remove( uid ) ) {
00400 emit categoryRemoved( *this, QString::null, uid );
00401 return TRUE;
00402 }
00403 return FALSE;
00404 }
00405
00411 QStringList Categories::labels( const QString &app,
00412 bool includeGlobal,
00413 ExtraLabels extra ) const
00414 {
00415 QMap< QString, CategoryGroup >::ConstIterator
00416 appIt = mAppCats.find( app );
00417 QStringList cats;
00418
00419 if ( appIt != mAppCats.end() )
00420 cats += (*appIt).labels();
00421
00422 if ( includeGlobal )
00423 cats += mGlobalCats.labels();
00424
00425 cats.sort();
00426 switch ( extra ) {
00427 case NoExtra: break;
00428 case AllUnfiled:
00429 cats.append( tr("All") );
00430 cats.append( tr("Unfiled") );
00431 break;
00432 case AllLabel:
00433 cats.append( tr("All") );
00434 break;
00435 case UnfiledLabel:
00436 cats.append( tr("Unfiled") );
00437 break;
00438 }
00439
00440 return cats;
00441 }
00442
00446 QString Categories::label( const QString &app, int id ) const
00447 {
00448 if ( mGlobalCats.contains( id ) )
00449 return mGlobalCats.label( id );
00450 QMap< QString, CategoryGroup >::ConstIterator
00451 appIt = mAppCats.find( app );
00452 if ( appIt == mAppCats.end() )
00453 return QString::null;
00454 return (*appIt).label( id );
00455 }
00456
00468 QString Categories::displaySingle( const QString &app,
00469 const QArray<int> &catids,
00470 DisplaySingle display ) const
00471 {
00472 QStringList strs = labels( app, catids );
00473 if ( !strs.count() )
00474 return tr("Unfiled");
00475 strs.sort();
00476 QString r;
00477 if ( strs.count() > 1 ) {
00478 switch ( display ) {
00479 case ShowFirst:
00480 r = strs.first();
00481 break;
00482 case ShowMulti:
00483 r = strs.first() + tr(" (multi.)");
00484 break;
00485 case ShowAll:
00486 r = strs.join(" ");
00487 break;
00488 }
00489 }
00490 else r = strs.first();
00491 return r;
00492 }
00493
00499 QArray<int> Categories::ids( const QString &app, const QStringList &labels) const
00500 {
00501 QArray<int> results;
00502 QStringList::ConstIterator it;
00503 int i;
00504
00505 for ( i=0, it=labels.begin(); it!=labels.end(); i++, ++it ) {
00506 int value = id( app, *it );
00507 if ( value != 0 ) {
00508 int tmp = results.size();
00509 results.resize( tmp + 1 );
00510 results[ tmp ] = value;
00511 }
00512 }
00513 return results;
00514 }
00515
00521 int Categories::id( const QString &app, const QString &cat ) const
00522 {
00523 if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) )
00524 return 0;
00525 int uid = mGlobalCats.id( cat );
00526 if ( uid != 0 )
00527 return uid;
00528 return mAppCats[app].id( cat );
00529 }
00530
00531
00540 bool Categories::renameCategory( const QString &appname,
00541 const QString &oldName,
00542 const QString &newName )
00543 {
00544 QMap< QString, CategoryGroup >::Iterator
00545 appIt = mAppCats.find( appname );
00546
00547 if ( appIt != mAppCats.end() ) {
00548 CategoryGroup &cats = *appIt;
00549 int id = cats.id( oldName );
00550 if ( id != 0 && cats.rename( id, newName ) ) {
00551 emit categoryRenamed( *this, appname, id );
00552 return TRUE;
00553 }
00554 }
00555 return renameGlobalCategory( oldName, newName );
00556 }
00557
00564 bool Categories::renameGlobalCategory( const QString &oldName,
00565 const QString &newName )
00566 {
00567 int uid = mGlobalCats.id( oldName );
00568 if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) {
00569 emit categoryRenamed( *this, QString::null, uid );
00570 return TRUE;
00571 }
00572 return FALSE;
00573 }
00574
00579 void Categories::setGlobal( const QString &appname,
00580 const QString &catname,
00581 bool global )
00582 {
00583
00584 if ( mGlobalCats.contains( catname ) && !global ) {
00585 mGlobalCats.remove( catname );
00586 addCategory( appname, catname );
00587 return ;
00588 }
00589
00590
00591 if ( !global )
00592 return;
00593 if ( removeCategory( appname, catname, FALSE ) )
00594 addGlobalCategory( catname );
00595 }
00596
00600 bool Categories::isGlobal( const QString &catname ) const
00601 {
00602 return mGlobalCats.contains( catname );
00603 }
00604
00605
00610 bool Categories::exists( const QString &catname ) const
00611 {
00612 if ( isGlobal(catname) )
00613 return TRUE;
00614
00615 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt )
00616 if ( exists( appsIt.key(), catname ) )
00617 return TRUE;
00618
00619 return FALSE;
00620 }
00621
00626 bool Categories::exists( const QString &appname,
00627 const QString &catname) const
00628 {
00629 QMap< QString, CategoryGroup >::ConstIterator
00630 appIt = mAppCats.find( appname );
00631
00632 if ( appIt == mAppCats.end() )
00633 return FALSE;
00634
00635 return (*appIt).contains( catname );
00636 }
00637
00644 bool Categories::save( const QString &fname ) const
00645 {
00646 QString strNewFile = fname + ".new";
00647 QFile f( strNewFile );
00648 QString out;
00649 int total_written;
00650
00651 if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
00652 qWarning("Unable to write to %s", fname.latin1());
00653 return FALSE;
00654 }
00655
00656 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
00657 out += "<!DOCTYPE CategoryList>\n";
00658
00659 out += "<Categories>\n";
00660
00661 for ( QMap<int, QString>::ConstIterator git = mGlobalCats.idMap().begin();
00662 git != mGlobalCats.idMap().end(); ++git )
00663 out += "<Category id=\"" + QString::number(git.key()) + "\"" +
00664 " name=\"" + escapeString(*git) + "\" />\n";
00665
00666 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt=mAppCats.begin();
00667 appsIt != mAppCats.end(); ++appsIt ) {
00668 const QString &app = appsIt.key();
00669 const QMap<int, QString> &appcats = (*appsIt).idMap();
00670 for ( QMap<int, QString>::ConstIterator appcatit = appcats.begin();
00671 appcatit != appcats.end(); ++appcatit )
00672 out += "<Category id=\"" + QString::number(appcatit.key()) + "\"" +
00673 " app=\"" + escapeString(app) + "\"" +
00674 " name=\"" + escapeString(*appcatit) + "\" />\n";
00675 }
00676 out += "</Categories>\n";
00677
00678 QCString cstr = out.utf8();
00679 total_written = f.writeBlock( cstr.data(), cstr.length() );
00680 if ( total_written != int(cstr.length()) ) {
00681 f.close();
00682 QFile::remove( strNewFile );
00683 return FALSE;
00684 }
00685 f.close();
00686
00687 #ifdef Q_OS_WIN32
00688 QFile::remove( fname );
00689 #endif
00690 if ( ::rename( strNewFile.latin1(), fname.latin1() ) < 0 ) {
00691 qWarning( "problem renaming file %s to %s",
00692 strNewFile.latin1(), fname.latin1());
00693
00694 QFile::remove( strNewFile );
00695 }
00696
00697 return TRUE;
00698 }
00699
00706 bool Categories::load( const QString &fname )
00707 {
00708 QFile file( fname );
00709 if ( !file.open( IO_ReadOnly ) ) {
00710 qWarning("Unable to open %s", fname.latin1());
00711
00712 addGlobalCategory(tr("Business"));
00713 addGlobalCategory(tr("Personal"));
00714 save(fname);
00715
00716 return FALSE;
00717 }
00718
00719 clear();
00720 QByteArray ba = file.readAll();
00721 QString data = QString::fromUtf8( ba.data(), ba.size() );
00722 QChar *uc = (QChar *)data.unicode();
00723 int len = data.length();
00724
00725
00726
00727 QString name;
00728 QString id;
00729 QString app;
00730 int i = 0;
00731 while ( (i = data.find( "<Category ", i)) != -1 ) {
00732
00733 i += 10;
00734 name = QString::null;
00735 app = QString::null;
00736 while ( 1 ) {
00737
00738 while ( i < len &&
00739 (uc[i] == ' ' || uc[i] == '\n' || uc[i] == '\r') )
00740 i++;
00741
00742 if ( i >= len-2 || (uc[i] == '/' && uc[i+1] == '>') )
00743 break;
00744
00745 int j = i;
00746 while ( j < len && uc[j] != '=' )
00747 j++;
00748 QString attr = QConstString( uc+i, j-i ).string();
00749 i = ++j;
00750 while ( i < len && uc[i] != '"' )
00751 i++;
00752 j = ++i;
00753 while ( j < len && uc[j] != '"' )
00754 j++;
00755 QString value = Qtopia::plainString( QConstString( uc+i, j-i ).string() );
00756 i = j + 1;
00757
00758
00759 if ( attr == "id" )
00760 id = value;
00761 else if ( attr == "app" )
00762 app = value;
00763
00764 else if ( attr == "name" )
00765 name = value;
00766 }
00767
00768 if ( name.isNull() || id.isNull() ) {
00769 qWarning("No name or id in the category");
00770 continue;
00771 }
00772 if ( app.isNull() )
00773 mGlobalCats.add( id.toInt(), name );
00774 else
00775 mAppCats[ app ].add( id.toInt(), name );
00776 }
00777
00778 return TRUE;
00779 }
00780
00785 void Categories::clear()
00786 {
00787 mGlobalCats.clear();
00788 mAppCats.clear();
00789 }
00790
00794 void Categories::dump() const
00795 {
00796 qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() );
00797 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) {
00798 const QString &app = appsIt.key();
00799 QStringList appcats = (*appsIt).labels();
00800 qDebug("\tapp = %s\tcategories = %s", app.latin1(),
00801 appcats.join(", ").latin1() );
00802
00803 }
00804 }
00805
00806 QStringList CheckedListView::checked() const
00807 {
00808 QStringList strs;
00809 for ( QCheckListItem *i = (QCheckListItem *) firstChild();
00810 i; i = (QCheckListItem *)i->nextSibling() )
00811 if ( i->isOn() )
00812 strs += i->text( 0 );
00813 return strs;
00814 }
00815
00816 void CheckedListView::addCheckableList( const QStringList &options )
00817 {
00818 for ( QStringList::ConstIterator it = options.begin();
00819 it != options.end(); ++it ) {
00820 (void) new QCheckListItem( this, *it,
00821 QCheckListItem::CheckBox );
00822 }
00823 }
00824
00825 void CheckedListView::setChecked( const QStringList &checked )
00826 {
00827
00828 bool showingChecked = FALSE;
00829 for ( QCheckListItem *i = (QCheckListItem *) firstChild();
00830 i; i = (QCheckListItem *)i->nextSibling() )
00831
00832
00833 if ( checked.find( i->text( 0 ) ) != checked.end() ) {
00834 i->setOn( TRUE );
00835
00836 if ( !showingChecked ) {
00837 ensureItemVisible( i );
00838 showingChecked = TRUE;
00839 }
00840 }
00841 else
00842 i->setOn( FALSE );
00843 }
00844
00933
00934 QStringList Categories::labels( const QString & app, const QArray<int> &catids ) const
00935 {
00936 QStringList strs = mGlobalCats.labels( catids );
00937 strs += mAppCats[app].labels( catids );
00938 return strs;
00939 }