From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'library/backend/categories.cpp') diff --git a/library/backend/categories.cpp b/library/backend/categories.cpp new file mode 100644 index 0000000..91331db --- a/dev/null +++ b/library/backend/categories.cpp @@ -0,0 +1,701 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included +** in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#include "categories.h" +#include +#include +#include +#include "stringutil.h" + +using namespace Qtopia; + +/*********************************************************** + * + * CategoryGroup + * + **********************************************************/ + +#ifdef PALMTOPCENTER +UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter ); +#else +UidGen CategoryGroup::sUidGen( UidGen::Qtopia ); +#endif + +int CategoryGroup::add( const QString &label ) +{ + if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) + return 0; + + QMap::Iterator findIt = mLabelIdMap.find( label ); + if ( findIt != mLabelIdMap.end() ) + return 0; + int newUid = uidGen().generate(); + insert( newUid, label ); + return newUid; +} + +void CategoryGroup::insert( int uid, const QString &label ) +{ + uidGen().store( uid ); + mIdLabelMap[uid] = label; + mLabelIdMap[label] = uid; +} + +bool CategoryGroup::add( int uid, const QString &label ) +{ + if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) + return FALSE; + + QMap::ConstIterator labelIt = mLabelIdMap.find( label ); + if ( labelIt != mLabelIdMap.end() ) + return FALSE; + QMap::ConstIterator idIt = mIdLabelMap.find( uid ); + if ( idIt != mIdLabelMap.end() ) + return FALSE; + insert( uid, label ); + return TRUE; +} + +bool CategoryGroup::remove( const QString &label ) +{ + QMap::Iterator findIt = mLabelIdMap.find( label ); + if ( findIt == mLabelIdMap.end() ) + return FALSE; + + mIdLabelMap.remove( *findIt ); + mLabelIdMap.remove( findIt ); + + return TRUE; +} + +bool CategoryGroup::remove( int uid ) +{ + QMap::Iterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return FALSE; + + mLabelIdMap.remove( *idIt ); + mIdLabelMap.remove( idIt ); + + return TRUE; +} + +bool CategoryGroup::rename( int uid, const QString &newLabel ) +{ + if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") ) + return FALSE; + + QMap::Iterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return FALSE; + + mLabelIdMap.remove( *idIt ); + mLabelIdMap[newLabel] = uid; + *idIt = newLabel; + + return TRUE; +} + +bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel ) +{ + return rename( id(oldLabel), newLabel ); +} + +bool CategoryGroup::contains(int uid) const +{ + return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() ); +} + +bool CategoryGroup::contains(const QString &label) const +{ + return ( mLabelIdMap.find( label ) != mLabelIdMap.end() ); +} + +/** Returns label associated with the uid or QString::null if + * not found + */ +const QString &CategoryGroup::label(int uid) const +{ + QMap::ConstIterator idIt = mIdLabelMap.find( uid ); + if ( idIt == mIdLabelMap.end() ) + return QString::null; + return *idIt; +} + +/** Returns the uid associated with label or 0 if not found */ +int CategoryGroup::id(const QString &label) const +{ + QMap::ConstIterator labelIt = mLabelIdMap.find( label ); + if ( labelIt == mLabelIdMap.end() ) + return 0; + return *labelIt; +} + +QStringList CategoryGroup::labels() const +{ + QStringList labels; + for ( QMap::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + labels += *it; + // ### I don't think this is the place for this... +// labels.sort(); + return labels; +} + +QStringList CategoryGroup::labels(const QArray &catids ) const +{ + QStringList labels; + if ( catids.count() == 0 ) + return labels; + for ( QMap::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + if ( catids.find( it.key() ) != -1 ) + labels += *it; + return labels; +} + +QArray CategoryGroup::ids( const QStringList &cats ) const +{ + QArray results; + + for ( QStringList::ConstIterator catIt = cats.begin(); + catIt != cats.end(); ++catIt ) { + if ( *catIt == QObject::tr("All") || *catIt == QObject::tr("Unfiled") ) + continue; + int value = id( *catIt ); + if ( value != 0 ) { + int tmp = results.size(); + results.resize( tmp + 1 ); + results[ tmp ] = value; + } + } + + return results; +} + +QArray CategoryGroup::ids() const +{ + QArray results( mIdLabelMap.count() ); + int i = 0; + for ( QMap::ConstIterator it = mIdLabelMap.begin(); + it != mIdLabelMap.end(); ++it ) + results[i++] = it.key(); + + return results; +} + +/*********************************************************** + * + * Categories + * + **********************************************************/ + +/** Add the category name as long as it doesn't already exist locally + * or globally. Return TRUE if added, FALSE if conflicts. + */ +int Categories::addCategory( const QString &appname, + const QString &catname, + int uid ) +{ + if ( mGlobalCats.contains(catname) ) + return 0; + + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) { + CategoryGroup newgroup; + newgroup.add( uid, catname ); + mAppCats.insert( appname, newgroup ); + emit categoryAdded( *this, appname, uid ); + return uid; + } + + CategoryGroup &cats = *appIt; + cats.add( uid, catname ); + emit categoryAdded( *this, appname, uid ); + return uid; +} + +int Categories::addCategory( const QString &appname, + const QString &catname ) +{ + if ( mGlobalCats.contains(catname) ) + return 0; + + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) { + CategoryGroup newgroup; + int uid = newgroup.add( catname ); + mAppCats.insert( appname, newgroup ); + emit categoryAdded( *this, appname, uid ); + return uid; + } + + CategoryGroup &cats = *appIt; + int uid = cats.add( catname ); + if ( !uid ) + return 0; + emit categoryAdded( *this, appname, uid ); + return uid; +} + +int Categories::addGlobalCategory( const QString &catname, int uid ) +{ + mGlobalCats.add( uid, catname ); + emit categoryAdded( *this, QString::null, uid ); + return uid; +} + +int Categories::addGlobalCategory( const QString &catname ) +{ + int uid = mGlobalCats.add( catname ); + if ( !uid ) + return 0; + emit categoryAdded( *this, QString::null, uid ); + return uid; +} + +/** Removes the category from the application; if it is not found + * in the application, then it attempts to remove it from + * the global list + */ +bool Categories::removeCategory( const QString &appname, + const QString &catname, + bool checkGlobal ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + int uid = cats.id( catname ); + if ( cats.remove( uid ) ) { + emit categoryRemoved( *this, appname, uid ); + return TRUE; + } + } + if ( !checkGlobal ) + return FALSE; + return removeGlobalCategory( catname ); +} + +bool Categories::removeCategory( const QString &appname, int uid ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + if ( cats.remove( uid ) ) { + emit categoryRemoved( *this, appname, uid ); + return TRUE; + } + } + return FALSE; +} + +bool Categories::removeGlobalCategory( const QString &catname ) +{ + int uid = mGlobalCats.id( catname ); + if ( mGlobalCats.remove( uid ) ) { + emit categoryRemoved( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + + +bool Categories::removeGlobalCategory( int uid ) +{ + if ( mGlobalCats.remove( uid ) ) { + emit categoryRemoved( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + +/** Returns the sorted list of all categories that are associated with + * the app. If includeGlobal parameter is TRUE then the returned + * categories will include the global category items. + */ +QStringList Categories::labels( const QString &app, + bool includeGlobal, + ExtraLabels extra ) const +{ + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( app ); + QStringList cats; + switch ( extra ) { + case NoExtra: break; + case AllUnfiled: + cats.append( tr("All") ); + cats.append( tr("Unfiled") ); + break; + case AllLabel: + cats.append( tr("All") ); + break; + case UnfiledLabel: + cats.append( tr("Unfiled") ); + break; + } + if ( appIt != mAppCats.end() ) + cats += (*appIt).labels(); + else qDebug("Categories::labels didn't find app %s", app.latin1() ); + if ( includeGlobal ) + cats += mGlobalCats.labels(); + // I don't think a sorted list is useful, the user might find prefer + // it in the original order. +// cats.sort(); + return cats; +} + +QString Categories::label( const QString &app, int id ) const +{ + if ( mGlobalCats.contains( id ) ) + return mGlobalCats.label( id ); + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( app ); + if ( appIt == mAppCats.end() ) + return QString::null; + return (*appIt).label( id ); +} + +QStringList Categories::labels( const QString & app, + const QArray &catids ) const +{ + QStringList strs = mGlobalCats.labels( catids ); + strs += mAppCats[app].labels( catids ); + return strs; +} + +/** Returns a single string associated with the cat ids for display in + * a combobox or any area that requires one string. If catids are empty + * then "Unfiled" will be returned. If multiple categories are assigned + * the first cat id is shown with " (multi)" appended to the string. + */ +QString Categories::displaySingle( const QString &app, + const QArray &catids, + DisplaySingle display ) const +{ + QStringList strs = labels( app, catids ); + if ( !strs.count() ) + return tr("Unfiled"); + strs.sort(); + QString r; + if ( strs.count() > 1 ) { + switch ( display ) { + case ShowFirst: + r = strs.first(); + break; + case ShowMulti: + r = strs.first() + tr(" (multi.)"); + break; + case ShowAll: + r = strs.join(" "); + break; + } + } + else r = strs.first(); + return r; +} + +QArray Categories::ids( const QString &app ) const +{ + QArray allIds = mGlobalCats.ids(); + QArray appIds = mAppCats[app].ids(); + + // we should make the guarentee that the ids are in the + // same order as the labels, (i.e. app cats then global) + // otherwise there is no point in having these two separate functions. + uint appSize = appIds.size(); + appIds.resize( appSize + allIds.size() ); + for ( uint i = appSize; i < appIds.size(); ++i ) + appIds[int(i)] = allIds[int(i - appSize)]; + + return appIds; +} + +QArray Categories::ids( const QString &app, const QStringList &cats ) const +{ + QArray allIds = mGlobalCats.ids( cats ); + QArray appIds = mAppCats[app].ids( cats ); + + uint appSize = appIds.size(); + appIds.resize( appSize + allIds.size() ); + for ( uint i = appSize; i < appIds.size(); ++i ) + appIds[int(i)] = allIds[int(i - appSize)]; + + return appIds; +} + +int Categories::id( const QString &app, const QString &cat ) const +{ + if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) ) + return 0; + int uid = mGlobalCats.id( cat ); + if ( uid != 0 ) + return uid; + return mAppCats[app].id( cat ); +} + + +/** Return TRUE if renaming succeeded; FALSE if app name not found, + * or if there was a name conflict + */ +bool Categories::renameCategory( const QString &appname, + const QString &oldName, + const QString &newName ) +{ + QMap< QString, CategoryGroup >::Iterator + appIt = mAppCats.find( appname ); + + if ( appIt != mAppCats.end() ) { + CategoryGroup &cats = *appIt; + int id = cats.id( oldName ); + if ( id != 0 && cats.rename( id, newName ) ) { + emit categoryRenamed( *this, appname, id ); + return TRUE; + } + } + return renameGlobalCategory( oldName, newName ); +} + +bool Categories::renameGlobalCategory( const QString &oldName, + const QString &newName ) +{ + int uid = mGlobalCats.id( oldName ); + if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) { + emit categoryRenamed( *this, QString::null, uid ); + return TRUE; + } + return FALSE; +} + +void Categories::setGlobal( const QString &appname, + const QString &catname, + bool global ) +{ + // if in global and should be in app; then move it + if ( mGlobalCats.contains( catname ) && !global ) { + mGlobalCats.remove( catname ); + addCategory( appname, catname ); + return ; + } + + // if in app and should be in global, then move it + if ( !global ) + return; + if ( removeCategory( appname, catname, FALSE ) ) + addGlobalCategory( catname ); +} + +bool Categories::isGlobal( const QString &catname ) const +{ + return mGlobalCats.contains( catname ); +} + + +/** Returns true if the catname is associated with any application + */ +bool Categories::exists( const QString &catname ) const +{ + if ( isGlobal(catname) ) + return TRUE; + + for ( QMap::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) + if ( exists( appsIt.key(), catname ) ) + return TRUE; + + return FALSE; +} + +bool Categories::exists( const QString &appname, + const QString &catname) const +{ + QMap< QString, CategoryGroup >::ConstIterator + appIt = mAppCats.find( appname ); + + if ( appIt == mAppCats.end() ) + return FALSE; + + return (*appIt).contains( catname ); +} + +bool Categories::save( const QString &fname ) const +{ + QFile file( fname ); + if ( !file.open( IO_WriteOnly ) ) { + qWarning("Unable to write to %s", fname.latin1()); + return FALSE; + } + + QTextStream ts( &file ); + ts << "\n"; + ts << "" << endl; + + ts << "" << endl; + for ( QMap::ConstIterator git = mGlobalCats.idMap().begin(); + git != mGlobalCats.idMap().end(); ++git ) + ts << "" << endl; + + for ( QMap::ConstIterator appsIt=mAppCats.begin(); + appsIt != mAppCats.end(); ++appsIt ) { + const QString &app = appsIt.key(); + const QMap &appcats = (*appsIt).idMap(); + for ( QMap::ConstIterator appcatit = appcats.begin(); + appcatit != appcats.end(); ++appcatit ) + ts << "" << endl; + } + ts << "" << endl; + + file.close(); + return TRUE; +} + +bool Categories::load( const QString &fname ) +{ + QFile file( fname ); + if ( !file.open( IO_ReadOnly ) ) { + qWarning("Unable to open %s", fname.latin1()); + return FALSE; + } + + clear(); + QByteArray ba = file.readAll(); + QString data = QString::fromUtf8( ba.data(), ba.size() ); + QChar *uc = (QChar *)data.unicode(); + int len = data.length(); + + // QTime t; + // t.start(); + QString name; + QString id; + QString app; + int i = 0; + while ( (i = data.find( "= len-2 || (uc[i] == '/' && uc[i+1] == '>') ) + break; + // we have another attribute read it. + int j = i; + while ( j < len && uc[j] != '=' ) + j++; + QString attr = QConstString( uc+i, j-i ).string(); + i = ++j; // skip = + while ( i < len && uc[i] != '"' ) + i++; + j = ++i; + while ( j < len && uc[j] != '"' ) + j++; + QString value = Qtopia::plainString( QConstString( uc+i, j-i ).string() ); + i = j + 1; + +// qDebug("attr='%s' value='%s'", attr.latin1(), value.latin1() ); + if ( attr == "id" ) + id = value; + else if ( attr == "app" ) + app = value; + + else if ( attr == "name" ) + name = value; + } + + if ( name.isNull() || id.isNull() ) { + qWarning("No name or id in the category"); + continue; + } + if ( app.isNull() ) + mGlobalCats.add( id.toInt(), name ); + else + mAppCats[ app ].add( id.toInt(), name ); + } + + return TRUE; +} + +void Categories::clear() +{ + mGlobalCats.clear(); + mAppCats.clear(); +} + +void Categories::dump() const +{ + qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() ); + for ( QMap::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) { + const QString &app = appsIt.key(); + QStringList appcats = (*appsIt).labels(); + qDebug("\tapp = %s\tcategories = %s", app.latin1(), + appcats.join(", ").latin1() ); + + } +} + +QStringList CheckedListView::checked() const +{ + QStringList strs; + for ( QCheckListItem *i = (QCheckListItem *) firstChild(); + i; i = (QCheckListItem *)i->nextSibling() ) + if ( i->isOn() ) + strs += i->text( 0 ); + return strs; +} + +void CheckedListView::addCheckableList( const QStringList &options ) +{ + for ( QStringList::ConstIterator it = options.begin(); + it != options.end(); ++it ) { + (void) new QCheckListItem( this, *it, + QCheckListItem::CheckBox ); + } +} + +void CheckedListView::setChecked( const QStringList &checked ) +{ + // iterate over all items + bool showingChecked = FALSE; + for ( QCheckListItem *i = (QCheckListItem *) firstChild(); + i; i = (QCheckListItem *)i->nextSibling() ) + // see if the item should be checked by searching the + // checked list + if ( checked.find( i->text( 0 ) ) != checked.end() ) { + i->setOn( TRUE ); + // make sure it is showing at least one checked item + if ( !showingChecked ) { + ensureItemVisible( i ); + showingChecked = TRUE; + } + } + else + i->setOn( FALSE ); +} -- cgit v0.9.0.2