summaryrefslogtreecommitdiff
path: root/library/backend/categories.cpp
Unidiff
Diffstat (limited to 'library/backend/categories.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/backend/categories.cpp327
1 files changed, 293 insertions, 34 deletions
diff --git a/library/backend/categories.cpp b/library/backend/categories.cpp
index 6e011c4..e37b3b9 100644
--- a/library/backend/categories.cpp
+++ b/library/backend/categories.cpp
@@ -1,218 +1,296 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of the Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free 7** GNU General Public License version 2 as published by the Free Software
8** Software Foundation and appearing in the file LICENSE.GPL included 8** Foundation and appearing in the file LICENSE.GPL included in the
9** in the packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** PARTICULAR PURPOSE.
14** 13**
15** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
16** 15**
17** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you. 17** not clear to you.
19** 18**
20**********************************************************************/ 19**********************************************************************/
21#include "categories.h" 20#include <qtopia/categories.h>
21#include <qtopia/stringutil.h>
22#include <qfile.h> 22#include <qfile.h>
23#include <qcstring.h> 23#include <qcstring.h>
24#include <qtextstream.h> 24#include <qtextstream.h>
25#include "stringutil.h"
26 25
27using namespace Qtopia; 26using namespace Qtopia;
28 27
29/*********************************************************** 28/***********************************************************
30 * 29 *
31 * CategoryGroup 30 * CategoryGroup
32 * 31 *
33 **********************************************************/ 32 **********************************************************/
34 33
35#ifdef PALMTOPCENTER 34#ifdef PALMTOPCENTER
36UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter ); 35UidGen CategoryGroup::sUidGen( UidGen::PalmtopCenter );
37#else 36#else
38UidGen CategoryGroup::sUidGen( UidGen::Qtopia ); 37UidGen CategoryGroup::sUidGen( UidGen::Qtopia );
39#endif 38#endif
40 39
40/*! \class CategoryGroup categories.h
41 \brief Helper class that is used by Categories
42
43 CategoryGroup is a group of categories that is associated with an
44 application or global set. Mainly it defines a map of ids to
45 category labels and category labels to ids. Lookups can be done with
46 labels or unique idenifiers.
47
48 \ingroup qtopiaemb
49 \ingroup qtopiadesktop
50 \warning Categories API will likely change between Qtopia 1.5 and Qtopia 3
51 \sa Categories::appGroupMap(), Categories::globalGroup()
52 */
53
54/*! Add \a label and return the UID. If failure, then 0 is returned. Note
55 that All and Unfiled are reserved labels.
56 \internal
57*/
41int CategoryGroup::add( const QString &label ) 58int CategoryGroup::add( const QString &label )
42{ 59{
43 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) 60 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
44 return 0; 61 return 0;
45 62
46 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label ); 63 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
47 if ( findIt != mLabelIdMap.end() ) 64 if ( findIt != mLabelIdMap.end() )
48 return 0; 65 return 0;
49 int newUid = uidGen().generate(); 66 int newUid = uidGen().generate();
50 insert( newUid, label ); 67 insert( newUid, label );
51 return newUid; 68 return newUid;
52} 69}
53 70
54void CategoryGroup::insert( int uid, const QString &label ) 71void CategoryGroup::insert( int uid, const QString &label )
55{ 72{
56 uidGen().store( uid ); 73 uidGen().store( uid );
57 mIdLabelMap[uid] = label; 74 mIdLabelMap[uid] = label;
58 mLabelIdMap[label] = uid; 75 mLabelIdMap[label] = uid;
59} 76}
60 77
78/*! \internal
79 */
61bool CategoryGroup::add( int uid, const QString &label ) 80bool CategoryGroup::add( int uid, const QString &label )
62{ 81{
63 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") ) 82 if ( label == QObject::tr("All") || label == QObject::tr("Unfiled") )
64 return FALSE; 83 return FALSE;
65 84
66 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label ); 85 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
67 if ( labelIt != mLabelIdMap.end() ) 86 if ( labelIt != mLabelIdMap.end() )
68 return FALSE; 87 return FALSE;
69 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid ); 88 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
70 if ( idIt != mIdLabelMap.end() ) 89 if ( idIt != mIdLabelMap.end() )
71 return FALSE; 90 return FALSE;
72 insert( uid, label ); 91 insert( uid, label );
73 return TRUE; 92 return TRUE;
74} 93}
75 94
95/*! Returns TRUE if \a label was removed from the group, FALSE if not.
96 \internal
97 */
76bool CategoryGroup::remove( const QString &label ) 98bool CategoryGroup::remove( const QString &label )
77{ 99{
78 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label ); 100 QMap<QString,int>::Iterator findIt = mLabelIdMap.find( label );
79 if ( findIt == mLabelIdMap.end() ) 101 if ( findIt == mLabelIdMap.end() )
80 return FALSE; 102 return FALSE;
81 103
82 mIdLabelMap.remove( *findIt ); 104 mIdLabelMap.remove( *findIt );
83 mLabelIdMap.remove( findIt ); 105 mLabelIdMap.remove( findIt );
84 106
85 return TRUE; 107 return TRUE;
86} 108}
87 109
110/*! Returns TRUE if \a uid was removed from the group, FALSE if not.
111 \internal
112 */
88bool CategoryGroup::remove( int uid ) 113bool CategoryGroup::remove( int uid )
89{ 114{
90 QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid ); 115 QMap<int,QString>::Iterator idIt = mIdLabelMap.find( uid );
91 if ( idIt == mIdLabelMap.end() ) 116 if ( idIt == mIdLabelMap.end() )
92 return FALSE; 117 return FALSE;
93 118
94 mLabelIdMap.remove( *idIt ); 119 mLabelIdMap.remove( *idIt );
95 mIdLabelMap.remove( idIt ); 120 mIdLabelMap.remove( idIt );
96 121
97 return TRUE; 122 return TRUE;
98} 123}
99 124
125/*! \internal
126 */
100bool CategoryGroup::rename( int uid, const QString &newLabel ) 127bool CategoryGroup::rename( int uid, const QString &newLabel )
101{ 128{
102 if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") ) 129 if ( newLabel == QObject::tr("All") || newLabel == QObject::tr("Unfiled") )
103 return FALSE; 130 return FALSE;
104 131
105 QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid ); 132 QMap<int, QString>::Iterator idIt = mIdLabelMap.find( uid );
106 if ( idIt == mIdLabelMap.end() ) 133 if ( idIt == mIdLabelMap.end() )
107 return FALSE; 134 return FALSE;
108 135
109 mLabelIdMap.remove( *idIt ); 136 mLabelIdMap.remove( *idIt );
110 mLabelIdMap[newLabel] = uid; 137 mLabelIdMap[newLabel] = uid;
111 *idIt = newLabel; 138 *idIt = newLabel;
112 139
113 return TRUE; 140 return TRUE;
114} 141}
115 142
143/*! \internal
144 */
116bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel ) 145bool CategoryGroup::rename( const QString &oldLabel, const QString &newLabel )
117{ 146{
118 return rename( id(oldLabel), newLabel ); 147 return rename( id(oldLabel), newLabel );
119} 148}
120 149
150/*! Returns TRUE if \a uid is stored in this group, FALSE if not. */
121bool CategoryGroup::contains(int uid) const 151bool CategoryGroup::contains(int uid) const
122{ 152{
123 return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() ); 153 return ( mIdLabelMap.find( uid ) != mIdLabelMap.end() );
124} 154}
125 155
156/*! Returns TRUE if \a label is stored in this group, FALSE if not. */
126bool CategoryGroup::contains(const QString &label) const 157bool CategoryGroup::contains(const QString &label) const
127{ 158{
128 return ( mLabelIdMap.find( label ) != mLabelIdMap.end() ); 159 return ( mLabelIdMap.find( label ) != mLabelIdMap.end() );
129} 160}
130 161
131/** Returns label associated with the uid or QString::null if 162/*! Returns label associated with the \a uid or QString::null if
132 * not found 163 not found
133 */ 164 */
134const QString &CategoryGroup::label(int uid) const 165const QString &CategoryGroup::label(int uid) const
135{ 166{
136 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid ); 167 QMap<int,QString>::ConstIterator idIt = mIdLabelMap.find( uid );
137 if ( idIt == mIdLabelMap.end() ) 168 if ( idIt == mIdLabelMap.end() )
138 return QString::null; 169 return QString::null;
139 return *idIt; 170 return *idIt;
140} 171}
141 172
142/** Returns the uid associated with label or 0 if not found */ 173/*! Returns the uid associated with \a label or 0 if not found */
143int CategoryGroup::id(const QString &label) const 174int CategoryGroup::id(const QString &label) const
144{ 175{
145 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label ); 176 QMap<QString,int>::ConstIterator labelIt = mLabelIdMap.find( label );
146 if ( labelIt == mLabelIdMap.end() ) 177 if ( labelIt == mLabelIdMap.end() )
147 return 0; 178 return 0;
148 return *labelIt; 179 return *labelIt;
149} 180}
150 181
182/*! Returns a list of all labels stored in this group. */
151QStringList CategoryGroup::labels() const 183QStringList CategoryGroup::labels() const
152{ 184{
153 QStringList labels; 185 QStringList labels;
154 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin(); 186 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
155 it != mIdLabelMap.end(); ++it ) 187 it != mIdLabelMap.end(); ++it )
156 labels += *it; 188 labels += *it;
157 // ### I don't think this is the place for this... 189 // ### I don't think this is the place for this...
158// labels.sort(); 190// labels.sort();
159 return labels; 191 return labels;
160} 192}
161 193
194/*! Returns a list of all labels associated with the \a catids */
162QStringList CategoryGroup::labels(const QArray<int> &catids ) const 195QStringList CategoryGroup::labels(const QArray<int> &catids ) const
163{ 196{
164 QStringList labels; 197 QStringList labels;
165 if ( catids.count() == 0 ) 198 if ( catids.count() == 0 )
166 return labels; 199 return labels;
167 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin(); 200 for ( QMap<int, QString>::ConstIterator it = mIdLabelMap.begin();
168 it != mIdLabelMap.end(); ++it ) 201 it != mIdLabelMap.end(); ++it )
169 if ( catids.find( it.key() ) != -1 ) 202 if ( catids.find( it.key() ) != -1 )
170 labels += *it; 203 labels += *it;
171 return labels; 204 return labels;
172} 205}
173 206
174/*********************************************************** 207/***********************************************************
175 * 208 *
176 * Categories 209 * Categories
177 * 210 *
178 **********************************************************/ 211 **********************************************************/
179 212
180/** Add the category name as long as it doesn't already exist locally 213/*!
181 * or globally. Return TRUE if added, FALSE if conflicts. 214 \class Categories categories.h
182 */ 215 \brief The Categories class is a database that groups categories and maps ids to names.
216
217 The Categories class is the low level Categories accessor class. To
218 add a category menu and filter for your application, see CategoryMenu.
219
220 The Categories class allows the developer to add, remove, and rename
221 categories. Categories can be created for an individual application
222 such as Todo List or to be used for all applications. Categories
223 that can be used by all applications are called global
224 categories. Each PalmtopRecord subclass stores categories as an
225 QArray<int> using PalmtopRecord::setCategories() and
226 PalmtopRecord::categories(). This allows each record to be assigned
227 to multiple categories. This also allows the user to rename a
228 category and for it to update automatically in all records.
229
230 This class provides several methods to convert between a category id
231 and it's associated string such as id(), ids(), label() and labels(). A
232 helper class called CategoryGroup is used to access categories of a
233 single application group, such as Todo List. Global categories can
234 also be accessed via CategoryGroup objects. See appGroupMap() and
235 globalGroup() for the appropriate accessor methods.
236
237 Categories are stored in an xml file in the Settings directory
238 (Categories.xml). A global function called categoryFileName() will
239 return to appropriate QString file location to be passed to load()
240 and save() for the master categories database.
241
242 \ingroup qtopiaemb
243 \ingroup qtopiadesktop
244 \warning Categories API will likely change between Qtopia 1.5 and Qtopia 3
245 \sa CategoryGroup, CategoryMenu
246*/
247
248
249/*!
250 Add the category name as long as it doesn't already exist locally or
251 globally. The \a uid is assigned to the category if successfully
252 added. Return \a uid if added, 0 if conflicts (error).
253
254 \internal
255*/
183int Categories::addCategory( const QString &appname, 256int Categories::addCategory( const QString &appname,
184 const QString &catname, 257 const QString &catname,
185 int uid ) 258 int uid )
186{ 259{
187 if ( mGlobalCats.contains(catname) ) 260 if ( mGlobalCats.contains(catname) )
188 return 0; 261 return 0;
189 262
190 QMap< QString, CategoryGroup >::Iterator 263 QMap< QString, CategoryGroup >::Iterator
191 appIt = mAppCats.find( appname ); 264 appIt = mAppCats.find( appname );
192 265
193 if ( appIt == mAppCats.end() ) { 266 if ( appIt == mAppCats.end() ) {
194 CategoryGroup newgroup; 267 CategoryGroup newgroup;
195 newgroup.add( uid, catname ); 268 newgroup.add( uid, catname );
196 mAppCats.insert( appname, newgroup ); 269 mAppCats.insert( appname, newgroup );
197 emit categoryAdded( *this, appname, uid ); 270 emit categoryAdded( *this, appname, uid );
198 return uid; 271 return uid;
199 } 272 }
200 273
201 CategoryGroup &cats = *appIt; 274 CategoryGroup &cats = *appIt;
202 cats.add( uid, catname ); 275 cats.add( uid, catname );
203 emit categoryAdded( *this, appname, uid ); 276 emit categoryAdded( *this, appname, uid );
204 return uid; 277 return uid;
205} 278}
206 279
280/*!
281 Add the category name as long as it doesn't already exist locally or
282 globally. Return UID if added, 0 if conflicts (error).
283*/
284
207int Categories::addCategory( const QString &appname, 285int Categories::addCategory( const QString &appname,
208 const QString &catname ) 286 const QString &catname )
209{ 287{
210 if ( mGlobalCats.contains(catname) ) 288 if ( mGlobalCats.contains(catname) )
211 return 0; 289 return 0;
212 290
213 QMap< QString, CategoryGroup >::Iterator 291 QMap< QString, CategoryGroup >::Iterator
214 appIt = mAppCats.find( appname ); 292 appIt = mAppCats.find( appname );
215 293
216 if ( appIt == mAppCats.end() ) { 294 if ( appIt == mAppCats.end() ) {
217 CategoryGroup newgroup; 295 CategoryGroup newgroup;
218 int uid = newgroup.add( catname ); 296 int uid = newgroup.add( catname );
@@ -220,149 +298,182 @@ int Categories::addCategory( const QString &appname,
220 emit categoryAdded( *this, appname, uid ); 298 emit categoryAdded( *this, appname, uid );
221 return uid; 299 return uid;
222 } 300 }
223 301
224 CategoryGroup &cats = *appIt; 302 CategoryGroup &cats = *appIt;
225 int uid = cats.add( catname ); 303 int uid = cats.add( catname );
226 if ( !uid ) 304 if ( !uid )
227 return 0; 305 return 0;
228 emit categoryAdded( *this, appname, uid ); 306 emit categoryAdded( *this, appname, uid );
229 return uid; 307 return uid;
230} 308}
231 309
310/*!
311 \internal
312*/
232int Categories::addGlobalCategory( const QString &catname, int uid ) 313int Categories::addGlobalCategory( const QString &catname, int uid )
233{ 314{
234 mGlobalCats.add( uid, catname ); 315 mGlobalCats.add( uid, catname );
235 emit categoryAdded( *this, QString::null, uid ); 316 emit categoryAdded( *this, QString::null, uid );
236 return uid; 317 return uid;
237} 318}
238 319
320/*!
321 Add the global category \a catname while checking that it doesn't
322 already exist globally. Return UID if added, 0 if conflicts.
323
324 \sa addCategory()
325 */
239int Categories::addGlobalCategory( const QString &catname ) 326int Categories::addGlobalCategory( const QString &catname )
240{ 327{
241 int uid = mGlobalCats.add( catname ); 328 int uid = mGlobalCats.add( catname );
242 if ( !uid ) 329 if ( !uid )
243 return 0; 330 return 0;
244 emit categoryAdded( *this, QString::null, uid ); 331 emit categoryAdded( *this, QString::null, uid );
245 return uid; 332 return uid;
246} 333}
247 334
248/** Removes the category from the application; if it is not found 335/*!
249 * in the application, then it attempts to remove it from 336
250 * the global list 337 Removes the \a catname from the application group. If it is not
251 */ 338 found in the application group and \a checkGlobal is TRUE, then it
339 attempts to remove it from the global list
340*/
252bool Categories::removeCategory( const QString &appname, 341bool Categories::removeCategory( const QString &appname,
253 const QString &catname, 342 const QString &catname,
254 bool checkGlobal ) 343 bool checkGlobal )
255{ 344{
256 QMap< QString, CategoryGroup >::Iterator 345 QMap< QString, CategoryGroup >::Iterator
257 appIt = mAppCats.find( appname ); 346 appIt = mAppCats.find( appname );
258 if ( appIt != mAppCats.end() ) { 347 if ( appIt != mAppCats.end() ) {
259 CategoryGroup &cats = *appIt; 348 CategoryGroup &cats = *appIt;
260 int uid = cats.id( catname ); 349 int uid = cats.id( catname );
261 if ( cats.remove( uid ) ) { 350 if ( cats.remove( uid ) ) {
262 emit categoryRemoved( *this, appname, uid ); 351 emit categoryRemoved( *this, appname, uid );
263 return TRUE; 352 return TRUE;
264 } 353 }
265 } 354 }
266 if ( !checkGlobal ) 355 if ( !checkGlobal )
267 return FALSE; 356 return FALSE;
268 return removeGlobalCategory( catname ); 357 return removeGlobalCategory( catname );
269} 358}
270 359
360
361/*!
362 Removes the \a uid from the application group \a appname. Returns TRUE
363 if success, FALSE if not found.
364*/
271bool Categories::removeCategory( const QString &appname, int uid ) 365bool Categories::removeCategory( const QString &appname, int uid )
272{ 366{
273 QMap< QString, CategoryGroup >::Iterator 367 QMap< QString, CategoryGroup >::Iterator
274 appIt = mAppCats.find( appname ); 368 appIt = mAppCats.find( appname );
275 if ( appIt != mAppCats.end() ) { 369 if ( appIt != mAppCats.end() ) {
276 CategoryGroup &cats = *appIt; 370 CategoryGroup &cats = *appIt;
277 if ( cats.remove( uid ) ) { 371 if ( cats.remove( uid ) ) {
278 emit categoryRemoved( *this, appname, uid ); 372 emit categoryRemoved( *this, appname, uid );
279 return TRUE; 373 return TRUE;
280 } 374 }
281 } 375 }
282 return FALSE; 376 return FALSE;
283} 377}
284 378
379/*!
380 Removes the global category \a catname. Returns TRUE
381 if success, FALSE if not found.
382*/
285bool Categories::removeGlobalCategory( const QString &catname ) 383bool Categories::removeGlobalCategory( const QString &catname )
286{ 384{
287 int uid = mGlobalCats.id( catname ); 385 int uid = mGlobalCats.id( catname );
288 if ( mGlobalCats.remove( uid ) ) { 386 if ( mGlobalCats.remove( uid ) ) {
289 emit categoryRemoved( *this, QString::null, uid ); 387 emit categoryRemoved( *this, QString::null, uid );
290 return TRUE; 388 return TRUE;
291 } 389 }
292 return FALSE; 390 return FALSE;
293} 391}
294 392
295 393/*!
394 Removes the global category \a uid. Returns TRUE
395 if success, FALSE if not found.
396*/
296bool Categories::removeGlobalCategory( int uid ) 397bool Categories::removeGlobalCategory( int uid )
297{ 398{
298 if ( mGlobalCats.remove( uid ) ) { 399 if ( mGlobalCats.remove( uid ) ) {
299 emit categoryRemoved( *this, QString::null, uid ); 400 emit categoryRemoved( *this, QString::null, uid );
300 return TRUE; 401 return TRUE;
301 } 402 }
302 return FALSE; 403 return FALSE;
303} 404}
304 405
305/** Returns the sorted list of all categories that are associated with 406/*!
306 * the app. If includeGlobal parameter is TRUE then the returned 407 Returns the sorted list of all categories that are associated with
307 * categories will include the global category items. 408 the \a app. If \a includeGlobal is TRUE then the returned
409 categories will include the global category items.
308 */ 410 */
309QStringList Categories::labels( const QString &app, 411QStringList Categories::labels( const QString &app,
310 bool includeGlobal, 412 bool includeGlobal,
311 ExtraLabels extra ) const 413 ExtraLabels extra ) const
312{ 414{
313 QMap< QString, CategoryGroup >::ConstIterator 415 QMap< QString, CategoryGroup >::ConstIterator
314 appIt = mAppCats.find( app ); 416 appIt = mAppCats.find( app );
315 QStringList cats; 417 QStringList cats;
316 418
317 if ( appIt != mAppCats.end() ) 419 if ( appIt != mAppCats.end() )
318 cats += (*appIt).labels(); 420 cats += (*appIt).labels();
319 else qDebug("Categories::labels didn't find app %s", app.latin1() ); 421 //else qDebug("Categories::labels didn't find app %s", app.latin1() );
320 if ( includeGlobal ) 422 if ( includeGlobal )
321 cats += mGlobalCats.labels(); 423 cats += mGlobalCats.labels();
322 424
323 cats.sort(); 425 cats.sort();
324 switch ( extra ) { 426 switch ( extra ) {
325 case NoExtra: break; 427 case NoExtra: break;
326 case AllUnfiled: 428 case AllUnfiled:
327 cats.append( tr("All") ); 429 cats.append( tr("All") );
328 cats.append( tr("Unfiled") ); 430 cats.append( tr("Unfiled") );
329 break; 431 break;
330 case AllLabel: 432 case AllLabel:
331 cats.append( tr("All") ); 433 cats.append( tr("All") );
332 break; 434 break;
333 case UnfiledLabel: 435 case UnfiledLabel:
334 cats.append( tr("Unfiled") ); 436 cats.append( tr("Unfiled") );
335 break; 437 break;
336 } 438 }
337 439
338 return cats; 440 return cats;
339} 441}
340 442
443/*!
444 Returns the label associated with the id
445*/
341QString Categories::label( const QString &app, int id ) const 446QString Categories::label( const QString &app, int id ) const
342{ 447{
343 if ( mGlobalCats.contains( id ) ) 448 if ( mGlobalCats.contains( id ) )
344 return mGlobalCats.label( id ); 449 return mGlobalCats.label( id );
345 QMap< QString, CategoryGroup >::ConstIterator 450 QMap< QString, CategoryGroup >::ConstIterator
346 appIt = mAppCats.find( app ); 451 appIt = mAppCats.find( app );
347 if ( appIt == mAppCats.end() ) 452 if ( appIt == mAppCats.end() )
348 return QString::null; 453 return QString::null;
349 return (*appIt).label( id ); 454 return (*appIt).label( id );
350} 455}
351 456
352/** Returns a single string associated with the cat ids for display in 457/*!
353 * a combobox or any area that requires one string. If catids are empty 458 Returns a single string associated with \a catids for display in a
354 * then "Unfiled" will be returned. If multiple categories are assigned 459 combobox or any area that requires one string. If \a catids are empty
355 * the first cat id is shown with " (multi)" appended to the string. 460 then "Unfiled" will be returned. If multiple categories are
356 */ 461 assigned then the behavior depends on the DisplaySingle type.
462
463 If \a display is set to ShowMulti then " (multi)" appended to the
464 first string. If \a display is set to ShowAll, then a space
465 seperated string is returned with all categories. If ShowFirst is
466 set, the just the first string is returned.
467*/
357QString Categories::displaySingle( const QString &app, 468QString Categories::displaySingle( const QString &app,
358 const QArray<int> &catids, 469 const QArray<int> &catids,
359 DisplaySingle display ) const 470 DisplaySingle display ) const
360{ 471{
361 QStringList strs = labels( app, catids ); 472 QStringList strs = labels( app, catids );
362 if ( !strs.count() ) 473 if ( !strs.count() )
363 return tr("Unfiled"); 474 return tr("Unfiled");
364 strs.sort(); 475 strs.sort();
365 QString r; 476 QString r;
366 if ( strs.count() > 1 ) { 477 if ( strs.count() > 1 ) {
367 switch ( display ) { 478 switch ( display ) {
368 case ShowFirst: 479 case ShowFirst:
@@ -371,135 +482,174 @@ QString Categories::displaySingle( const QString &app,
371 case ShowMulti: 482 case ShowMulti:
372 r = strs.first() + tr(" (multi.)"); 483 r = strs.first() + tr(" (multi.)");
373 break; 484 break;
374 case ShowAll: 485 case ShowAll:
375 r = strs.join(" "); 486 r = strs.join(" ");
376 break; 487 break;
377 } 488 }
378 } 489 }
379 else r = strs.first(); 490 else r = strs.first();
380 return r; 491 return r;
381} 492}
382 493
494/*!
495
496 Returns all ids associated with the application CategoryGroup \a app
497 and the passed in \a labels in that group.
498*/
383QArray<int> Categories::ids( const QString &app, const QStringList &labels) const 499QArray<int> Categories::ids( const QString &app, const QStringList &labels) const
384{ 500{
385 QArray<int> results; 501 QArray<int> results;
386 QStringList::ConstIterator it; 502 QStringList::ConstIterator it;
387 int i; 503 int i;
388 504
389 for ( i=0, it=labels.begin(); it!=labels.end(); i++, ++it ) { 505 for ( i=0, it=labels.begin(); it!=labels.end(); i++, ++it ) {
390 int value = id( app, *it ); 506 int value = id( app, *it );
391 if ( value != 0 ) { 507 if ( value != 0 ) {
392 int tmp = results.size(); 508 int tmp = results.size();
393 results.resize( tmp + 1 ); 509 results.resize( tmp + 1 );
394 results[ tmp ] = value; 510 results[ tmp ] = value;
395 } 511 }
396 } 512 }
397 return results; 513 return results;
398} 514}
399 515
516/*!
517 Returns the id associated with the app. If the id is not found in the
518 application CategoryGroup, then it searches the global CategoryGroup.
519 If it is not found it either, 0 is returned.
520*/
400int Categories::id( const QString &app, const QString &cat ) const 521int Categories::id( const QString &app, const QString &cat ) const
401{ 522{
402 if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) ) 523 if ( cat == tr("Unfiled") || cat.contains( tr(" (multi.)") ) )
403 return 0; 524 return 0;
404 int uid = mGlobalCats.id( cat ); 525 int uid = mGlobalCats.id( cat );
405 if ( uid != 0 ) 526 if ( uid != 0 )
406 return uid; 527 return uid;
407 return mAppCats[app].id( cat ); 528 return mAppCats[app].id( cat );
408} 529}
409 530
410 531
411/** Return TRUE if renaming succeeded; FALSE if app name not found, 532/*!
412 * or if there was a name conflict 533 Return TRUE if renaming succeeded; FALSE if \a appname or \a oldName
534 is not found, or if \a newName conflicts with an existing category
535 in the CategoryGroup.
536
537 It will first search the CategoryGroup associated with \a appname
538 and if not found it will try to replace in global CategoryGroup.
413 */ 539 */
414bool Categories::renameCategory( const QString &appname, 540bool Categories::renameCategory( const QString &appname,
415 const QString &oldName, 541 const QString &oldName,
416 const QString &newName ) 542 const QString &newName )
417{ 543{
418 QMap< QString, CategoryGroup >::Iterator 544 QMap< QString, CategoryGroup >::Iterator
419 appIt = mAppCats.find( appname ); 545 appIt = mAppCats.find( appname );
420 546
421 if ( appIt != mAppCats.end() ) { 547 if ( appIt != mAppCats.end() ) {
422 CategoryGroup &cats = *appIt; 548 CategoryGroup &cats = *appIt;
423 int id = cats.id( oldName ); 549 int id = cats.id( oldName );
424 if ( id != 0 && cats.rename( id, newName ) ) { 550 if ( id != 0 && cats.rename( id, newName ) ) {
425 emit categoryRenamed( *this, appname, id ); 551 emit categoryRenamed( *this, appname, id );
426 return TRUE; 552 return TRUE;
427 } 553 }
428 } 554 }
429 return renameGlobalCategory( oldName, newName ); 555 return renameGlobalCategory( oldName, newName );
430} 556}
431 557
558/*!
559 Return TRUE if renaming succeeded; FALSE if \a appname or \a oldName
560 is not found, or if \a newName conflicts with an existing category
561 in the CategoryGroup. This function will only rename categories found
562 in the global CategoryGroup.
563 */
432bool Categories::renameGlobalCategory( const QString &oldName, 564bool Categories::renameGlobalCategory( const QString &oldName,
433 const QString &newName ) 565 const QString &newName )
434{ 566{
435 int uid = mGlobalCats.id( oldName ); 567 int uid = mGlobalCats.id( oldName );
436 if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) { 568 if ( uid != 0 && mGlobalCats.rename( uid, newName ) ) {
437 emit categoryRenamed( *this, QString::null, uid ); 569 emit categoryRenamed( *this, QString::null, uid );
438 return TRUE; 570 return TRUE;
439 } 571 }
440 return FALSE; 572 return FALSE;
441} 573}
442 574
575/*!
576 Changes the grouping of a category. If a category was global and \a global
577 is set to TRUE, then the \a catname will be moved to the \a appname group.
578*/
443void Categories::setGlobal( const QString &appname, 579void Categories::setGlobal( const QString &appname,
444 const QString &catname, 580 const QString &catname,
445 bool global ) 581 bool global )
446{ 582{
447 // if in global and should be in app; then move it 583 // if in global and should be in app; then move it
448 if ( mGlobalCats.contains( catname ) && !global ) { 584 if ( mGlobalCats.contains( catname ) && !global ) {
449 mGlobalCats.remove( catname ); 585 mGlobalCats.remove( catname );
450 addCategory( appname, catname ); 586 addCategory( appname, catname );
451 return ; 587 return ;
452 } 588 }
453 589
454 // if in app and should be in global, then move it 590 // if in app and should be in global, then move it
455 if ( !global ) 591 if ( !global )
456 return; 592 return;
457 if ( removeCategory( appname, catname, FALSE ) ) 593 if ( removeCategory( appname, catname, FALSE ) )
458 addGlobalCategory( catname ); 594 addGlobalCategory( catname );
459} 595}
460 596
597/*!
598 Returns TRUE if the \a catname is in the global CategoryGroup, FALSE if not.
599*/
461bool Categories::isGlobal( const QString &catname ) const 600bool Categories::isGlobal( const QString &catname ) const
462{ 601{
463 return mGlobalCats.contains( catname ); 602 return mGlobalCats.contains( catname );
464} 603}
465 604
466 605
467/** Returns true if the catname is associated with any application 606/*!
607 Returns true if the \a catname is associated with any CategoryGroup,
608 including global.
468 */ 609 */
469bool Categories::exists( const QString &catname ) const 610bool Categories::exists( const QString &catname ) const
470{ 611{
471 if ( isGlobal(catname) ) 612 if ( isGlobal(catname) )
472 return TRUE; 613 return TRUE;
473 614
474 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) 615 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt )
475 if ( exists( appsIt.key(), catname ) ) 616 if ( exists( appsIt.key(), catname ) )
476 return TRUE; 617 return TRUE;
477 618
478 return FALSE; 619 return FALSE;
479} 620}
480 621
622/*!
623 Returns TRUE if the \a catname is associated with the \a appname
624 CategoryGroup, FALSE if not found.
625 */
481bool Categories::exists( const QString &appname, 626bool Categories::exists( const QString &appname,
482 const QString &catname) const 627 const QString &catname) const
483{ 628{
484 QMap< QString, CategoryGroup >::ConstIterator 629 QMap< QString, CategoryGroup >::ConstIterator
485 appIt = mAppCats.find( appname ); 630 appIt = mAppCats.find( appname );
486 631
487 if ( appIt == mAppCats.end() ) 632 if ( appIt == mAppCats.end() )
488 return FALSE; 633 return FALSE;
489 634
490 return (*appIt).contains( catname ); 635 return (*appIt).contains( catname );
491} 636}
492 637
638/*!
639 Saves the Categories database to the \a fname. See categoryFileName()
640 for the default file name string used for the shared category database.
493 641
642 Returns FALSE if there is error writing the file or TRUE on success.
643 */
494bool Categories::save( const QString &fname ) const 644bool Categories::save( const QString &fname ) const
495{ 645{
496 QString strNewFile = fname + ".new"; 646 QString strNewFile = fname + ".new";
497 QFile f( strNewFile ); 647 QFile f( strNewFile );
498 QString out; 648 QString out;
499 int total_written; 649 int total_written;
500 650
501 if ( !f.open( IO_WriteOnly|IO_Raw ) ) { 651 if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
502 qWarning("Unable to write to %s", fname.latin1()); 652 qWarning("Unable to write to %s", fname.latin1());
503 return FALSE; 653 return FALSE;
504 } 654 }
505 655
@@ -525,34 +675,43 @@ bool Categories::save( const QString &fname ) const
525 } 675 }
526 out += "</Categories>\n"; 676 out += "</Categories>\n";
527 677
528 QCString cstr = out.utf8(); 678 QCString cstr = out.utf8();
529 total_written = f.writeBlock( cstr.data(), cstr.length() ); 679 total_written = f.writeBlock( cstr.data(), cstr.length() );
530 if ( total_written != int(cstr.length()) ) { 680 if ( total_written != int(cstr.length()) ) {
531 f.close(); 681 f.close();
532 QFile::remove( strNewFile ); 682 QFile::remove( strNewFile );
533 return FALSE; 683 return FALSE;
534 } 684 }
535 f.close(); 685 f.close();
536 686
687#ifdef Q_OS_WIN32
688 QFile::remove( fname );
689#endif
537 if ( ::rename( strNewFile.latin1(), fname.latin1() ) < 0 ) { 690 if ( ::rename( strNewFile.latin1(), fname.latin1() ) < 0 ) {
538 qWarning( "problem renaming file %s to %s", 691 qWarning( "problem renaming file %s to %s",
539 strNewFile.latin1(), fname.latin1()); 692 strNewFile.latin1(), fname.latin1());
540 // remove the tmp file... 693 // remove the tmp file...
541 QFile::remove( strNewFile ); 694 QFile::remove( strNewFile );
542 } 695 }
543 696
544 return TRUE; 697 return TRUE;
545} 698}
546 699
700/*!
701 Loads the Categories database using \a fname. See categoryFileName()
702 for the default file name string used for the shared category database.
703
704 Returns FALSE if there is error reading the file or TRUE on success.
705 */
547bool Categories::load( const QString &fname ) 706bool Categories::load( const QString &fname )
548{ 707{
549 QFile file( fname ); 708 QFile file( fname );
550 if ( !file.open( IO_ReadOnly ) ) { 709 if ( !file.open( IO_ReadOnly ) ) {
551 qWarning("Unable to open %s", fname.latin1()); 710 qWarning("Unable to open %s", fname.latin1());
552 711
553 addGlobalCategory(tr("Business")); 712 addGlobalCategory(tr("Business"));
554 addGlobalCategory(tr("Personal")); 713 addGlobalCategory(tr("Personal"));
555 save(fname); 714 save(fname);
556 715
557 return FALSE; 716 return FALSE;
558 } 717 }
@@ -610,30 +769,37 @@ bool Categories::load( const QString &fname )
610 qWarning("No name or id in the category"); 769 qWarning("No name or id in the category");
611 continue; 770 continue;
612 } 771 }
613 if ( app.isNull() ) 772 if ( app.isNull() )
614 mGlobalCats.add( id.toInt(), name ); 773 mGlobalCats.add( id.toInt(), name );
615 else 774 else
616 mAppCats[ app ].add( id.toInt(), name ); 775 mAppCats[ app ].add( id.toInt(), name );
617 } 776 }
618 777
619 return TRUE; 778 return TRUE;
620} 779}
621 780
781/*!
782 Clear the categories in memory. Equivelent to creating an empty Categories
783 object.
784*/
622void Categories::clear() 785void Categories::clear()
623{ 786{
624 mGlobalCats.clear(); 787 mGlobalCats.clear();
625 mAppCats.clear(); 788 mAppCats.clear();
626} 789}
627 790
791/*!
792 Dump the contents to standard out. Used for debugging only.
793*/
628void Categories::dump() const 794void Categories::dump() const
629{ 795{
630 qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() ); 796 qDebug("\tglobal categories = %s", mGlobalCats.labels().join(", ").latin1() );
631 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) { 797 for ( QMap<QString, CategoryGroup>::ConstIterator appsIt = mAppCats.begin(); appsIt != mAppCats.end(); ++appsIt ) {
632 const QString &app = appsIt.key(); 798 const QString &app = appsIt.key();
633 QStringList appcats = (*appsIt).labels(); 799 QStringList appcats = (*appsIt).labels();
634 qDebug("\tapp = %s\tcategories = %s", app.latin1(), 800 qDebug("\tapp = %s\tcategories = %s", app.latin1(),
635 appcats.join(", ").latin1() ); 801 appcats.join(", ").latin1() );
636 802
637 } 803 }
638} 804}
639 805
@@ -666,12 +832,105 @@ void CheckedListView::setChecked( const QStringList &checked )
666 // checked list 832 // checked list
667 if ( checked.find( i->text( 0 ) ) != checked.end() ) { 833 if ( checked.find( i->text( 0 ) ) != checked.end() ) {
668 i->setOn( TRUE ); 834 i->setOn( TRUE );
669 // make sure it is showing at least one checked item 835 // make sure it is showing at least one checked item
670 if ( !showingChecked ) { 836 if ( !showingChecked ) {
671 ensureItemVisible( i ); 837 ensureItemVisible( i );
672 showingChecked = TRUE; 838 showingChecked = TRUE;
673 } 839 }
674 } 840 }
675 else 841 else
676 i->setOn( FALSE ); 842 i->setOn( FALSE );
677} 843}
844
845/*! \fn Categories &Categories::operator= ( const Categories &c )
846
847 Performs deep copy.
848 */
849
850
851/*! \fn QStringList Categories::labels( const QString & app, const QArray<int> &catids ) const
852
853 Returns list of labels associated with the application and catids
854*/
855
856/*! \fn QStringList Categories::globalCategories() const
857
858 Returns list of all global category labels
859*/
860
861/*! \fn const QMap<QString, CategoryGroup> &Categories::appGroupMap() const
862
863 Returns a map of application names to CategoryGroup. The CategoryGroup
864 class defines a map of ids to category labels and category labels to ids.
865*/
866
867/*! \fn const CategoryGroup &Categories::globalGroup() const
868
869 Returns the global CategoryGroup. The CategoryGroup
870 class defines a map of ids to category labels and category labels to ids.
871*/
872
873/*! \fn void Categories::categoryAdded( const Categories &cats, const QString &appname, int uid)
874
875 Emitted if a category is added.
876
877 \a cats is a const reference to this object
878 \a appname is the CategoryGroup application name that the category was added to or QString::null if it was global
879 \a uid is the unique identifier associated with the added category
880 */
881
882/*! \fn void Categories::categoryRemoved( const Categories &cats, const QString &appname,
883 int uid)
884
885 Emitted if removed category is removed.
886
887 \a cats is a const reference to this object
888 \a appname is the CategoryGroup application name that the category was removed from or QString::null if it was the global CategoryGroup
889 \a uid is the unique identifier associated with the removed category
890*/
891
892
893/*! \fn void Categories::categoryRenamed( const Categories &cats, const QString &appname,
894 int uid)
895
896 Emitted if \a uid in the \a appname CategoryGroup is renamed in \a cats
897 object.
898
899 \a cats is a const reference to this object
900 \a appname is the CategoryGroup application name that the category was renamed in or QString::null if it was the global CategoryGroup
901 \a uid is the unique identifier associated with the renamed category
902*/
903
904/*! \fn Categories::Categories( QObject *parent=0, const char *name = 0 )
905
906 Constructor for an empty Categories object.
907*/
908
909/*! \fn Categories::Categories( const Categories &copyFrom )
910
911 Deep copy constructor
912*/
913
914/*! \fn Categories::~Categories()
915
916 Empty destructor. Call save() before destruction if there are changes
917 that need to be saved.
918*/
919
920/*! \fn CategoryGroup::clear()
921 \internal
922*/
923
924/*! \fn const QMap<int, QString> &CategoryGroup::idMap() const
925
926 Returns a const reference to the id to label QMap
927*/
928
929/*! \fn CategoryGroup::CategoryGroup()
930 \internal
931*/
932
933/*! \fn CategoryGroup::CategoryGroup(const CategoryGroup &c)
934 \internal
935*/
936