-rw-r--r-- | libopie/big-screen/omodalhelper.cpp | 7 | ||||
-rw-r--r-- | libopie/big-screen/omodalhelper.h | 377 |
2 files changed, 346 insertions, 38 deletions
diff --git a/libopie/big-screen/omodalhelper.cpp b/libopie/big-screen/omodalhelper.cpp index e3d1c70..c5a47b3 100644 --- a/libopie/big-screen/omodalhelper.cpp +++ b/libopie/big-screen/omodalhelper.cpp @@ -76,7 +76,7 @@ void OModalHelperControler::done( int result ) { if ( sender() && !sender()->isA("OModalQueuedDialog") ) m_dia = static_cast<QDialog*>( sender() ); - m_base->done( m_id ); + m_base->done( result, m_id ); } void OModalHelperControler::next() { @@ -155,6 +155,11 @@ void OModalQueuedDialog::setRecord( int record, int count ) { }else show(); + if ( count > 1 ) + m_bar->show(); + else + m_bar->hide(); + m_bar->setText( tr("Editing record %1 out of %2", "Shows the current edited record out of an array of records").arg( record ). arg( count ) ); } diff --git a/libopie/big-screen/omodalhelper.h b/libopie/big-screen/omodalhelper.h index bc20d10..78a2ac9 100644 --- a/libopie/big-screen/omodalhelper.h +++ b/libopie/big-screen/omodalhelper.h @@ -33,6 +33,7 @@ #include <qwidget.h> #include <qvaluelist.h> #include <qmap.h> +#include <qvariant.h> typedef int TransactionID; @@ -41,7 +42,7 @@ class OModalHelperSignal; class QDialog; struct OModalHelperBase { - virtual void done( TransactionID ) = 0; + virtual void done( int status, TransactionID ) = 0; virtual void next( TransactionID ) = 0; virtual void prev( TransactionID ) = 0; }; @@ -84,6 +85,8 @@ public: bool handles( Id id)const; TransactionID transactionID( Id id)const; + void suspend( bool = true ); + void cancel(); void cancel( TransactionID ); @@ -93,17 +96,19 @@ public: TransactionID handle( Id id, const Record& rec = Record() ); - void edited( TransactionID, int what, const QString& data ); + void edited( Id, int what, const QVariant& data ); Record record( TransactionID )const; - RecordList done()const; + RecordList recordsDone()const; private: - virtual void done( TransactionID ); + virtual void done( int, TransactionID ); virtual void next( TransactionID ); virtual void prev( TransactionID ); - Record nextRecord( TransactionID, int * )const; - Record prevRecord( TransactionID, int * )const; + Record nextRecord( TransactionID &, int & )const; + Record prevRecord( TransactionID &, int & )const; + int pos( TransactionID )const; + Dialog* newDialogRecord( const Record& ); private: OModalHelperDialog *queuedDialog()const; // generate or recycle @@ -116,6 +121,7 @@ private: TransactionMap m_done; // done and waiting for getting picked DialogMap m_editing; // only used for New Mode enum Mode m_mode; // the mode we're in + bool m_disabled :1; }; @@ -205,10 +211,10 @@ private: */ template<class Dialog, class Record, typename Id> OModalHelper<Dialog, Record, Id>::OModalHelper( enum Mode mode, QObject* parent ) { + m_disabled = false; m_mode = mode; m_signal = new OModalHelperSignal( this, parent ); m_controler = new OModalHelperControler( this, m_signal ); - } @@ -240,15 +246,34 @@ bool OModalHelper<Dialog, Record, Id>::handles( Id id )const { */ template<class Dialog, class Record, typename Id> TransactionID OModalHelper<Dialog, Record, Id>::transactionID( Id id)const { - if ( m_transactions.isEmpty() ) - return false; + if ( m_transactions.isEmpty() || !m_ids.contains( id ) ) + return 0; TransactionMap::ConstIterator it = m_transactions.begin(); for ( ; it != m_transactions.end(); ++it ) if ( it.data() == id ) - return true; + return it.key(); - return false; + return 0; +} + +/** + * If you're requested to flush your data and you do not want + * to call cancel with this method you can disable and enabled + * all dialogs. + * The state gets saved so if you want to handle a new record the dialog + * will be disabled as well. + * + * @param sus If true setDisabled(TRUE) will be called otherwise FALSE + */ +template<class Dialog, class Record, typename Id> +void OModalHelper<Dialog, Record, Id>::suspend(bool sus) { + m_disabled = sus; + if (m_mode == New ) + for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it ) + it.key()->setDisabled( sus ); + else if (m_dialog ) + queuedDialog()->setDisabled( sus ); } /** @@ -268,11 +293,12 @@ void OModalHelper<Dialog, Record, Id>::cancel() { if (m_mode == New && !m_editing.isEmpty() ) { for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it ) delete it.key(); + m_editing.clear(); }else if (m_dialog ) queuedDialog()->setRecord( 0, 0 ); - m_controler->setTransactionID( -1 ); + m_controler->setTransactionID( 0 ); } @@ -295,34 +321,16 @@ void OModalHelper::cancel( TransactionID tid ) { it = m_editing.remove( it ); break; } - else if ( m_transactions.contains( tid ) ) { - /* need to stop editing from the queue block */ - /* if we're currently editing actiavte the previous */ -#if 0 - if (tid == m_controler->transactionID() ) { - } -#endif - /* now either activate the previous again or hide */ - if (! m_transactions.count() -1 ) - queuedDialog()->setRecord( 0, 0 ); - else { - int pos; - Record rec = prevRecord( tid, &pos ); - static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( rec ); - queuedDialog()->setRecord( pos, m_transactions.count() ); - m_controler->setTransactionID( tid ); - } - } /* now remove from the various maps done and currently editing map*/ if (m_transactions.contains( tid ) ) m_ids.remove( m_transactions[tid] ); if (m_done.contains( tid ) ) m_doneIds.remove( m_done[tid ] ); - - m_done.remove( tid ); m_transactions.remove( tid ); + + next( 0 ); } /** @@ -383,7 +391,6 @@ void OModalHelper<Dialog, Record, Id>::connectRejected( QObject* rec, const char template<class Dialog, class Record, typename Id> TransactionID OModalHelper<Dialog, Record, Id>::handle( Id id, const Record& rec ) { static TransactionID t_id = 0; - t_id++; /* *this method consists out of two parts divided each into New and Queued Mode. * Either we have the dialog already, in this case we need to highlight the widget @@ -391,15 +398,311 @@ TransactionID OModalHelper<Dialog, Record, Id>::handle( Id id, const Record& rec */ TransactionID tid = 0; /* we already have the record lets see if it was done or not */ - if ( m_ids.contains( id ) ) { + if ( !(tid = transactionID( id ) ) ) { + if (m_mode == New ) { + /* lets find the dialog and show it need to reverse map*/ + for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it ) + if ( it.data() == tid ) + it.key()->show(); + }else if (m_controler->transactionID() != tid ) { + int po = pos( tid ); + m_controler->setTransactionID( tid ); + static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( m_ids[ m_transactions[tid] ] ); + queuedDialog()->setRecord( po, m_transactions.count() ); + } + }else { + tid = ++t_id; + m_transactions.insert( tid, id ); + m_ids.insert( id, rec ); + + if (m_mode == New ) + m_editing.insert( newDialogRecord( rec ), tid ); + else{ + m_controler->setTransactionID( tid ); + static_cast<Dialog*>( queuedDialog()->centerDialog() )->setRecord( rec ); + queuedDialog()->setRecord( m_transactions.count(), m_transactions.count() ); + } + } + return tid; +} +/** + * The goal of this helper is to help you to create non blocking + * GUIs. In the example of the todolist you can have the edit dialog + * but still change the priority or completion inline even if you currently + * edit the record. + * Your Dialog needs to have a Method setData(int,const QVariant& ) which will be called + * in these cases. + * If you edit anything while a record is edited call this function to merge the + * change in. Note if the record is not handled here we will ignore the request + * + */ +template<class Dialog, class Record, typename Id> +void OModalHelper<Dialog, Record, Id>::edited( Id id, int what, const QVariant& data ) { + int tid; + if (!( tid = transactionID( id ) ) ) + return; + + if (m_mode == New ) { + for (DialogMap::Iterator it= m_editing.begin(); it != m_editing.end(); ++it ) + if ( it.data() == tid ) + it.key()->setData( what, data ); + }else{ + int po = pos( tid ); + Dialog* dia = static_cast<Dialog*>( queuedDialog()->centerDialog() ); + dia->setRecord( m_ids[id] ); + dia->setData( what, data ); + queuedDialog()->setRecord( pos, m_transactions.count() ); + } +} + +/** + * This functions either returns the unedited record the done record + * or a new empty Record using Record(). + * If a done record is retrieved all traces are removed inside this class. This + * is what was called popping a record. This means when you call this function + * with the same TransactionID an Empty record is retrieved. + * + */ +template<class Dialog, class Record, typename Id> +Record OModalHelper<Dialog, Record, Id>::record( TransactionID tid)const { + if (m_transactions.contains( tid ) ) + return m_ids[ m_transactions[tid] ]; + else if (m_done.contains( tid ) ) { + Record rec = m_doneIds[ m_done[ tid] ]; + m_doneIds.remove( m_done[ tid ] ); + m_done.remove( tid ); + return rec; + }else + return Record(); +} + +/** + * Returns all done Records and removes all references to them internally. A 2nd call to this will + * only contain done record that where edited past the point + */ +template<class Dialog, class Record, typename Id> +OModalHelper<Dialog,Record,Id>::RecordList OModalHelper<Dialog, Record, Id>::recordsDone()const { + RecordList list; + + for (IdMap::ConstIterator it = m_doneIds.begin(); it != m_doneIds.end(); ++it ) + list.append( it.data() ); + + /* clean up */ + m_done.clear(); + m_doneIds.clear(); + + return list; +} + + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +void OModalHelper<Dialog, Record, Id>::done( int status, TransactionID tid) { +/* If we're in New mode the transaction Id does not count */ + Record rec; + + if (m_mode == New ) { + Dialog *dia = static_cast<Dialog*>( m_controler->dialog() ); + m_controler->setTransactionID( 0 ); // set the internal dialog to 0l again + tid = m_editing[ dia ]; + m_editing.remove( dia ); + rec = dia->record(); + delete dia; + }else + rec = queuedDialog()->record(); + + Id id = m_transactions[ tid ]; + if (result == QDialog::Accept ) { + m_doneIds.insert( is, rec ); + m_done.insert( tid, id ); } - /* fall through if the record is in the done list */ - tid = t_id; + m_transactions.remove( tid ); + m_ids.remove( id ); + + if (status == QDialog::Accept ) + emit m_signal->accepted( tid ); + else + emit m_signal->rejected( tid ); - return; + emit m_signal->done( result, tid ); + + next( 0 ); +} + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +void OModalHelper<Dialog, Record, Id>::next( TransactionID tid) { + if (m_mode == New ) + return; + + if (! (m_transactions.count() ) ) { + m_controler->setTransactionID( 0 ); + queuedDialog()->setRecord( 0, 0 ); + return; + } + + int next; + Record rec; + + /* save the maybe edited record before switching */ + Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() ); + rec = dia->record(); + m_ids.replace( m_transactions[tid], rec ); + + rec = nextRecord( tid, next ); + queuedDialog()->setRecord( next, m_transactions.count() ); + dia->setRecord( rec ); + + m_controler->setTransactionID( tid ); // was changed during the next call +} + +/** + * @internal + */ +/* + * code duplication should create a template fcuntion + * which takes a pointer to a function ( next, prev ) function + */ +template<class Dialog, class Record, typename Id> +void OModalHelper<Dialog, Record, Id>::prev( TransactionID tid ) { + if (m_mode == New ) + return; + + if (! (m_transactions.count()) ) { + m_controler->setTransactionID( 0 ); + queuedDialog()->setRecord( 0, 0 ); + return; + } + + int prev; + Record rec; + + /* save the maybe edited record before switching */ + Dialog *dia = static_cast<Dialog*>( queuedDialog()->centerDialog() ); + rec = dia->record(); + m_ids.replace( m_transactions[tid], rec ); + + rec = prevRecord( tid, prev ); + queuedDialog()->setRecord( prev, m_transactions.count() ); + dia->setRecord( rec ); + + m_controler->setTransactionID( tid ); // was changed during the next call +} + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +Record OModalHelper<Dialog, Record, Id>::nextRecord( TransactionID &tid, int &po ) { + /* if tid is == 0 we will take the first one */ + /* pos starts at 1 here */ + /* we know we're only called if there are records */ + Record rec; + TransactionMap::Iterator it; + if (!tid ) { + po = 1; + TransactionMap::Iterator it = m_transactions.begin(); + }else{ + po = pos( tid ); + /* if it is the last take the first as next */ + if ( po == m_transactions.count() ) { + po = 1; + it = m_transactions.begin(); + }else { + /* we know we're not the last and there is one after us */ + it = m_transactions.find( tid ); + ++it; ++po; + } + } + + tid = it.key(); + rec = m_ids[ tid ]; + return rec; +} + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +Record OModalHelper<Dialog, Record, Id>::prevRecord( TransactionID& tid, int& pos ) { + /* if tid is == 0 we will take the first one */ + /* pos starts at 1 here */ + /* we know we're only called if there are records */ + Record rec; + TransactionMap::Iterator it; + if (!tid ) { + po = 1; + TransactionMap::Iterator it = m_transactions.begin(); + }else{ + po = pos( tid ); + /* if it is the last take the first as next */ + if ( po == 1 ) { + po = m_transactions.count(); + it = m_transactions.end(); + --it; + }else { + /* we know we're not the first and there is one before us */ + it = m_transactions.find( tid ); + --it; --po; + } + } + + tid = it.key(); + rec = m_ids[ tid ]; + return rec; +} + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +int OModalHelper<Dialog, Record, Id>::pos( TransactionID id)const { + int i = 1; + for ( TransactionMap::ConstIterator it = m_transactions.begin(); it != m_transactions.end(); ++it, i++ ) + if ( it.key() == id ) + return i; + + + return 0; +} + +/** + * @internal + */ +template<class Dialog, class Record, typename Id> +Dialog* OModalHelper<Dialog, Record, Id>::newDialogRecord( const Record& rec ) { + Dialog* dia = new Dialog; + dia->setRecord( rec ); + dia->setDisabled( m_disabled ); + + QObject::connect(dia, SIGNAL(done(int) ), + m_controler, SLOT(done(int) ) ); + + /* FIXME big screen QPEApplication needs fixed*/ + dia->show(); +} + +template<class Record, class Dialog, typename Id> +OModalHelperDialog* OModalHelper<Record, Dialog, Id>::queuedDialog()const{ + if (!m_dialog ) { + m_dialog = new OModalHelperDialog; + m_dialog->setEnabled( m_disabled ); + + QObject::connect(m_dialog, SIGNAL(done(int) ), + m_controler, SLOT(done(int) ) ); + QObject::connect(m_dialog, SIGNAL(next() ), + m_controler, SLOT(next() ) ); + QObject::connect(m_dialog, SIGNAL(prev() ), + m_controler, SLOT(prev() ) ); + } + return m_dialog; } #endif |