summaryrefslogtreecommitdiff
path: root/library/backend
Side-by-side diff
Diffstat (limited to 'library/backend') (more/less context) (ignore whitespace changes)
-rw-r--r--library/backend/categories.cpp9
-rw-r--r--library/backend/categories.h2
-rw-r--r--library/backend/event.cpp4
-rw-r--r--library/backend/palmtoprecord.h12
4 files changed, 17 insertions, 10 deletions
diff --git a/library/backend/categories.cpp b/library/backend/categories.cpp
index 2e84089..cce9f38 100644
--- a/library/backend/categories.cpp
+++ b/library/backend/categories.cpp
@@ -1,936 +1,931 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of the 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 <qtopia/private/categories.h>
#include <qtopia/stringutil.h>
#include <qfile.h>
#include <qcstring.h>
#include <qtextstream.h>
using namespace Qtopia;
/***********************************************************
*
* CategoryGroup
*
**********************************************************/
#ifdef PALMTOPCENTER
UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter );
#else
UidGen CategoryGroup::sUidGen( UidGen::Qtopia );
#endif
/*! \class CategoryGroup categories.h
\brief Helper class that is used by Categories
CategoryGroup is a group of categories that is associated with an
application or global set. Mainly it defines a map of ids to
category labels and category labels to ids. Lookups can be done with
labels or unique idenifiers.
\ingroup qtopiaemb
\ingroup qtopiadesktop
\warning Categories API will likely change between Qtopia 1.5 and Qtopia 3
\sa Categories::appGroupMap(), Categories::globalGroup()
*/
/*! Add \a label and return the UID. If failure, then 0 is returned. Note
that All and Unfiled are reserved labels.
\internal
*/
int CategoryGroup::add( const QString &label )
{
if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
return 0;
QMap<QString,int>::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;
}
/*! \internal
*/
bool CategoryGroup::add( int uid, const QString &label )
{
if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
return FALSE;
QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
if ( labelIt != mLabelIdMap.end() )
return FALSE;
QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
if ( idIt != mIdLabelMap.end() )
return FALSE;
insert( uid, label );
return TRUE;
}
/*! Returns TRUE if \a label was removed from the group, FALSE if not.
\internal
*/
bool CategoryGroup::remove( const QString &label )
{
QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
if ( findIt == mLabelIdMap.end() )
return FALSE;
mIdLabelMap.remove( *findIt );
mLabelIdMap.remove( findIt );
return TRUE;
}
/*! Returns TRUE if \a uid was removed from the group, FALSE if not.
\internal
*/
bool CategoryGroup::remove( int uid )
{
QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid );
if ( idIt == mIdLabelMap.end() )
return FALSE;
mLabelIdMap.remove( *idIt );
mIdLabelMap.remove( idIt );
return TRUE;
}
/*! \internal
*/
bool CategoryGroup::rename( int uid, const QString &newLabel )
{
if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") )
return FALSE;
QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid );
if ( idIt == mIdLabelMap.end() )
return FALSE;
mLabelIdMap.remove( *idIt );
mLabelIdMap[newLabel] = uid;
*idIt = newLabel;
return TRUE;
}
/*! \internal
*/
bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel )
{
return rename( id(oldLabel), newLabel );
}
/*! Returns TRUE if \a uid is stored in this group, FALSE if not. */
bool CategoryGroup::contains(int uid) const
{
return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() );
}
/*! Returns TRUE if \a label is stored in this group, FALSE if not. */
bool CategoryGroup::contains(const QString &label) const
{
return ( mLabelIdMap.find( label ) != mLabelIdMap.end() );
}
/*! Returns label associated with the \a uid or QString::null if
not found
*/
const QString &CategoryGroup::label(int uid) const
{
QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
if ( idIt == mIdLabelMap.end() )
return QString::null;
return *idIt;
}
/*! Returns the uid associated with \a label or 0 if not found */
int CategoryGroup::id(const QString &label) const
{
QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
if ( labelIt == mLabelIdMap.end() )
return 0;
return *labelIt;
}
/*! Returns a list of all labels stored in this group. */
QStringList CategoryGroup::labels() const
{
QStringList labels;
for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
it != mIdLabelMap.end(); ++it )
labels += *it;
// ### I don't think this is the place for this...
// labels.sort();
return labels;
}
/*! Returns a list of all labels associated with the \a catids */
QStringList CategoryGroup::labels(const QArray<int> &catids ) const
{
QStringList labels;
if ( catids.count() == 0 )
return labels;
for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
it != mIdLabelMap.end(); ++it )
if ( catids.find( it.key() ) != -1 )
labels += *it;
return labels;
}
/***********************************************************
*
* Categories
*
**********************************************************/
/*!
\class Categories categories.h
\brief The Categories class is a database that groups categories and maps ids to names.
The Categories class is the low level Categories accessor class. To
add a category menu and filter for your application, see CategoryMenu.
The Categories class allows the developer to add, remove, and rename
categories. Categories can be created for an individual application
such as Todo List or to be used for all applications. Categories
that can be used by all applications are called global
categories. Each PalmtopRecord subclass stores categories as an
QArray<int> using PalmtopRecord::setCategories() and
PalmtopRecord::categories(). This allows each record to be assigned
to multiple categories. This also allows the user to rename a
category and for it to update automatically in all records.
This class provides several methods to convert between a category id
and it's associated string such as id(), ids(), label() and labels(). A
helper class called CategoryGroup is used to access categories of a
single application group, such as Todo List. Global categories can
also be accessed via CategoryGroup objects. See appGroupMap() and
globalGroup() for the appropriate accessor methods.
Categories are stored in an xml file in the Settings directory
(Categories.xml). A global function called categoryFileName() will
return to appropriate QString file location to be passed to load()
and save() for the master categories database.
\ingroup qtopiaemb
\ingroup qtopiadesktop
\warning Categories API will likely change between Qtopia 1.5 and Qtopia 3
\sa CategoryGroup, CategoryMenu
*/
/*!
Add the category name as long as it doesn't already exist locally or
globally. The \a uid is assigned to the category if successfully
added. Return \a uid if added, 0 if conflicts (error).
\internal
*/
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;
}
/*!
Add the category name as long as it doesn't already exist locally or
globally. Return UID if added, 0 if conflicts (error).
*/
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;
}
/*!
\internal
*/
int Categories::addGlobalCategory( const QString &catname, int uid )
{
mGlobalCats.add( uid, catname );
emit categoryAdded( *this, QString::null, uid );
return uid;
}
/*!
Add the global category \a catname while checking that it doesn't
already exist globally. Return UID if added, 0 if conflicts.
\sa addCategory()
*/
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 \a catname from the application group. If it is not
found in the application group and \a checkGlobal is TRUE, 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 );
}
/*!
Removes the \a uid from the application group \a appname. Returns TRUE
if success, FALSE if not found.
*/
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;
}
/*!
Removes the global category \a catname. Returns TRUE
if success, FALSE if not found.
*/
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;
}
/*!
Removes the global category \a uid. Returns TRUE
if success, FALSE if not found.
*/
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 \a app. If \a includeGlobal 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;
if ( appIt != mAppCats.end() )
cats += (*appIt).labels();
//else qDebug("Categories::labels didn't find app %s", app.latin1() );
if ( includeGlobal )
cats += mGlobalCats.labels();
cats.sort();
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;
}
return cats;
}
/*!
Returns the label associated with the id
*/
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 );
}
/*!
Returns a single string associated with \a catids for display in a
combobox or any area that requires one string. If \a catids are empty
then "Unfiled" will be returned. If multiple categories are
assigned then the behavior depends on the DisplaySingle type.
If \a display is set to ShowMulti then " (multi)" appended to the
first string. If \a display is set to ShowAll, then a space
seperated string is returned with all categories. If ShowFirst is
set, the just the first string is returned.
*/
QString Categories::displaySingle( const QString &app,
const QArray<int> &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();
+ else r = strs.first();
return r;
}
/*!
Returns all ids associated with the application CategoryGroup \a app
and the passed in \a labels in that group.
*/
QArray<int> Categories::ids( const QString &app, const QStringList &labels) const
{
QArray<int> results;
QStringList::ConstIterator it;
int i;
for ( i=0, it=labels.begin(); it!=labels.end(); i++, ++it ) {
int value = id( app, *it );
if ( value != 0 ) {
int tmp = results.size();
results.resize( tmp + 1 );
results[ tmp ] = value;
}
}
return results;
}
/*!
Returns the id associated with the app. If the id is not found in the
application CategoryGroup, then it searches the global CategoryGroup.
If it is not found it either, 0 is returned.
*/
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 \a appname or \a oldName
is not found, or if \a newName conflicts with an existing category
in the CategoryGroup.
It will first search the CategoryGroup associated with \a appname
and if not found it will try to replace in global CategoryGroup.
*/
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 );
}
/*!
Return TRUE if renaming succeeded; FALSE if \a appname or \a oldName
is not found, or if \a newName conflicts with an existing category
in the CategoryGroup. This function will only rename categories found
in the global CategoryGroup.
*/
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;
}
/*!
Changes the grouping of a category. If a category was global and \a global
is set to TRUE, then the \a catname will be moved to the \a appname group.
*/
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 );
}
/*!
Returns TRUE if the \a catname is in the global CategoryGroup, FALSE if not.
*/
bool Categories::isGlobal( const QString &catname ) const
{
return mGlobalCats.contains( catname );
}
/*!
Returns true if the \a catname is associated with any CategoryGroup,
including global.
*/
bool Categories::exists( const QString &catname ) const
{
if ( isGlobal(catname) )
return TRUE;
for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt )
if ( exists( appsIt.key(), catname ) )
return TRUE;
return FALSE;
}
/*!
Returns TRUE if the \a catname is associated with the \a appname
CategoryGroup, FALSE if not found.
*/
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 );
}
/*!
Saves the Categories database to the \a fname. See categoryFileName()
for the default file name string used for the shared category database.
Returns FALSE if there is error writing the file or TRUE on success.
*/
bool Categories::save( const QString &fname ) const
{
QString strNewFile = fname + ".new";
QFile f( strNewFile );
QString out;
int total_written;
if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
qWarning("Unable to write to %s", fname.latin1());
return FALSE;
}
out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
out += "<!DOCTYPE CategoryList>\n";
out += "<Categories>\n";
for ( QMap<int, QString>::ConstIterator git = mGlobalCats.idMap().begin();
git != mGlobalCats.idMap().end(); ++git )
out += "<Category id=\"" + QString::number(git.key()) + "\"" +
" name=\"" + escapeString(*git) + "\" />\n";
for ( QMap<QString, CategoryGroup>::ConstIterator appsIt=mAppCats.begin();
appsIt != mAppCats.end(); ++appsIt ) {
const QString &app = appsIt.key();
const QMap<int, QString> &appcats = (*appsIt).idMap();
for ( QMap<int, QString>::ConstIterator appcatit = appcats.begin();
appcatit != appcats.end(); ++appcatit )
out += "<Category id=\"" + QString::number(appcatit.key()) + "\"" +
" app=\"" + escapeString(app) + "\"" +
" name=\"" + escapeString(*appcatit) + "\" />\n";
}
out += "</Categories>\n";
QCString cstr = out.utf8();
total_written = f.writeBlock( cstr.data(), cstr.length() );
if ( total_written != int(cstr.length()) ) {
f.close();
QFile::remove( strNewFile );
return FALSE;
}
f.close();
#ifdef Q_OS_WIN32
QFile::remove( fname );
#endif
if ( ::rename( strNewFile.latin1(), fname.latin1() ) < 0 ) {
qWarning( "problem renaming file %s to %s",
strNewFile.latin1(), fname.latin1());
// remove the tmp file...
QFile::remove( strNewFile );
}
return TRUE;
}
/*!
Loads the Categories database using \a fname. See categoryFileName()
for the default file name string used for the shared category database.
Returns FALSE if there is error reading the file or TRUE on success.
*/
bool Categories::load( const QString &fname )
{
QFile file( fname );
if ( !file.open( IO_ReadOnly ) ) {
qWarning("Unable to open %s", fname.latin1());
addGlobalCategory(tr("Business"));
addGlobalCategory(tr("Personal"));
save(fname);
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( "<Category ", i)) != -1 ) {
i += 10;
name = QString::null;
app = QString::null;
while ( 1 ) {
// skip white space
while ( i < len &&
(uc[i] == ' ' || uc[i] == '\n' || uc[i] == '\r') )
i++;
// if at the end, then done
if ( i >= 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;
}
/*!
Clear the categories in memory. Equivelent to creating an empty Categories
object.
*/
void Categories::clear()
{
mGlobalCats.clear();
mAppCats.clear();
}
/*!
Dump the contents to standard out. Used for debugging only.
*/
void Categories::dump() const
{
qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() );
for ( QMap<QString, CategoryGroup>::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 );
}
/*! \fn Categories &Categories::operator= ( const Categories &c )
Performs deep copy.
*/
-/*! \fn QStringList Categories::labels( const QString & app, const QArray<int> &catids ) const
-
- Returns list of labels associated with the application and catids
-*/
-
/*! \fn QStringList Categories::globalCategories() const
Returns list of all global category labels
*/
/*! \fn const QMap<QString, CategoryGroup> &Categories::appGroupMap() const
Returns a map of application names to CategoryGroup. The CategoryGroup
class defines a map of ids to category labels and category labels to ids.
*/
/*! \fn const CategoryGroup &Categories::globalGroup() const
Returns the global CategoryGroup. The CategoryGroup
class defines a map of ids to category labels and category labels to ids.
*/
/*! \fn void Categories::categoryAdded( const Categories &cats, const QString &appname, int uid)
Emitted if a category is added.
\a cats is a const reference to this object
\a appname is the CategoryGroup application name that the category was added to or QString::null if it was global
\a uid is the unique identifier associated with the added category
-*/
+*/
/*! \fn void Categories::categoryRemoved( const Categories &cats, const QString &appname,
int uid)
Emitted if removed category is removed.
\a cats is a const reference to this object
\a appname is the CategoryGroup application name that the category was removed from or QString::null if it was the global CategoryGroup
\a uid is the unique identifier associated with the removed category
*/
/*! \fn void Categories::categoryRenamed( const Categories &cats, const QString &appname,
int uid)
Emitted if \a uid in the \a appname CategoryGroup is renamed in \a cats
object.
\a cats is a const reference to this object
\a appname is the CategoryGroup application name that the category was renamed in or QString::null if it was the global CategoryGroup
\a uid is the unique identifier associated with the renamed category
*/
/*! \fn Categories::Categories( QObject *parent=0, const char *name = 0 )
Constructor for an empty Categories object.
*/
/*! \fn Categories::Categories( const Categories &copyFrom )
Deep copy constructor
*/
/*! \fn Categories::~Categories()
Empty destructor. Call save() before destruction if there are changes
that need to be saved.
*/
/*! \fn CategoryGroup::clear()
\internal
*/
/*! \fn const QMap<int, QString> &CategoryGroup::idMap() const
Returns a const reference to the id to label QMap
*/
/*! \fn CategoryGroup::CategoryGroup()
\internal
*/
/*! \fn CategoryGroup::CategoryGroup(const CategoryGroup &c)
\internal
*/
diff --git a/library/backend/categories.h b/library/backend/categories.h
index ba65ee3..d5b3669 100644
--- a/library/backend/categories.h
+++ b/library/backend/categories.h
@@ -1,226 +1,226 @@
/**********************************************************************
** 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.
**
**********************************************************************/
#ifndef QTPALMTOP_CATEGORIES_H
#define QTPALMTOP_CATEGORIES_H
#include <qstring.h>
#include <qstringlist.h>
#include <qmap.h>
#include <qlistview.h>
#include <qarray.h>
#include "qpcglobal.h"
#include "palmtopuidgen.h"
class CategoryGroup;
#if defined(QPC_TEMPLATEDLL)
// MOC_SKIP_BEGIN
template class QPC_EXPORT QMap<int, QString>;
template class QPC_EXPORT QMap<QString, int>;
template class QPC_EXPORT QMap< QString, CategoryGroup >;
// MOC_SKIP_END
#endif
class QPC_EXPORT CategoryGroup
{
friend class Categories;
public:
CategoryGroup(): mIdLabelMap(), mLabelIdMap() { }
CategoryGroup( const CategoryGroup &c ) :
mIdLabelMap( c.mIdLabelMap), mLabelIdMap( c.mLabelIdMap ) { }
void clear() { mIdLabelMap.clear(); mLabelIdMap.clear(); }
int add( const QString &label );
bool add( int uid, const QString &label );
bool remove( const QString &label );
bool remove( int uid );
bool rename( int uid, const QString &newLabel );
bool rename( const QString &oldLabel, const QString &newLabel );
bool contains(int id) const;
bool contains(const QString &label) const;
/** Returns label associated with the uid or QString::null if
* not found
*/
const QString &label(int id) const;
/** Returns the uid associated with label or 0 if not found */
int id(const QString &label) const;
/** Returns a sorted list of labels */
QStringList labels() const;
QStringList labels( const QArray<int> &catids ) const;
const QMap<int, QString> &idMap() const { return mIdLabelMap; }
private:
void insert( int uid, const QString &label );
QMap<int, QString> mIdLabelMap;
QMap<QString, int> mLabelIdMap;
static Qtopia::UidGen &uidGen() { return sUidGen; }
static Qtopia::UidGen sUidGen;
};
-/** Map from application name to categories */
+/* Map from application name to categories */
class QPC_EXPORT Categories : public QObject
{
Q_OBJECT
public:
Categories( QObject *parent=0, const char *name = 0 )
: QObject( parent, name ), mGlobalCats(), mAppCats() { }
Categories( const Categories &copyFrom ) : QObject( copyFrom.parent() ),
mGlobalCats( copyFrom.mGlobalCats ),
mAppCats( copyFrom.mAppCats ) { }
virtual ~Categories() { }
Categories &operator= ( const Categories &c )
{ mAppCats = c.mAppCats; mGlobalCats = c.mGlobalCats; return *this; }
void clear();
/** Add the category name as long as it doesn't already exist
* locally or globally. Return UID if added, 0 if conflicts
* (error).
*/
int addCategory( const QString &appname, const QString &catname);
/** Add the category name as long as it doesn't already exist
* locally or globally. Return UID if added, 0 if conflicts
* (error).
*/
int addCategory( const QString &appname, const QString &catname, int uid);
/** Add the global category just checking that it doesn't
* already exist globally. Return UID if added, 0 if conflicts.
*/
int addGlobalCategory( const QString &catname );
/** Add the global category just checking that it doesn't
* already exist globally. Return UID if added, 0 if conflicts.
*/
int addGlobalCategory( const QString &catname, int uid );
/** Removes the category from the application; if it is not found
* in the application, then it removes it from the global list
*/
bool removeCategory( const QString &appName, const QString &catName,
bool checkGlobal = TRUE);
bool removeCategory( const QString &appName, int uid );
bool removeGlobalCategory( const QString &catName );
bool removeGlobalCategory( int uid );
QArray<int> ids( const QString &app, const QStringList &labels) const;
/** Returns the id associated with the app */
int id( const QString &app, const QString &cat ) const;
/** Returns the label associated with the id */
QString label( const QString &app, int id ) const;
enum ExtraLabels { NoExtra, AllUnfiled, AllLabel, UnfiledLabel };
/** 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.
* If extra = NoExtra, then
* If extra = AllUnfiled, then All and Unfiled will be prepended to
* the list
* If extra = AllLabel, then All is prepended
* If extra = UnfiledLabel, then Unfiled is prepended
*/
QStringList labels( const QString &app,
bool includeGlobal = TRUE,
ExtraLabels extra = NoExtra ) const;
enum DisplaySingle { ShowMulti, ShowAll, ShowFirst };
/** 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
* then the behavior depends on the DisplaySingle type.
* If /a display is set to ShowMulti then " (multi)" appended to the
* first string. If /a display is set to ShowAll, then a space seperated
* string is returned with all categories. If ShowFirst is returned,
* the just the first string is returned.
*/
QString displaySingle( const QString &app,
const QArray<int> &catids,
DisplaySingle display ) const;
QStringList globalCategories() const { return mGlobalCats.labels();}
bool renameCategory( const QString &appname,
const QString &oldName,
const QString &newName );
bool renameGlobalCategory( const QString &oldName,
const QString &newName );
void setGlobal( const QString &appname, const QString &catname,
bool value );
bool isGlobal( const QString &catname ) const;
/** Returns true if the catname is associated with any application
*/
bool exists( const QString &catname ) const;
bool exists( const QString &appname, const QString &catname) const;
bool save( const QString &fname ) const;
bool load( const QString &fname );
// for debugging
void dump() const;
const QMap<QString, CategoryGroup> &appGroupMap() const{ return mAppCats; }
const CategoryGroup &globalGroup() const { return mGlobalCats; }
signals:
/** emitted if added a category;
* the second param is the application the category was added to
* or null if global
* the third param is the uid of the newly added category
*/
void categoryAdded( const Categories &, const QString &, int );
/** emitted if removed a category
* the second param is the application the category was removed from
* or null if global
* the third param is the uid of the removed category
*/
void categoryRemoved( const Categories &, const QString &, int );
/** emitted if a category is renamed; the second param is the uid of
* the removed category */
void categoryRenamed( const Categories &, const QString &, int );
private:
CategoryGroup mGlobalCats;
QMap< QString, CategoryGroup > mAppCats;
};
class QPC_EXPORT CheckedListView : public QListView
{
public:
void addCheckableList( const QStringList &options );
void setChecked( const QStringList &checked );
QStringList checked() const;
};
#endif
diff --git a/library/backend/event.cpp b/library/backend/event.cpp
index d906f19..4c24ab3 100644
--- a/library/backend/event.cpp
+++ b/library/backend/event.cpp
@@ -1,1354 +1,1354 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of the 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 "event.h"
#include "qfiledirect_p.h"
#include <qtopia/timeconversion.h>
#include <qtopia/stringutil.h>
#include <qtopia/private/recordfields.h>
#include <qbuffer.h>
#include <time.h>
#include "vobject_p.h"
#include <stdio.h>
using namespace Qtopia;
static void write( QString& buf, const Event::RepeatPattern &r )
{
buf += " rtype=\"";
switch ( r.type ) {
case Event::Daily:
buf += "Daily";
break;
case Event::Weekly:
buf += "Weekly";
break;
case Event::MonthlyDay:
buf += "MonthlyDay";
break;
case Event::MonthlyDate:
buf += "MonthlyDate";
break;
case Event::Yearly:
buf += "Yearly";
break;
default:
buf += "NoRepeat";
break;
}
buf += "\"";
if ( r.days > 0 )
buf += " rweekdays=\"" + QString::number( static_cast<int>( r.days ) ) + "\"";
if ( r.position != 0 )
buf += " rposition=\"" + QString::number( r.position ) + "\"";
buf += " rfreq=\"" + QString::number( r.frequency ) + "\"";
buf += " rhasenddate=\"" + QString::number( static_cast<int>( r.hasEndDate ) ) + "\"";
if ( r.hasEndDate )
buf += " enddt=\""
+ QString::number( r.endDateUTC ? r.endDateUTC : time( 0 ) )
+ "\"";
buf += " created=\"" + QString::number( r.createTime ) + "\"";
}
Qtopia::UidGen Event::sUidGen( Qtopia::UidGen::Qtopia );
/*!
\class Event event.h
\brief The Event class holds the data of a calendar event.
This data includes descriptive data of the event and schedualing information.
\ingroup qtopiaemb
\ingroup qtopiadesktop
*/
/*!
\class Event::RepeatPattern
\class The Event::RepeatPattern class is internal.
\internal
*/
/*!
\enum Event::Days
\internal
*/
/*!
\enum Event::Type
\internal
*/
/*!
\enum Event::SoundTypeChoice
This enum type defines what kind of sound is made when an alarm occurs
for an event. The currently defined types are:
<ul>
<li>\c Silent - No sound is produced.
<li>\c Loud - A loud sound is produced.
</ul>
*/
/*!
\fn bool Event::operator<( const Event & ) const
\internal
*/
/*!
\fn bool Event::operator<=( const Event & ) const
\internal
*/
/*!
\fn bool Event::operator!=( const Event & ) const
\internal
*/
/*!
\fn bool Event::operator>( const Event & ) const
\internal
*/
/*!
\fn bool Event::operator>=( const Event & ) const
\internal
*/
/*!
\enum Event::RepeatType
This enum defines how a event will repeat, if at all.
<ul>
<li>\c NoRepeat - Event does not repeat.
<li>\c Daily - Event occurs every n days.
<li>\c Weekly - Event occurs every n weeks.
<li>\c MonthlyDay - Event occurs every n months. Event will always occur in
the same week and same day of week as the first event.
<li>\c MonthlyDate - Event occurs every n months. Event will always occur
on the same day of the month as the first event.
<li>\c Yearly - Event occurs every n years.
</ul>
*/
/*!
\fn bool Event::isAllDay() const
Returns TRUE if the event is an all day event. Otherwise returns FALSE.
*/
/*!
\fn void Event::setAllDay(bool allday)
If \a allday is TRUE, will set the event to be an all day event.
Otherwise sets the event to not be an all day event.
\warning This function may affect the start and end times of the event.
*/
/*!
- \fn QDateTime Event::start() const
+ \fn QDateTime Event::start(bool) const
Returns the start date and time of the first occurance of the event.
*/
/*!
- \fn QDateTime Event::end() const
+ \fn QDateTime Event::end(bool) const
Returns the end date and time of the first occurance of the event.
*/
/*!
\fn time_t Event::startTime() const
\internal
*/
/*!
\fn time_t Event::endTime() const
\internal
*/
/*!
\fn void Event::setAlarm(int delay, SoundTypeChoice s)
Sets the alarm delay of the event to \a delay and the sound type of the
alarm to \a s.
*/
/*!
\fn void Event::clearAlarm()
Clears the alarm for the event.
*/
/*!
\fn int Event::alarmDelay() const
Returns the delay in minutes between the alarm for an event and the
start of the event.
*/
/*!
\fn Event::RepeatType Event::repeatType() const
Returns the repeat pattern type for the event.
\sa frequency()
*/
/*!
\fn int Event::weekOffset() const
Returns the number of weeks from the start of the month that this event
occurs.
*/
/*!
\fn QDate Event::repeatTill() const
Returns the date that the event will continue to repeat until. If the event
repeats forever the value returned is undefined.
\sa repeatForever()
*/
/*!
\fn bool Event::repeatForever() const
Returns FALSE if there is a date set for the event to continue until.
Otherwise returns TRUE.
*/
/*!
\fn bool Event::doRepeat() const
\internal
*/
/*!
\fn bool Event::repeatOnWeekDay(int day) const
Returns TRUE if the event has a RepeatType of Weekly and is set to occur on
\a day each week. Otherwise returns FALSE.
\sa QDate::dayName()
*/
/*!
\fn void Event::setRepeatOnWeekDay(int day, bool enable)
If \a enable is TRUE then sets the event to occur on \a day each week.
Otherwise sets the event not to occur on \a day.
\warning this function is only relavent for a event with RepeatType of
Weekly.
\sa QDate::dayName()
*/
/*!
\fn int Event::frequency() const
Returns how often the event repeats.
\sa repeatType()
*/
/*!
\fn void Event::setRepeatType(RepeatType t)
Sets the repeat pattern type of the event to \a t.
\sa setFrequency()
*/
/*!
\fn void Event::setFrequency(int n)
Sets how often the event occurs with in its repeat pattern.
\sa setRepeatType()
*/
/*!
\fn void Event::setRepeatTill(const QDate &d)
Sets the event to repeat until \a d.
*/
/*!
\fn void Event::setRepeatForever(bool enable)
If \a enable is TRUE, sets the event to repeat forever. Otherwise
sets the event to stop repeating at some date.
\warning This function may affect the specific date the event will repeat
till.
*/
/*!
\fn bool Event::match(const QRegExp &r) const
Returns TRUE if the event matches the regular expression \a r.
Otherwise returns FALSE.
*/
/*!
\fn char Event::day(int)
\internal
*/
/*!
Creates a new, empty event.
*/
Event::Event() : Record()
{
startUTC = endUTC = time( 0 );
typ = Normal;
hAlarm = FALSE;
hRepeat = FALSE;
aMinutes = 0;
aSound = Silent;
pattern.type = NoRepeat;
pattern.frequency = -1;
}
/*!
\internal
*/
Event::Event( const QMap<int, QString> &map )
{
setDescription( map[DatebookDescription] );
setLocation( map[Location] );
setCategories( idsFromString( map[DatebookCategory] ) );
setTimeZone( map[TimeZone] );
setNotes( map[Note] );
setStart( TimeConversion::fromUTC( map[StartDateTime].toUInt() ) );
setEnd( TimeConversion::fromUTC( map[EndDateTime].toUInt() ) );
setType( (Event::Type) map[DatebookType].toInt() );
setAlarm( ( map[HasAlarm] == "1" ? TRUE : FALSE ), map[AlarmTime].toInt(), (Event::SoundTypeChoice)map[SoundType].toInt() );
Event::RepeatPattern p;
p.type = (Event::RepeatType) map[ RepeatPatternType ].toInt();
p.frequency = map[ RepeatPatternFrequency ].toInt();
p.position = map[ RepeatPatternPosition ].toInt();
p.days = map[ RepeatPatternDays ].toInt();
p.hasEndDate = map[ RepeatPatternHasEndDate ].toInt();
p.endDateUTC = map[ RepeatPatternEndDate ].toUInt();
setRepeat( p );
setUid( map[ DatebookUid ].toInt() );
}
/*!
Destroys an event.
*/
Event::~Event()
{
}
/*!
\internal
*/
int Event::week( const QDate& date )
{
// Calculates the week this date is in within that
// month. Equals the "row" is is in in the month view
int week = 1;
QDate tmp( date.year(), date.month(), 1 );
if ( date.dayOfWeek() < tmp.dayOfWeek() )
++week;
week += ( date.day() - 1 ) / 7;
return week;
}
/*!
\internal
*/
int Event::occurrence( const QDate& date )
{
// calculates the number of occurrances of this day of the
// week till the given date (e.g 3rd Wednesday of the month)
return ( date.day() - 1 ) / 7 + 1;
}
/*!
\internal
*/
int Event::dayOfWeek( char day )
{
int dayOfWeek = 1;
char i = Event::MON;
while ( !( i & day ) && i <= Event::SUN ) {
i <<= 1;
++dayOfWeek;
}
return dayOfWeek;
}
/*!
\internal
*/
int Event::monthDiff( const QDate& first, const QDate& second )
{
return ( second.year() - first.year() ) * 12 +
second.month() - first.month();
}
/*!
\internal
*/
QMap<int, QString> Event::toMap() const
{
QMap<int, QString> m;
if ( !description().isEmpty() )
m.insert( DatebookDescription, description() );
if ( !location().isEmpty() )
m.insert ( Location, location() );
if ( categories().count() )
m.insert ( DatebookCategory, idsToString( categories() ) );
if ( !timeZone().isEmpty() )
m.insert ( TimeZone, timeZone() );
if ( !notes().isEmpty() )
m.insert ( Note, notes() );
m.insert ( StartDateTime, QString::number( TimeConversion::toUTC( start() ) ) );
m.insert ( EndDateTime, QString::number( TimeConversion::toUTC( end() ) ) );
m.insert ( DatebookType, QString::number( (int)type() ) );
m.insert ( HasAlarm, ( hasAlarm() ? "1" : "0" ) );
m.insert ( SoundType, QString::number( (int)alarmSound() ) );
m.insert ( AlarmTime, QString::number( alarmTime() ) );
m.insert ( RepeatPatternType, QString::number( static_cast<int>( repeatPattern().type ) ) );
m.insert ( RepeatPatternFrequency, QString::number( repeatPattern().frequency ) );
m.insert ( RepeatPatternPosition, QString::number( repeatPattern().position ) );
m.insert ( RepeatPatternDays, QString::number( repeatPattern().days ) );
m.insert ( RepeatPatternHasEndDate, QString::number( static_cast<int>( repeatPattern().hasEndDate ) ) );
m.insert ( RepeatPatternEndDate, QString::number( repeatPattern().endDateUTC ) );
m.insert( DatebookUid, QString::number( uid()) );
return m;
}
/*!
\internal
*/
void Event::setRepeat( const RepeatPattern &p )
{
setRepeat( p.type != NoRepeat, p );
}
/*!
Sets the description of the event to \a s.
*/
void Event::setDescription( const QString &s )
{
descript = s;
}
/*!
Sets the location of the event to \a s.
*/
void Event::setLocation( const QString &s )
{
locat = s;
}
// void Event::setCategory( const QString &s )
// {
// categ = s;
// }
/*!
\internal
*/
void Event::setType( Type t )
{
typ = t;
}
/*!
Sets the start date and time of the first or only occurance of this event
to the date and time \a d. \a d should be in local time.
*/
void Event::setStart( const QDateTime &d )
{
startUTC = TimeConversion::toUTC( d );
}
/*!
\internal
*/
void Event::setStart( time_t time )
{
startUTC = time;
}
/*!
Sets the end date and time of the first or only occurance of this event
to the date and time \a d. \a d should be in local time.
*/
void Event::setEnd( const QDateTime &d )
{
endUTC = TimeConversion::toUTC( d );
}
/*!
\internal
*/
void Event::setEnd( time_t time )
{
endUTC = time;
}
/*!
\internal
*/
void Event::setTimeZone( const QString &z )
{
tz = z;
}
/*!
\internal
*/
void Event::setAlarm( bool b, int minutes, SoundTypeChoice s )
{
hAlarm = b;
aMinutes = minutes;
aSound = s;
}
/*!
\internal
*/
void Event::setRepeat( bool b, const RepeatPattern &p )
{
hRepeat = b;
pattern = p;
}
/*!
Sets the notes for the event to \a n.
*/
void Event::setNotes( const QString &n )
{
note = n;
}
/*!
Returns the description of the event.
*/
const QString &Event::description() const
{
return descript;
}
/*!
Returns the location of the event.
*/
const QString &Event::location() const
{
return locat;
}
// QString Event::category() const
// {
// return categ;
// }
/*!
\internal
*/
Event::Type Event::type() const
{
return typ;
}
/*
QDateTime Event::start() const {
return start( TRUE );
}
*/
/*!
\internal
*/
QDateTime Event::start( bool actual ) const
{
QDateTime dt = TimeConversion::fromUTC( startUTC );
if ( actual && typ == AllDay ) {
QTime t = dt.time();
t.setHMS( 0, 0, 0 );
dt.setTime( t );
}
return dt;
}
/*
QDateTime Event::end() const {
return end( TRUE );
}
*/
/*!
\internal
*/
QDateTime Event::end( bool actual ) const
{
/* small work around... */
if ( actual && typ == AllDay ) {
return QDateTime( TimeConversion::fromUTC( startUTC ).date(), QTime(23, 59, 59 ) );
}
return TimeConversion::fromUTC( endUTC );
}
/*!
\internal
*/
const QString &Event::timeZone() const
{
return tz;
}
/*!
\internal
*/
bool Event::hasAlarm() const
{
return hAlarm;
}
/*!
\internal
*/
int Event::alarmTime() const
{
return aMinutes;
}
/*!
Returns the sound type for the alarm of this event.
*/
Event::SoundTypeChoice Event::alarmSound() const
{
return aSound;
}
/*!
\internal
*/
bool Event::hasRepeat() const
{
return doRepeat();
}
/*!
\internal
*/
const Event::RepeatPattern &Event::repeatPattern() const
{
return pattern;
}
/*!
\internal
*/
Event::RepeatPattern &Event::repeatPattern()
{
return pattern;
}
/*!
Returns the notes for the event.
*/
const QString &Event::notes() const
{
return note;
}
/*!
\internal
*/
bool Event::operator==( const Event &e ) const
{
if ( uid() && e.uid() == uid() )
return TRUE;
return ( e.descript == descript &&
e.locat == locat &&
e.categ == categ &&
e.typ == typ &&
e.startUTC == startUTC &&
e.endUTC == endUTC &&
e.tz == tz &&
e.hAlarm == hAlarm &&
e.aMinutes == aMinutes &&
e.aSound == aSound &&
e.hRepeat == hRepeat &&
e.pattern == pattern &&
e.note == note );
}
/*!
\internal
Appends the contact information to \a buf.
*/
void Event::save( QString& buf )
{
buf += " description=\"" + Qtopia::escapeString(descript) + "\"";
if ( !locat.isEmpty() )
buf += " location=\"" + Qtopia::escapeString(locat) + "\"";
// save the categoies differently....
QString strCats = idsToString( categories() );
buf += " categories=\"" + Qtopia::escapeString(strCats) + "\"";
buf += " uid=\"" + QString::number( uid() ) + "\"";
if ( (Type)typ != Normal )
buf += " type=\"AllDay\"";
if ( hAlarm ) {
buf += " alarm=\"" + QString::number( aMinutes ) + "\" sound=\"";
if ( aSound == Event::Loud )
buf += "loud";
else
buf += "silent";
buf += "\"";
}
if ( hRepeat )
write( buf, pattern );
buf += " start=\""
+ QString::number( startUTC )
+ "\"";
buf += " end=\""
+ QString::number( endUTC )
+ "\"";
if ( !note.isEmpty() )
buf += " note=\"" + Qtopia::escapeString( note ) + "\"";
buf += customToXml();
}
/*!
\internal
*/
bool Event::RepeatPattern::operator==( const Event::RepeatPattern &right ) const
{
// *sigh*
return ( type == right.type
&& frequency == right.frequency
&& position == right.position
&& days == right.days
&& hasEndDate == right.hasEndDate
&& endDateUTC == right.endDateUTC
&& createTime == right.createTime );
}
/*!
\class EffectiveEvent
\brief The EffectiveEvent class the data for a single occurance of an event.
This class describes the event for a single occurance of it. For example if
an Event occurs every week, the effective event might represent the third
occurance of this Event.
\ingroup qtopiaemb
\ingroup qtopiadesktop
\warning This class will be phased out in Qtopia 3.x
*/
/*!
\enum EffectiveEvent::Position
\internal
*/
/*!
\fn EffectiveEvent &EffectiveEvent::operator=(const EffectiveEvent &)
\internal
*/
class EffectiveEventPrivate
{
public:
//currently the existence of the d pointer means multi-day repeating,
//msut be changed if we use the d pointer for anything else.
QDate startDate;
QDate endDate;
};
/*!
\internal
*/
EffectiveEvent::EffectiveEvent()
{
mDate = QDate::currentDate();
mStart = mEnd = QTime::currentTime();
d = 0;
}
/*!
\internal
*/
EffectiveEvent::EffectiveEvent( const Event &e, const QDate &date, Position pos )
{
mEvent = e;
mDate = date;
if ( pos & Start )
mStart = e.start( TRUE ).time();
else
mStart = QTime( 0, 0, 0 );
if ( pos & End )
mEnd = e.end( TRUE ).time();
else
mEnd = QTime( 23, 59, 59 );
d = 0;
}
/*!
\internal
*/
EffectiveEvent::~EffectiveEvent()
{
delete d;
}
/*!
\internal
*/
EffectiveEvent::EffectiveEvent( const EffectiveEvent &e )
{
d = 0;
*this = e;
}
EffectiveEvent& EffectiveEvent::operator=( const EffectiveEvent & e )
{
if ( &e == this )
return *this;
delete d;
if ( e.d ) {
d = new EffectiveEventPrivate;
d->startDate = e.d->startDate;
d->endDate = e.d->endDate;
} else {
d = 0;
}
mEvent = e.mEvent;
mDate = e.mDate;
mStart = e.mStart;
mEnd = e.mEnd;
return *this;
}
// QString EffectiveEvent::category() const
// {
// return mEvent.category();
// }
/*!
Returns the description of the event for this effective event.
*/
const QString &EffectiveEvent::description( ) const
{
return mEvent.description();
}
/*!
\internal
*/
const QString &EffectiveEvent::location( ) const
{
return mEvent.location();
}
/*!
\internal
*/
const QString &EffectiveEvent::notes() const
{
return mEvent.notes();
}
/*!
Returns the event associated with this effective event.
*/
const Event &EffectiveEvent::event() const
{
return mEvent;
}
/*!
\internal
*/
const QTime &EffectiveEvent::end() const
{
return mEnd;
}
/*!
\internal
*/
const QTime &EffectiveEvent::start() const
{
return mStart;
}
/*!
Returns the date the effective event occurs on.
*/
const QDate &EffectiveEvent::date() const
{
return mDate;
}
/*!
\internal
*/
int EffectiveEvent::length() const
{
return (mEnd.hour() * 60 - mStart.hour() * 60)
+ QABS(mStart.minute() - mEnd.minute() );
}
/*!
\internal
*/
void EffectiveEvent::setDate( const QDate &dt )
{
mDate = dt;
}
/*!
\internal
*/
void EffectiveEvent::setStart( const QTime &start )
{
mStart = start;
}
/*!
\internal
*/
void EffectiveEvent::setEnd( const QTime &end )
{
mEnd = end;
}
/*!
\internal
*/
void EffectiveEvent::setEvent( Event e )
{
mEvent = e;
}
/*!
\internal
*/
bool EffectiveEvent::operator<( const EffectiveEvent &e ) const
{
if ( mDate < e.date() )
return TRUE;
if ( mDate == e.date() )
return ( mStart < e.start() );
else
return FALSE;
}
/*!
\internal
*/
bool EffectiveEvent::operator<=( const EffectiveEvent &e ) const
{
return (mDate <= e.date() );
}
/*!
\internal
*/
bool EffectiveEvent::operator==( const EffectiveEvent &e ) const
{
return ( mDate == e.date()
&& mStart == e.start()
&& mEnd == e.end()
&& mEvent == e.event() );
}
/*!
\internal
*/
bool EffectiveEvent::operator!=( const EffectiveEvent &e ) const
{
return !(*this == e);
}
/*!
\internal
*/
bool EffectiveEvent::operator>( const EffectiveEvent &e ) const
{
return !(*this <= e );
}
/*!
\internal
*/
bool EffectiveEvent::operator>=(const EffectiveEvent &e) const
{
return !(*this < e);
}
/*!
\internal
*/
void EffectiveEvent::setEffectiveDates( const QDate &from, const QDate &to )
{
if ( !from.isValid() ) {
delete d;
d = 0;
return;
}
if ( !d )
d = new EffectiveEventPrivate;
d->startDate = from;
d->endDate = to;
}
/*!
\internal
*/
QDate EffectiveEvent::startDate() const
{
if ( d )
return d->startDate;
else if ( mEvent.hasRepeat() )
return mDate; // single day, since multi-day should have a d pointer
else
return mEvent.start().date();
}
/*!
\internal
*/
QDate EffectiveEvent::endDate() const
{
if ( d )
return d->endDate;
else if ( mEvent.hasRepeat() )
return mDate; // single day, since multi-day should have a d pointer
else
return mEvent.end().date();
}
/*!
\internal
*/
int EffectiveEvent::size() const
{
return ( mEnd.hour() - mStart.hour() ) * 3600
+ (mEnd.minute() - mStart.minute() * 60
+ mEnd.second() - mStart.second() );
}
// vcal conversion code
static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value )
{
VObject *ret = 0;
if ( o && !value.isEmpty() )
ret = addPropValue( o, prop, value.latin1() );
return ret;
}
static inline VObject *safeAddProp( VObject *o, const char *prop)
{
VObject *ret = 0;
if ( o )
ret = addProp( o, prop );
return ret;
}
/*
* Until we support vCal/iCal right
* we will make DTSTART and other things
* be floating in the sense of
* RFC 2445
*/
namespace {
/*
* Convert QDateTime to iso8601 but take
* local time and do not use the Z at the end
*
*/
QCString toISOLocal( const QDateTime& dt ) {
QCString str;
/*
* year month day T Hour Minute Second
* 4 2 2 2 2 2 digits
*/
str.sprintf("%04d%02d%02dT%02d%02d%02d",
dt.date().year(),
dt.date().month(),
dt.date().day(),
dt.time().hour(),
dt.time().minute(),
dt.time().second() );
qWarning("Str ist %s", str.data() );
return str;
}
};
static VObject *createVObject( const Event &e )
{
VObject *vcal = newVObject( VCCalProp );
safeAddPropValue( vcal, VCVersionProp, "1.0" );
VObject *event = safeAddProp( vcal, VCEventProp );
safeAddPropValue( event, VCDTstartProp, toISOLocal( e.start() ) );
safeAddPropValue( event, VCDTendProp, toISOLocal( e.end() ) );
safeAddPropValue( event, "X-Qtopia-NOTES", e.description() );
safeAddPropValue( event, VCDescriptionProp, e.description() );
safeAddPropValue( event, VCLocationProp, e.location() );
if ( e.hasAlarm() ) {
VObject *alarm = safeAddProp( event, VCAAlarmProp );
QDateTime dt = e.start();
dt = dt.addSecs( -e.alarmTime()*60 );
safeAddPropValue( alarm, VCRunTimeProp, toISOLocal( dt ) );
safeAddPropValue( alarm, VCAudioContentProp,
(e.alarmSound() == Event::Silent ? "silent" : "alarm" ) );
}
safeAddPropValue( event, "X-Qtopia-TIMEZONE", e.timeZone() );
if ( e.type() == Event::AllDay )
safeAddPropValue( event, "X-Qtopia-AllDay", e.timeZone() );
// ### repeat missing
// ### categories missing
return vcal;
}
static Event parseVObject( VObject *obj )
{
Event e;
bool haveAlarm = FALSE;
bool haveStart = FALSE;
bool haveEnd = FALSE;
QDateTime alarmTime;
Event::SoundTypeChoice soundType = Event::Silent;
VObjectIterator it;
initPropIterator( &it, obj );
while( moreIteration( &it ) ) {
VObject *o = nextVObject( &it );
QCString name = vObjectName( o );
QCString value = vObjectStringZValue( o );
if ( name == VCDTstartProp ) {
e.setStart( TimeConversion::fromISO8601( value ) );
haveStart = TRUE;
}
else if ( name == VCDTendProp ) {
e.setEnd( TimeConversion::fromISO8601( value ) );
haveEnd = TRUE;
}
else if ( name == "X-Qtopia-NOTES" ) {
e.setNotes( value );
}
else if ( name == VCDescriptionProp ) {
e.setDescription( value );
}
else if ( name == VCLocationProp ) {
e.setLocation( value );
}
else if ( name == VCAudioContentProp ) {
haveAlarm = TRUE;
VObjectIterator nit;
initPropIterator( &nit, o );
while( moreIteration( &nit ) ) {
VObject *o = nextVObject( &nit );
QCString name = vObjectName( o );
QCString value = vObjectStringZValue( o );
if ( name == VCRunTimeProp )
alarmTime = TimeConversion::fromISO8601( value );
else if ( name == VCAudioContentProp ) {
if ( value == "silent" )
soundType = Event::Silent;
else
soundType = Event::Loud;
}
}
}
else if ( name == "X-Qtopia-TIMEZONE") {
e.setTimeZone( value );
}
else if ( name == "X-Qtopia-AllDay" ) {
e.setType( Event::AllDay );
}
#if 0
else {
printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
VObjectIterator nit;
initPropIterator( &nit, o );
while( moreIteration( &nit ) ) {
VObject *o = nextVObject( &nit );
QCString name = vObjectName( o );
QString value = vObjectStringZValue( o );
printf(" subprop: %s = %s\n", name.data(), value.latin1() );
}
}
#endif
}
if ( !haveStart && !haveEnd )
e.setStart( QDateTime::currentDateTime() );
if ( !haveEnd ) {
e.setType( Event::AllDay );
e.setEnd( e.start() );
}
if ( haveAlarm ) {
int minutes = alarmTime.secsTo( e.start() ) / 60;
e.setAlarm( TRUE, minutes, soundType );
}
return e;
}
/*!
Writes the list of \a events as a set of VCards to the file \a filename.
*/
void Event::writeVCalendar( const QString &filename, const QValueList<Event> &events)
{
QFileDirect f( filename.utf8().data() );
if ( !f.open( IO_WriteOnly ) ) {
qWarning("Unable to open vcard write");
return;
}
QValueList<Event>::ConstIterator it;
for( it = events.begin(); it != events.end(); ++it ) {
VObject *obj = createVObject( *it );
writeVObject( f.directHandle() , obj );
cleanVObject( obj );
}
cleanStrTbl();
}
/*!
Writes \a event as a VCard to the file \a filename.
*/
void Event::writeVCalendar( const QString &filename, const Event &event)
{
QFileDirect f( filename.utf8().data() );
if ( !f.open( IO_WriteOnly ) ) {
qWarning("Unable to open vcard write");
return;
}
VObject *obj = createVObject( event );
writeVObject( f.directHandle() , obj );
cleanVObject( obj );
cleanStrTbl();
}
/*!
Returns the set of events read as VCards from the file \a filename.
*/
QValueList<Event> Event::readVCalendar( const QString &filename )
{
VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() );
QValueList<Event> events;
while ( obj ) {
QCString name = vObjectName( obj );
if ( name == VCCalProp ) {
VObjectIterator nit;
initPropIterator( &nit, obj );
while( moreIteration( &nit ) ) {
VObject *o = nextVObject( &nit );
QCString name = vObjectName( o );
if ( name == VCEventProp )
events.append( parseVObject( o ) );
}
} else if ( name == VCEventProp ) {
// shouldn't happen, but just to be sure
events.append( parseVObject( obj ) );
}
VObject *t = obj;
obj = nextVObjectInList(obj);
cleanVObject( t );
}
return events;
}
bool Event::match( const QRegExp &r ) const
{
bool returnMe;
returnMe = false;
if ( descript.find( r ) > -1 )
returnMe = true;
else if ( locat.find( r ) > -1 )
returnMe = true;
else if ( TimeConversion::fromUTC( startUTC ).toString().find( r ) > -1 )
returnMe = true;
else if ( TimeConversion::fromUTC( endUTC ).toString().find( r ) > -1 )
returnMe = true;
else if ( tz.find( r ) > -1 )
returnMe = true;
else if ( note.find( r ) > -1 )
returnMe = true;
else if ( doRepeat() ) {
if ( pattern.hasEndDate )
if ( TimeConversion::fromUTC( pattern.endDateUTC ).toString().find(r) > -1 )
returnMe = true;
}
return returnMe;
}
diff --git a/library/backend/palmtoprecord.h b/library/backend/palmtoprecord.h
index 72f7d1c..15cdd6a 100644
--- a/library/backend/palmtoprecord.h
+++ b/library/backend/palmtoprecord.h
@@ -1,95 +1,107 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of the 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.
**
**********************************************************************/
#ifndef QTPALMTOP_RECORD_H
#define QTPALMTOP_RECORD_H
#include <qglobal.h>
#include "qpcglobal.h"
#include "palmtopuidgen.h"
#include <qarray.h>
#include <qmap.h>
#if defined(QPC_TEMPLATEDLL)
// MOC_SKIP_BEGIN
QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<QString, QString>;
// MOC_SKIP_END
#endif
class QRegExp;
+/**
+ * @short Qtopia namespace
+ * The namespace of Qtopia
+ */
namespace Qtopia {
class RecordPrivate;
+/**
+ * @short The base class of all Records
+ *
+ * The base class for Records in Qtopia
+ * @see Task
+ * @see Event
+ * @see Contact
+ */
class QPC_EXPORT Record
{
public:
Record() : mUid(0), mCats() { }
Record( const Record &c ) : mUid( c.mUid ), mCats ( c.mCats ), customMap(c.customMap) { }
virtual ~Record() { }
Record &operator=( const Record &c );
virtual bool match( const QRegExp & ) const { return FALSE; }
void setCategories( const QArray<int> &v ) { mCats = v; mCats.sort(); }
void setCategories( int single );
const QArray<int> &categories() const { return mCats; }
void reassignCategoryId( int oldId, int newId )
{
int index = mCats.find( oldId );
if ( index >= 0 )
mCats[index] = newId;
}
int uid() const { return mUid; };
virtual void setUid( int i ) { mUid = i; uidGen().store( mUid ); }
bool isValidUid() const { return mUid != 0; }
void assignUid() { setUid( uidGen().generate() ); }
virtual QString customField(const QString &) const;
virtual void setCustomField(const QString &, const QString &);
virtual void removeCustomField(const QString &);
virtual bool operator == ( const Record &r ) const
{ return mUid == r.mUid; }
virtual bool operator != ( const Record &r ) const
{ return mUid != r.mUid; }
// convenience methods provided for loading and saving to xml
static QString idsToString( const QArray<int> &ids );
// convenience methods provided for loading and saving to xml
static QArray<int> idsFromString( const QString &str );
// for debugging
static void dump( const QMap<int, QString> &map );
protected:
virtual UidGen &uidGen() = 0;
virtual QString customToXml() const;
private:
int mUid;
QArray<int> mCats;
QMap<QString, QString> customMap;
RecordPrivate *d;
};
}
#endif