summaryrefslogtreecommitdiff
path: root/libopie/big-screen/omodalhelper.h
Unidiff
Diffstat (limited to 'libopie/big-screen/omodalhelper.h') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/big-screen/omodalhelper.h708
1 files changed, 0 insertions, 708 deletions
diff --git a/libopie/big-screen/omodalhelper.h b/libopie/big-screen/omodalhelper.h
deleted file mode 100644
index 78a2ac9..0000000
--- a/libopie/big-screen/omodalhelper.h
+++ b/dev/null
@@ -1,708 +0,0 @@
1/*
2               =. This file is part of the OPIE Project
3             .=l. Copyright (c) 2003 hOlgAr <zecke@handhelds.org>
4           .>+-=
5 _;:,     .>    :=|. This library is free software; you can
6.> <`_,   >  .   <= redistribute it and/or modify it under
7:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
8.="- .-=="i,     .._ License as published by the Free Software
9 - .   .-<_>     .<> Foundation; either version 2 of the License,
10     ._= =}       : or (at your option) any later version.
11    .%`+i>       _;_.
12    .i_,=:_.      -<s. This library is distributed in the hope that
13     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
14    : ..    .:,     . . . without even the implied warranty of
15    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
16  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
17..}^=.=       =       ; Library General Public License for more
18++=   -.     .`     .: details.
19 :     =  ...= . :.=-
20 -.   .:....=;==+<; You should have received a copy of the GNU
21  -_. . .   )=.  = Library General Public License along with
22    --        :-=` this library; see the file COPYING.LIB.
23 If not, write to the Free Software Foundation,
24 Inc., 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA.
26
27*/
28
29#ifndef HAZE_OMODAL_HELPER_H
30#define HAZE_OMODAL_HELPER_H
31
32#include <qdialog.h>
33#include <qwidget.h>
34#include <qvaluelist.h>
35#include <qmap.h>
36#include <qvariant.h>
37
38typedef int TransactionID;
39
40class OModalHelperControler;
41class OModalHelperSignal;
42class QDialog;
43
44struct OModalHelperBase {
45 virtual void done( int status, TransactionID ) = 0;
46 virtual void next( TransactionID ) = 0;
47 virtual void prev( TransactionID ) = 0;
48};
49
50/**
51 * Modality sucks! ;) But it is easy to work with
52 * do exec() on a dialog and you know everything is funky.
53 * You only need to have one Dialog loaded and so on.
54 * This class helps you to work like with modality and help
55 * you to keep things in sync
56 * It's a template class but it sends signals once one Item is ready
57 * the signals contains the status and id of the item and then you
58 * need fetch it.
59 * Handled Records will stay available until the first call to retrieve
60 * either the record via the TransactionID or via the QValueList<Record>. Note
61 * that most functions do not take handled records into account.
62 * Also if you edit an record external you can tell this class and it'll
63 * call the merge() function of your widget to maybe merge in these changes.
64 * It also supports multiple modes. Either it can create new dialogs
65 * for each item or it can queue them depending on your usage. But it is
66 * so smart that if only one item is shown that the queue bar is not shown
67 * See the example for simple usage.
68 *
69 * @short helps to life without modaility
70 * @author hOlgAr
71 * @version 0.01
72 */
73template<class Dialog, class Record, typename Id = int>
74class OModalHelper : private OModalHelperBase{
75 friend class OModalHelperSignal;
76 friend class OModalHelperControler;
77public:
78 typedef QValueList<Record> RecordList;
79 typedef QMap<Id, Record> IdMap;
80 typedef QMap<TransactionID, Id> TransactionMap;
81 typedef QMap<QDialog*, TransactionID> DialogMap
82 enum Mode { Queue, New };
83 OModalHelper(enum Mode mode, QObject* parnet );
84
85 bool handles( Id id)const;
86 TransactionID transactionID( Id id)const;
87
88 void suspend( bool = true );
89
90 void cancel();
91 void cancel( TransactionID );
92
93 void connectDone( QObject* rec, const char* slot );
94 void connectAccepted( QObject* rec, const char* slot );
95 void connectRejected( QObject* rec, const char* slot );
96
97 TransactionID handle( Id id, const Record& rec = Record() );
98
99 void edited( Id, int what, const QVariant& data );
100
101 Record record( TransactionID )const;
102 RecordList recordsDone()const;
103private:
104 virtual void done( int, TransactionID );
105 virtual void next( TransactionID );
106 virtual void prev( TransactionID );
107
108 Record nextRecord( TransactionID &, int & )const;
109 Record prevRecord( TransactionID &, int & )const;
110 int pos( TransactionID )const;
111 Dialog* newDialogRecord( const Record& );
112
113private:
114 OModalHelperDialog *queuedDialog()const; // generate or recycle
115 OModalHelperDialog *m_dialog;
116 OModalHelperSignal *m_signal; // our signal
117 OModalHelperControler *m_controler;
118 IdMap m_ids; // maps ids (uids) to a record
119 IdMap m_doneIds;
120 TransactionMap m_transactions; // activate transactions
121 TransactionMap m_done; // done and waiting for getting picked
122 DialogMap m_editing; // only used for New Mode
123 enum Mode m_mode; // the mode we're in
124 bool m_disabled :1;
125};
126
127
128
129/* ### FIXME use namespace with Qt3 */
130
131/*
132 * A note on flow. The Signal is used for QT Signals when
133 * a record is done.
134 * There is either one controler and this controler slot will
135 * be connected to a dialog signal.
136 * In Queue we get the next and prev signals and call the Helper.
137 * this then changes the Record of the dialog and sets the transactionId
138 * of the controler.
139 * For the new mode
140 *
141 */
142
143class OModalHelperSignal : public QObject {
144 Q_OBJECT
145public:
146 OModalHelperSignal(OModalHelperBase* base, QObject* parent);
147 ~OModalHelperSignal();
148
149signals:
150 done( int status, TransactionID transaction );
151 accepted( TransactionID transaction );
152 rejected( TransactionID transaction );
153
154private:
155 OModalHelperBase* m_base;
156};
157
158
159class OModalHelperControler : public QObject {
160 Q_OBJECT
161public:
162 OModalHelperControler( OModalHelperBase* , QObject* parent);
163 virtual TransactionID transactionID()const;
164 void setTransactionID( TransactionID id );
165 QDialog* dialog()const;
166
167public slots:
168 virtual void done(int result );
169 virtual void next();
170 virtual void prev();
171private:
172 QDialog *m_dia;
173 TransactionID m_id;
174 OModalHelperBase *m_base;
175}
176
177struct OModalQueueBar;
178class OModalQueuedDialog : public QDialog {
179 Q_OBJECT
180public:
181 OModalQueuedDialog(QDialog *mainWidget);
182 ~OModalQueuedDialog();
183
184 QDialog* centerDialog()const;
185
186 void setQueueBarEnabled( bool = true );
187 void setRecord( int record, int count );
188
189signals:
190 void next();
191 void prev();
192
193private:
194 OModalQueueBar *m_bar;
195 QDialog *m_center;
196};
197
198
199/*
200 * Tcpp Template Implementation
201 */
202
203/**
204 * This is the simple Template c'tor. It takes the mode
205 * this helper should operate in and the parent object.
206 * This helper will be deleted when the parent gets deleted
207 * or you delete it yourself.
208 *
209 * @param mode The mode this dialog should be in
210 * @param parent The parent QObject of this helper.
211 */
212template<class Dialog, class Record, typename Id>
213OModalHelper<Dialog, Record, Id>::OModalHelper( enum Mode mode, QObject* parent ) {
214 m_disabled = false;
215 m_mode = mode;
216 m_signal = new OModalHelperSignal( this, parent );
217 m_controler = new OModalHelperControler( this, m_signal );
218}
219
220
221/**
222 * This functions looks for your record and sees if it is
223 * handled with this helper. Note that done records
224 * will not be returned.
225 *
226 * @return true if the record is currenlty edited otherwise false
227 *
228 * @param Id The id which might be handled
229 */
230template<class Dialog, class Record, typename Id>
231bool OModalHelper<Dialog, Record, Id>::handles( Id id )const {
232 if ( m_transactions.isEmpty() )
233 return false;
234
235 TransactionMap::ConstIterator it = m_transactions.begin();
236 for ( ; it != m_transactions.end(); ++it )
237 if ( it.data() == id )
238 return true;
239
240 return false;
241}
242
243
244/**
245 * just like handles( Id ) but returns the TransactionId
246 */
247template<class Dialog, class Record, typename Id>
248TransactionID OModalHelper<Dialog, Record, Id>::transactionID( Id id)const {
249 if ( m_transactions.isEmpty() || !m_ids.contains( id ) )
250 return 0;
251
252 TransactionMap::ConstIterator it = m_transactions.begin();
253 for ( ; it != m_transactions.end(); ++it )
254 if ( it.data() == id )
255 return it.key();
256
257 return 0;
258}
259
260/**
261 * If you're requested to flush your data and you do not want
262 * to call cancel with this method you can disable and enabled
263 * all dialogs.
264 * The state gets saved so if you want to handle a new record the dialog
265 * will be disabled as well.
266 *
267 * @param sus If true setDisabled(TRUE) will be called otherwise FALSE
268 */
269template<class Dialog, class Record, typename Id>
270void OModalHelper<Dialog, Record, Id>::suspend(bool sus) {
271 m_disabled = sus;
272 if (m_mode == New )
273 for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
274 it.key()->setDisabled( sus );
275 else if (m_dialog )
276 queuedDialog()->setDisabled( sus );
277}
278
279/**
280 * Cancel will cancel all current operations and clear the list
281 * of done operations as well.
282 * This also clears all done operations you did not popped
283 */
284template<class Dialog, class Record, typename Id>
285void OModalHelper<Dialog, Record, Id>::cancel() {
286 m_ids.clear();
287 m_doneIds.clear();
288 m_done.clear();
289 m_transactions.clear();
290
291 /* we also need to remove the QDialogs */
292 /* and hide the queue dialog if present */
293 if (m_mode == New && !m_editing.isEmpty() ) {
294 for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
295 delete it.key();
296
297 m_editing.clear();
298 }else if (m_dialog )
299 queuedDialog()->setRecord( 0, 0 );
300
301 m_controler->setTransactionID( 0 );
302}
303
304
305/**
306 * This cancels editing of the record behind the Transaction Number
307 * Note that if editing is already done it will also be removed from this list
308 */
309template<class Dialog, class Record, typename Id>
310void OModalHelper::cancel( TransactionID tid ) {
311 /* wrong tid */
312 if (!m_transactions.contains( tid ) && !m_done.contains( tid) )
313 return;
314
315 if (m_mode == New )
316 /* reverse map eek */
317 for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
318 if ( it.data() == tid ) {
319 it.key()->hide();
320 delete it.key();
321 it = m_editing.remove( it );
322 break;
323 }
324
325 /* now remove from the various maps done and currently editing map*/
326 if (m_transactions.contains( tid ) )
327 m_ids.remove( m_transactions[tid] );
328 if (m_done.contains( tid ) )
329 m_doneIds.remove( m_done[tid ] );
330 m_done.remove( tid );
331 m_transactions.remove( tid );
332
333 next( 0 );
334}
335
336/**
337 * Connect to the done Signal. SIGNAL( done(int, TransactionID ) )
338 * This signal gets emitted whenever a Record was accepted or rejected
339 *
340 * @param rec The object where the slot belongs to
341 * @param slot The slot which should be called. See the needed parameter above
342 */
343template<class Dialog, class Record, typename Id>
344void OModalHelper<Dialog, Record, Id>::connectDone( QObject* rec, const char* slot ) {
345 QObject::connect(m_signal, SIGNAL(done(int, TransactionID) ),
346 rec, slot );
347}
348
349/**
350 * Connect to the accepted Signal. SIGNAL( accepted(TransactionID ) )
351 * This signal gets emitted whenever a Record was accepted
352 *
353 * @param rec The object where the slot belongs to
354 * @param slot The slot which should be called. See the needed parameter above
355 */
356template<class Dialog, class Record, typename Id>
357void OModalHelper<Dialog, Record, Id>::connectAccepted( QObject* rec, const char* slot ) {
358 QObject::connect(m_signal, SIGNAL(accepted(TransactionID) ),
359 rec, slot );
360}
361
362/**
363 * Same as the accepted method but this one gets emitted if the dialog
364 * got rejected.
365 * SIGNAL( rejected(TransactionID) )
366 *
367 * @param rec The QObject of the slot
368 * @param slot The slot make sure the signature is correct
369 */
370template<class Dialog, class Record, typename Id>
371void OModalHelper<Dialog, Record, Id>::connectRejected( QObject* rec, const char* slot ) {
372 QObject::connect(m_signal, SIGNAL(rejected(TransactionID) ),
373 rec, slot );
374}
375
376/**
377 * Tell the helper to handle a record. If the record is currently handled
378 * it will be made active.
379 * Already handled record which are waiting getting popped are not taken into account
380 * Otherwise this helpers make the record editable.
381 * The record supplied needs to have a valid copy operator and constructor.
382 * In the case where the record is already present the parameter gets discarded.
383 * If you want the new record to be taken you need to cancel the Transaction first
384 *
385 * @param id The Identification of the Record. For PIM it would uid()
386 * @param rec The record we want to be edited
387 *
388 * @returns This functions returns the TransactionId assigned to the record
389 *
390 */
391template<class Dialog, class Record, typename Id>
392TransactionID OModalHelper<Dialog, Record, Id>::handle( Id id, const Record& rec ) {
393 static TransactionID t_id = 0;
394 /*
395 *this method consists out of two parts divided each into New and Queued Mode.
396 * Either we have the dialog already, in this case we need to highlight the widget
397 * Or we need to add it.
398 */
399 TransactionID tid = 0;
400 /* we already have the record lets see if it was done or not */
401 if ( !(tid = transactionID( id ) ) ) {
402 if (m_mode == New ) {
403 /* lets find the dialog and show it need to reverse map*/
404 for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
405 if ( it.data() == tid )
406 it.key()->show();
407 }else if (m_controler->transactionID() != tid ) {
408 int po = pos( tid );
409 m_controler->setTransactionID( tid );
410 static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( m_ids[ m_transactions[tid] ] );
411 queuedDialog()->setRecord( po, m_transactions.count() );
412 }
413 }else {
414 tid = ++t_id;
415 m_transactions.insert( tid, id );
416 m_ids.insert( id, rec );
417
418 if (m_mode == New )
419 m_editing.insert( newDialogRecord( rec ), tid );
420 else{
421 m_controler->setTransactionID( tid );
422 static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( rec );
423 queuedDialog()->setRecord( m_transactions.count(), m_transactions.count() );
424 }
425 }
426 return tid;
427}
428
429/**
430 * The goal of this helper is to help you to create non blocking
431 * GUIs. In the example of the todolist you can have the edit dialog
432 * but still change the priority or completion inline even if you currently
433 * edit the record.
434 * Your Dialog needs to have a Method setData(int,const QVariant& ) which will be called
435 * in these cases.
436 * If you edit anything while a record is edited call this function to merge the
437 * change in. Note if the record is not handled here we will ignore the request
438 *
439 */
440template<class Dialog, class Record, typename Id>
441void OModalHelper<Dialog, Record, Id>::edited( Id id, int what, const QVariant& data ) {
442 int tid;
443 if (!( tid = transactionID( id ) ) )
444 return;
445
446 if (m_mode == New ) {
447 for (DialogMap::Iterator it= m_editing.begin(); it != m_editing.end(); ++it )
448 if ( it.data() == tid )
449 it.key()->setData( what, data );
450 }else{
451 int po = pos( tid );
452 Dialog* dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
453 dia->setRecord( m_ids[id] );
454 dia->setData( what, data );
455 queuedDialog()->setRecord( pos, m_transactions.count() );
456 }
457}
458
459/**
460 * This functions either returns the unedited record the done record
461 * or a new empty Record using Record().
462 * If a done record is retrieved all traces are removed inside this class. This
463 * is what was called popping a record. This means when you call this function
464 * with the same TransactionID an Empty record is retrieved.
465 *
466 */
467template<class Dialog, class Record, typename Id>
468Record OModalHelper<Dialog, Record, Id>::record( TransactionID tid)const {
469 if (m_transactions.contains( tid ) )
470 return m_ids[ m_transactions[tid] ];
471 else if (m_done.contains( tid ) ) {
472 Record rec = m_doneIds[ m_done[ tid] ];
473 m_doneIds.remove( m_done[ tid ] );
474 m_done.remove( tid );
475 return rec;
476 }else
477 return Record();
478}
479
480/**
481 * Returns all done Records and removes all references to them internally. A 2nd call to this will
482 * only contain done record that where edited past the point
483 */
484template<class Dialog, class Record, typename Id>
485OModalHelper<Dialog,Record,Id>::RecordList OModalHelper<Dialog, Record, Id>::recordsDone()const {
486 RecordList list;
487
488 for (IdMap::ConstIterator it = m_doneIds.begin(); it != m_doneIds.end(); ++it )
489 list.append( it.data() );
490
491 /* clean up */
492 m_done.clear();
493 m_doneIds.clear();
494
495 return list;
496}
497
498
499/**
500 * @internal
501 */
502template<class Dialog, class Record, typename Id>
503void OModalHelper<Dialog, Record, Id>::done( int status, TransactionID tid) {
504/* If we're in New mode the transaction Id does not count */
505 Record rec;
506
507 if (m_mode == New ) {
508 Dialog *dia = static_cast<Dialog*>( m_controler->dialog() );
509 m_controler->setTransactionID( 0 ); // set the internal dialog to 0l again
510 tid = m_editing[ dia ];
511 m_editing.remove( dia );
512 rec = dia->record();
513 delete dia;
514 }else
515 rec = queuedDialog()->record();
516
517 Id id = m_transactions[ tid ];
518 if (result == QDialog::Accept ) {
519 m_doneIds.insert( is, rec );
520 m_done.insert( tid, id );
521 }
522
523 m_transactions.remove( tid );
524 m_ids.remove( id );
525
526
527 if (status == QDialog::Accept )
528 emit m_signal->accepted( tid );
529 else
530 emit m_signal->rejected( tid );
531
532 emit m_signal->done( result, tid );
533
534 next( 0 );
535}
536
537/**
538 * @internal
539 */
540template<class Dialog, class Record, typename Id>
541void OModalHelper<Dialog, Record, Id>::next( TransactionID tid) {
542 if (m_mode == New )
543 return;
544
545 if (! (m_transactions.count() ) ) {
546 m_controler->setTransactionID( 0 );
547 queuedDialog()->setRecord( 0, 0 );
548 return;
549 }
550
551 int next;
552 Record rec;
553
554 /* save the maybe edited record before switching */
555 Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
556 rec = dia->record();
557 m_ids.replace( m_transactions[tid], rec );
558
559 rec = nextRecord( tid, next );
560 queuedDialog()->setRecord( next, m_transactions.count() );
561 dia->setRecord( rec );
562
563 m_controler->setTransactionID( tid ); // was changed during the next call
564}
565
566/**
567 * @internal
568 */
569/*
570 * code duplication should create a template fcuntion
571 * which takes a pointer to a function ( next, prev ) function
572 */
573template<class Dialog, class Record, typename Id>
574void OModalHelper<Dialog, Record, Id>::prev( TransactionID tid ) {
575 if (m_mode == New )
576 return;
577
578 if (! (m_transactions.count()) ) {
579 m_controler->setTransactionID( 0 );
580 queuedDialog()->setRecord( 0, 0 );
581 return;
582 }
583
584 int prev;
585 Record rec;
586
587 /* save the maybe edited record before switching */
588 Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
589 rec = dia->record();
590 m_ids.replace( m_transactions[tid], rec );
591
592 rec = prevRecord( tid, prev );
593 queuedDialog()->setRecord( prev, m_transactions.count() );
594 dia->setRecord( rec );
595
596 m_controler->setTransactionID( tid ); // was changed during the next call
597}
598
599/**
600 * @internal
601 */
602template<class Dialog, class Record, typename Id>
603Record OModalHelper<Dialog, Record, Id>::nextRecord( TransactionID &tid, int &po ) {
604 /* if tid is == 0 we will take the first one */
605 /* pos starts at 1 here */
606 /* we know we're only called if there are records */
607 Record rec;
608 TransactionMap::Iterator it;
609 if (!tid ) {
610 po = 1;
611 TransactionMap::Iterator it = m_transactions.begin();
612 }else{
613 po = pos( tid );
614 /* if it is the last take the first as next */
615 if ( po == m_transactions.count() ) {
616 po = 1;
617 it = m_transactions.begin();
618 }else {
619 /* we know we're not the last and there is one after us */
620 it = m_transactions.find( tid );
621 ++it; ++po;
622 }
623 }
624
625 tid = it.key();
626 rec = m_ids[ tid ];
627 return rec;
628}
629
630/**
631 * @internal
632 */
633template<class Dialog, class Record, typename Id>
634Record OModalHelper<Dialog, Record, Id>::prevRecord( TransactionID& tid, int& pos ) {
635 /* if tid is == 0 we will take the first one */
636 /* pos starts at 1 here */
637 /* we know we're only called if there are records */
638 Record rec;
639 TransactionMap::Iterator it;
640 if (!tid ) {
641 po = 1;
642 TransactionMap::Iterator it = m_transactions.begin();
643 }else{
644 po = pos( tid );
645 /* if it is the last take the first as next */
646 if ( po == 1 ) {
647 po = m_transactions.count();
648 it = m_transactions.end();
649 --it;
650 }else {
651 /* we know we're not the first and there is one before us */
652 it = m_transactions.find( tid );
653 --it; --po;
654 }
655 }
656
657 tid = it.key();
658 rec = m_ids[ tid ];
659 return rec;
660}
661
662/**
663 * @internal
664 */
665template<class Dialog, class Record, typename Id>
666int OModalHelper<Dialog, Record, Id>::pos( TransactionID id)const {
667 int i = 1;
668 for ( TransactionMap::ConstIterator it = m_transactions.begin(); it != m_transactions.end(); ++it, i++ )
669 if ( it.key() == id )
670 return i;
671
672
673 return 0;
674}
675
676/**
677 * @internal
678 */
679template<class Dialog, class Record, typename Id>
680Dialog* OModalHelper<Dialog, Record, Id>::newDialogRecord( const Record& rec ) {
681 Dialog* dia = new Dialog;
682 dia->setRecord( rec );
683 dia->setDisabled( m_disabled );
684
685 QObject::connect(dia, SIGNAL(done(int) ),
686 m_controler, SLOT(done(int) ) );
687
688 /* FIXME big screen QPEApplication needs fixed*/
689 dia->show();
690}
691
692template<class Record, class Dialog, typename Id>
693OModalHelperDialog* OModalHelper<Record, Dialog, Id>::queuedDialog()const{
694 if (!m_dialog ) {
695 m_dialog = new OModalHelperDialog;
696 m_dialog->setEnabled( m_disabled );
697
698 QObject::connect(m_dialog, SIGNAL(done(int) ),
699 m_controler, SLOT(done(int) ) );
700 QObject::connect(m_dialog, SIGNAL(next() ),
701 m_controler, SLOT(next() ) );
702 QObject::connect(m_dialog, SIGNAL(prev() ),
703 m_controler, SLOT(prev() ) );
704 }
705 return m_dialog;
706}
707
708#endif