Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

omodalhelper.h

Go to the documentation of this file.
00001 /*
00002                =.            This file is part of the OPIE Project
00003              .=l.            Copyright (c)  2003 hOlgAr <zecke@handhelds.org>
00004            .>+-=
00005  _;:,     .>    :=|.         This library is free software; you can
00006 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00007 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00008 .="- .-=="i,     .._         License as published by the Free Software
00009  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00010      ._= =}       :          or (at your option) any later version.
00011     .%`+i>       _;_.
00012     .i_,=:_.      -<s.       This library is distributed in the hope that
00013      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00014     : ..    .:,     . . .    without even the implied warranty of
00015     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00016   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00017 ..}^=.=       =       ;      Library General Public License for more
00018 ++=   -.     .`     .:       details.
00019  :     =  ...= . :.=-
00020  -.   .:....=;==+<;          You should have received a copy of the GNU
00021   -_. . .   )=.  =           Library General Public License along with
00022     --        :-=`           this library; see the file COPYING.LIB.
00023                              If not, write to the Free Software Foundation,
00024                              Inc., 59 Temple Place - Suite 330,
00025                              Boston, MA 02111-1307, USA.
00026  
00027 */
00028 
00029 #ifndef OMODALHELPER_H
00030 #define OMODALHELPER_H
00031 
00032 /* QT*/
00033 #include <qdialog.h>
00034 #include <qwidget.h>
00035 #include <qvaluelist.h>
00036 #include <qmap.h>
00037 #include <qvariant.h>
00038 
00039 typedef int TransactionID;
00040 
00041 class QDialog;
00042 
00043 namespace Opie
00044 {
00045 
00046 class OModalHelperControler;
00047 class OModalHelperSignal;
00048 
00049 struct OModalHelperBase
00050 {
00051     virtual void done( int status, TransactionID ) = 0;
00052     virtual void next( TransactionID ) = 0;
00053     virtual void prev( TransactionID ) = 0;
00054 };
00055 
00079 template<class Dialog, class Record, typename Id = int>
00080 class OModalHelper : private OModalHelperBase
00081 {
00082     friend class OModalHelperSignal;
00083     friend class OModalHelperControler;
00084 public:
00085     typedef QValueList<Record> RecordList;
00086     typedef QMap<Id, Record> IdMap;
00087     typedef QMap<TransactionID, Id> TransactionMap;
00088     typedef QMap<QDialog*, TransactionID> DialogMap
00089     enum Mode { Queue, New };
00090     OModalHelper(enum Mode mode, QObject* parnet );
00091 
00092     bool handles( Id id)const;
00093     TransactionID transactionID( Id id)const;
00094 
00095     void suspend( bool = true );
00096 
00097     void cancel();
00098     void cancel( TransactionID );
00099 
00100     void connectDone( QObject* rec, const char* slot );
00101     void connectAccepted( QObject* rec, const char* slot );
00102     void connectRejected( QObject* rec, const char* slot );
00103 
00104     TransactionID handle( Id id, const Record& rec = Record() );
00105 
00106     void edited( Id, int what, const QVariant& data );
00107 
00108     Record record( TransactionID )const;
00109     RecordList recordsDone()const;
00110 private:
00111     virtual void done( int, TransactionID );
00112     virtual void next( TransactionID );
00113     virtual void prev( TransactionID );
00114 
00115     Record nextRecord( TransactionID &, int & )const;
00116     Record prevRecord( TransactionID &, int & )const;
00117     int pos( TransactionID )const;
00118     Dialog* newDialogRecord( const Record& );
00119 
00120 private:
00121     OModalHelperDialog     *queuedDialog()const; // generate or recycle
00122     OModalHelperDialog     *m_dialog;
00123     OModalHelperSignal     *m_signal; // our signal
00124     OModalHelperControler  *m_controler;
00125     IdMap                  m_ids; // maps ids (uids) to a record
00126     IdMap                  m_doneIds;
00127     TransactionMap         m_transactions; // activate transactions
00128     TransactionMap         m_done; // done and waiting for getting picked
00129     DialogMap              m_editing; // only used for New Mode
00130     enum Mode              m_mode; // the mode we're in
00131 bool                   m_disabled :1;
00132 };
00133 
00134 
00135 
00136 /* ### FIXME use namespace with Qt3 */
00137 
00138 /*
00139  * A note on flow. The Signal is used for QT Signals when
00140  * a record is done.
00141  * There is either one controler and this controler slot will
00142  * be connected to a dialog signal.
00143  * In Queue we get the next and prev signals and call the Helper.
00144  * this then changes the Record of the dialog and sets the transactionId
00145  * of the controler.
00146  * For the new mode
00147  *
00148  */
00149 
00150 class OModalHelperSignal : public QObject
00151 {
00152     Q_OBJECT
00153 public:
00154     OModalHelperSignal(OModalHelperBase* base,  QObject* parent);
00155     ~OModalHelperSignal();
00156 
00157 signals:
00158     done( int status,  TransactionID transaction );
00159     accepted( TransactionID transaction );
00160     rejected( TransactionID transaction );
00161 
00162 private:
00163     OModalHelperBase* m_base;
00164 };
00165 
00166 
00167 class OModalHelperControler : public QObject
00168 {
00169     Q_OBJECT
00170 public:
00171     OModalHelperControler( OModalHelperBase* , QObject* parent);
00172     virtual TransactionID transactionID()const;
00173     void setTransactionID( TransactionID id );
00174     QDialog* dialog()const;
00175 
00176 public slots:
00177     virtual void done(int result );
00178     virtual void next();
00179     virtual void prev();
00180 private:
00181     QDialog *m_dia;
00182     TransactionID m_id;
00183     OModalHelperBase *m_base;
00184 }
00185 
00186 struct OModalQueueBar;
00187 class OModalQueuedDialog : public QDialog
00188 {
00189     Q_OBJECT
00190 public:
00191     OModalQueuedDialog(QDialog *mainWidget);
00192     ~OModalQueuedDialog();
00193 
00194     QDialog* centerDialog()const;
00195 
00196     void setQueueBarEnabled( bool = true );
00197     void setRecord( int record, int count );
00198 
00199 signals:
00200     void next();
00201     void prev();
00202 
00203 private:
00204     OModalQueueBar *m_bar;
00205     QDialog *m_center;
00206 };
00207 
00208 
00209 /*
00210  * Tcpp Template Implementation
00211  */
00212 
00222 template<class Dialog, class Record, typename Id>
00223 OModalHelper<Dialog, Record, Id>::OModalHelper( enum Mode mode, QObject* parent )
00224 {
00225     m_disabled = false;
00226     m_mode = mode;
00227     m_signal = new OModalHelperSignal( this, parent );
00228     m_controler = new OModalHelperControler( this, m_signal );
00229 }
00230 
00231 
00241 template<class Dialog, class Record, typename Id>
00242 bool OModalHelper<Dialog, Record, Id>::handles( Id id )const
00243 {
00244     if ( m_transactions.isEmpty() )
00245         return false;
00246 
00247     TransactionMap::ConstIterator it = m_transactions.begin();
00248     for ( ; it != m_transactions.end(); ++it )
00249         if ( it.data() == id )
00250             return true;
00251 
00252     return false;
00253 }
00254 
00255 
00259 template<class Dialog, class Record, typename Id>
00260 TransactionID OModalHelper<Dialog, Record, Id>::transactionID( Id id)const
00261 {
00262     if ( m_transactions.isEmpty() || !m_ids.contains( id ) )
00263         return 0;
00264 
00265     TransactionMap::ConstIterator it = m_transactions.begin();
00266     for ( ; it != m_transactions.end(); ++it )
00267         if ( it.data() == id )
00268             return it.key();
00269 
00270     return 0;
00271 }
00272 
00282 template<class Dialog, class Record, typename Id>
00283 void OModalHelper<Dialog, Record, Id>::suspend(bool sus)
00284 {
00285     m_disabled = sus;
00286     if (m_mode == New )
00287         for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
00288             it.key()->setDisabled( sus );
00289     else if (m_dialog )
00290         queuedDialog()->setDisabled( sus );
00291 }
00292 
00298 template<class Dialog, class Record, typename Id>
00299 void OModalHelper<Dialog, Record, Id>::cancel()
00300 {
00301     m_ids.clear();
00302     m_doneIds.clear();
00303     m_done.clear();
00304     m_transactions.clear();
00305 
00306     /* we also need to remove the QDialogs */
00307     /* and hide the queue dialog if present */
00308     if (m_mode == New && !m_editing.isEmpty() )
00309     {
00310         for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
00311             delete it.key();
00312 
00313         m_editing.clear();
00314     }
00315     else if (m_dialog )
00316         queuedDialog()->setRecord( 0, 0 );
00317 
00318     m_controler->setTransactionID( 0 );
00319 }
00320 
00321 
00326 template<class Dialog, class Record, typename Id>
00327 void OModalHelper::cancel( TransactionID tid )
00328 {
00329     /* wrong tid */
00330     if (!m_transactions.contains( tid ) && !m_done.contains( tid) )
00331         return;
00332 
00333     if (m_mode == New )
00334         /* reverse map eek */
00335         for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
00336             if ( it.data() == tid )
00337             {
00338                 it.key()->hide();
00339                 delete it.key();
00340                 it = m_editing.remove( it );
00341                 break;
00342             }
00343 
00344     /* now remove from the various maps  done and currently editing map*/
00345     if (m_transactions.contains( tid ) )
00346         m_ids.remove( m_transactions[tid]  );
00347     if (m_done.contains( tid ) )
00348         m_doneIds.remove( m_done[tid ]  );
00349     m_done.remove( tid );
00350     m_transactions.remove( tid );
00351 
00352     next( 0 );
00353 }
00354 
00362 template<class Dialog, class Record, typename Id>
00363 void OModalHelper<Dialog, Record, Id>::connectDone( QObject* rec, const char* slot )
00364 {
00365     QObject::connect(m_signal, SIGNAL(done(int, TransactionID) ),
00366                      rec, slot );
00367 }
00368 
00376 template<class Dialog, class Record, typename Id>
00377 void OModalHelper<Dialog, Record, Id>::connectAccepted( QObject* rec, const char* slot )
00378 {
00379     QObject::connect(m_signal, SIGNAL(accepted(TransactionID) ),
00380                      rec, slot );
00381 }
00382 
00391 template<class Dialog, class Record, typename Id>
00392 void OModalHelper<Dialog, Record, Id>::connectRejected( QObject* rec, const char* slot )
00393 {
00394     QObject::connect(m_signal, SIGNAL(rejected(TransactionID) ),
00395                      rec, slot );
00396 }
00397 
00413 template<class Dialog, class Record, typename Id>
00414 TransactionID OModalHelper<Dialog, Record, Id>::handle( Id id, const Record& rec )
00415 {
00416     static TransactionID t_id = 0;
00417     /*
00418      *this method consists out of two parts divided each into New and Queued Mode.
00419      * Either we have the dialog already, in this case we need to highlight the widget
00420      * Or we need to add it.
00421      */
00422     TransactionID tid = 0;
00423     /* we already have the record lets see if it was done or not */
00424     if ( !(tid = transactionID( id ) ) )
00425     {
00426         if (m_mode == New )
00427         {
00428             /* lets find the dialog and show it need to reverse map*/
00429             for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
00430                 if ( it.data() == tid )
00431                     it.key()->show();
00432         }
00433         else if (m_controler->transactionID() != tid )
00434         {
00435             int po = pos( tid );
00436             m_controler->setTransactionID( tid );
00437             static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( m_ids[ m_transactions[tid] ] );
00438             queuedDialog()->setRecord( po, m_transactions.count() );
00439         }
00440     }
00441     else
00442     {
00443         tid = ++t_id;
00444         m_transactions.insert( tid, id );
00445         m_ids.insert( id, rec );
00446 
00447         if (m_mode == New )
00448             m_editing.insert( newDialogRecord( rec ), tid );
00449         else
00450         {
00451             m_controler->setTransactionID( tid );
00452             static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( rec );
00453             queuedDialog()->setRecord( m_transactions.count(), m_transactions.count() );
00454         }
00455     }
00456     return tid;
00457 }
00458 
00470 template<class Dialog, class Record, typename Id>
00471 void OModalHelper<Dialog, Record, Id>::edited( Id id, int what, const QVariant& data )
00472 {
00473     int tid;
00474     if (!( tid = transactionID( id ) ) )
00475         return;
00476 
00477     if (m_mode == New )
00478     {
00479         for (DialogMap::Iterator it= m_editing.begin(); it != m_editing.end(); ++it )
00480             if ( it.data() == tid )
00481                 it.key()->setData( what, data );
00482     }
00483     else
00484     {
00485         int po = pos( tid );
00486         Dialog* dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
00487         dia->setRecord( m_ids[id] );
00488         dia->setData( what, data );
00489         queuedDialog()->setRecord( pos, m_transactions.count() );
00490     }
00491 }
00492 
00501 template<class Dialog, class Record, typename Id>
00502 Record OModalHelper<Dialog, Record, Id>::record( TransactionID tid)const
00503 {
00504     if (m_transactions.contains( tid ) )
00505         return m_ids[ m_transactions[tid] ];
00506     else if (m_done.contains( tid ) )
00507     {
00508         Record rec = m_doneIds[ m_done[ tid] ];
00509         m_doneIds.remove( m_done[ tid ] );
00510         m_done.remove( tid );
00511         return rec;
00512     }
00513     else
00514         return Record();
00515 }
00516 
00521 template<class Dialog, class Record, typename Id>
00522 OModalHelper<Dialog,Record,Id>::RecordList OModalHelper<Dialog, Record, Id>::recordsDone()const
00523 {
00524     RecordList list;
00525 
00526     for (IdMap::ConstIterator it = m_doneIds.begin(); it != m_doneIds.end(); ++it )
00527         list.append( it.data() );
00528 
00529     /* clean up */
00530     m_done.clear();
00531     m_doneIds.clear();
00532 
00533     return list;
00534 }
00535 
00536 
00540 template<class Dialog, class Record, typename Id>
00541 void OModalHelper<Dialog, Record, Id>::done( int status, TransactionID tid)
00542 {
00543     /* If we're in New mode the transaction Id does not count */
00544     Record rec;
00545 
00546     if (m_mode == New )
00547     {
00548         Dialog *dia = static_cast<Dialog*>( m_controler->dialog() );
00549         m_controler->setTransactionID( 0 ); // set the internal dialog to 0l again
00550         tid = m_editing[ dia ];
00551         m_editing.remove( dia );
00552         rec = dia->record();
00553         delete dia;
00554     }
00555     else
00556         rec = queuedDialog()->record();
00557 
00558     Id id = m_transactions[ tid ];
00559     if (result == QDialog::Accept )
00560     {
00561         m_doneIds.insert( is, rec  );
00562         m_done.insert( tid, id );
00563     }
00564 
00565     m_transactions.remove( tid );
00566     m_ids.remove( id );
00567 
00568 
00569     if (status == QDialog::Accept )
00570         emit m_signal->accepted( tid );
00571     else
00572         emit m_signal->rejected( tid );
00573 
00574     emit m_signal->done( result, tid );
00575 
00576     next( 0 );
00577 }
00578 
00582 template<class Dialog, class Record, typename Id>
00583 void OModalHelper<Dialog, Record, Id>::next( TransactionID tid)
00584 {
00585     if (m_mode == New )
00586         return;
00587 
00588     if (! (m_transactions.count() ) )
00589     {
00590         m_controler->setTransactionID( 0 );
00591         queuedDialog()->setRecord( 0, 0 );
00592         return;
00593     }
00594 
00595     int next;
00596     Record rec;
00597 
00598     /* save the maybe edited record before switching */
00599     Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
00600     rec = dia->record();
00601     m_ids.replace( m_transactions[tid], rec );
00602 
00603     rec = nextRecord( tid, next );
00604     queuedDialog()->setRecord( next, m_transactions.count() );
00605     dia->setRecord( rec );
00606 
00607     m_controler->setTransactionID( tid ); // was changed during the next call
00608 }
00609 
00613 /*
00614  * code duplication should create a template fcuntion
00615  * which takes a pointer to a function ( next, prev ) function
00616  */
00617 template<class Dialog, class Record, typename Id>
00618 void OModalHelper<Dialog, Record, Id>::prev( TransactionID tid )
00619 {
00620     if (m_mode == New )
00621         return;
00622 
00623     if (! (m_transactions.count()) )
00624     {
00625         m_controler->setTransactionID( 0 );
00626         queuedDialog()->setRecord( 0, 0 );
00627         return;
00628     }
00629 
00630     int prev;
00631     Record rec;
00632 
00633     /* save the maybe edited record before switching */
00634     Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() );
00635     rec = dia->record();
00636     m_ids.replace( m_transactions[tid], rec );
00637 
00638     rec = prevRecord( tid, prev );
00639     queuedDialog()->setRecord( prev, m_transactions.count() );
00640     dia->setRecord( rec );
00641 
00642     m_controler->setTransactionID( tid ); // was changed during the next call
00643 }
00644 
00648 template<class Dialog, class Record, typename Id>
00649 Record  OModalHelper<Dialog, Record, Id>::nextRecord( TransactionID &tid, int &po )
00650 {
00651     /* if tid is == 0 we will take the first one */
00652     /* pos starts at 1 here */
00653     /* we know we're only called if there are records */
00654     Record rec;
00655     TransactionMap::Iterator it;
00656     if (!tid )
00657     {
00658         po = 1;
00659         TransactionMap::Iterator it = m_transactions.begin();
00660     }
00661     else
00662     {
00663         po = pos( tid );
00664         /* if it is the last take the first as next */
00665         if ( po == m_transactions.count() )
00666         {
00667             po = 1;
00668             it = m_transactions.begin();
00669         }
00670         else
00671         {
00672             /* we know we're not the last and there is one after us */
00673             it = m_transactions.find( tid );
00674             ++it; ++po;
00675         }
00676     }
00677 
00678     tid = it.key();
00679     rec = m_ids[ tid ];
00680     return rec;
00681 }
00682 
00686 template<class Dialog, class Record, typename Id>
00687 Record OModalHelper<Dialog, Record, Id>::prevRecord( TransactionID& tid, int& pos )
00688 {
00689     /* if tid is == 0 we will take the first one */
00690     /* pos starts at 1 here */
00691     /* we know we're only called if there are records */
00692     Record rec;
00693     TransactionMap::Iterator it;
00694     if (!tid )
00695     {
00696         po = 1;
00697         TransactionMap::Iterator it = m_transactions.begin();
00698     }
00699     else
00700     {
00701         po = pos( tid );
00702         /* if it is the last take the first as next */
00703         if ( po == 1 )
00704         {
00705             po = m_transactions.count();
00706             it = m_transactions.end();
00707             --it;
00708         }
00709         else
00710         {
00711             /* we know we're not the first and there is one before us */
00712             it = m_transactions.find( tid );
00713             --it; --po;
00714         }
00715     }
00716 
00717     tid = it.key();
00718     rec = m_ids[ tid ];
00719     return rec;
00720 }
00721 
00725 template<class Dialog, class Record, typename Id>
00726 int OModalHelper<Dialog, Record, Id>::pos( TransactionID id)const
00727 {
00728     int i = 1;
00729     for ( TransactionMap::ConstIterator it = m_transactions.begin(); it != m_transactions.end(); ++it, i++ )
00730         if ( it.key() == id )
00731             return i;
00732 
00733 
00734     return 0;
00735 }
00736 
00740 template<class Dialog, class Record, typename Id>
00741 Dialog* OModalHelper<Dialog, Record, Id>::newDialogRecord( const Record& rec )
00742 {
00743     Dialog* dia = new Dialog;
00744     dia->setRecord( rec );
00745     dia->setDisabled( m_disabled );
00746 
00747     QObject::connect(dia, SIGNAL(done(int) ),
00748                      m_controler, SLOT(done(int) ) );
00749 
00750     /* FIXME big screen QPEApplication needs fixed*/
00751     dia->show();
00752 }
00753 
00754 template<class Record, class Dialog, typename Id>
00755 OModalHelperDialog* OModalHelper<Record, Dialog, Id>::queuedDialog()const
00756 {
00757     if (!m_dialog )
00758     {
00759         m_dialog = new OModalHelperDialog;
00760         m_dialog->setEnabled( m_disabled );
00761 
00762         QObject::connect(m_dialog, SIGNAL(done(int) ),
00763                          m_controler, SLOT(done(int) ) );
00764         QObject::connect(m_dialog, SIGNAL(next() ),
00765                          m_controler, SLOT(next() ) );
00766         QObject::connect(m_dialog, SIGNAL(prev() ),
00767                          m_controler, SLOT(prev() ) );
00768     }
00769     return m_dialog;
00770 }
00771 
00772 };
00773 
00774 #endif

Generated on Sat Nov 5 16:16:24 2005 for OPIE by  doxygen 1.4.2