summaryrefslogtreecommitdiff
authorzecke <zecke>2003-09-13 15:04:36 (UTC)
committer zecke <zecke>2003-09-13 15:04:36 (UTC)
commit6b4c7e5d9f5c21bf044afb260fcfa066e86c12a1 (patch) (side-by-side diff)
tree736f68df631447b88768cb8f080306e78ae3cd20
parent14db240e82c6208277946c6a76fe1d41615d6804 (diff)
downloadopie-6b4c7e5d9f5c21bf044afb260fcfa066e86c12a1.zip
opie-6b4c7e5d9f5c21bf044afb260fcfa066e86c12a1.tar.gz
opie-6b4c7e5d9f5c21bf044afb260fcfa066e86c12a1.tar.bz2
The rest of the implementation.
Theoretically you could use it, now writing the example and then finally compile that sucker for the 1st time
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/big-screen/omodalhelper.cpp7
-rw-r--r--libopie/big-screen/omodalhelper.h377
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
@@ -67,25 +67,25 @@ void OModalHelperControler::setTransactionID( TransactionID id ) {
QDialog* OModalHelperControler::dialog()const {
return m_dia;
}
/*
* If we're in the New mode we will map the QDialog
* to the TransactionID
*/
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() {
m_base->next( m_id );
}
void OModalHelperControler::prev() {
m_base->prev( m_id );
}
/* The Queued Dialog inclusive QueuedBar */
struct OModalQueueBar : public QHBox {
@@ -146,15 +146,20 @@ void OModalQueuedDialog::setQueueBarEnabled( bool b) {
m_bar->show();
else
m_bar->hide();
}
void OModalQueuedDialog::setRecord( int record, int count ) {
if (!record && !count ) {
hide();
return;
}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
@@ -24,33 +24,34 @@
Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef HAZE_OMODAL_HELPER_H
#define HAZE_OMODAL_HELPER_H
#include <qdialog.h>
#include <qwidget.h>
#include <qvaluelist.h>
#include <qmap.h>
+#include <qvariant.h>
typedef int TransactionID;
class OModalHelperControler;
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;
};
/**
* Modality sucks! ;) But it is easy to work with
* do exec() on a dialog and you know everything is funky.
* You only need to have one Dialog loaded and so on.
* This class helps you to work like with modality and help
* you to keep things in sync
* It's a template class but it sends signals once one Item is ready
* the signals contains the status and id of the item and then you
@@ -75,56 +76,61 @@ class OModalHelper : private OModalHelperBase{
friend class OModalHelperControler;
public:
typedef QValueList<Record> RecordList;
typedef QMap<Id, Record> IdMap;
typedef QMap<TransactionID, Id> TransactionMap;
typedef QMap<QDialog*, TransactionID> DialogMap
enum Mode { Queue, New };
OModalHelper(enum Mode mode, QObject* parnet );
bool handles( Id id)const;
TransactionID transactionID( Id id)const;
+ void suspend( bool = true );
+
void cancel();
void cancel( TransactionID );
void connectDone( QObject* rec, const char* slot );
void connectAccepted( QObject* rec, const char* slot );
void connectRejected( QObject* rec, const char* slot );
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
OModalHelperDialog *m_dialog;
OModalHelperSignal *m_signal; // our signal
OModalHelperControler *m_controler;
IdMap m_ids; // maps ids (uids) to a record
IdMap m_doneIds;
TransactionMap m_transactions; // activate transactions
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;
};
/* ### FIXME use namespace with Qt3 */
/*
* A note on flow. The Signal is used for QT Signals when
* a record is done.
* There is either one controler and this controler slot will
* be connected to a dialog signal.
* In Queue we get the next and prev signals and call the Helper.
@@ -196,28 +202,28 @@ private:
/**
* This is the simple Template c'tor. It takes the mode
* this helper should operate in and the parent object.
* This helper will be deleted when the parent gets deleted
* or you delete it yourself.
*
* @param mode The mode this dialog should be in
* @param parent The parent QObject of this helper.
*/
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 );
-
}
/**
* This functions looks for your record and sees if it is
* handled with this helper. Note that done records
* will not be returned.
*
* @return true if the record is currenlty edited otherwise false
*
* @param Id The id which might be handled
*/
@@ -231,107 +237,109 @@ bool OModalHelper<Dialog, Record, Id>::handles( Id id )const {
if ( it.data() == id )
return true;
return false;
}
/**
* just like handles( Id ) but returns the TransactionId
*/
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 );
}
/**
* Cancel will cancel all current operations and clear the list
* of done operations as well.
* This also clears all done operations you did not popped
*/
template<class Dialog, class Record, typename Id>
void OModalHelper<Dialog, Record, Id>::cancel() {
m_ids.clear();
m_doneIds.clear();
m_done.clear();
m_transactions.clear();
/* we also need to remove the QDialogs */
/* and hide the queue dialog if present */
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 );
}
/**
* This cancels editing of the record behind the Transaction Number
* Note that if editing is already done it will also be removed from this list
*/
template<class Dialog, class Record, typename Id>
void OModalHelper::cancel( TransactionID tid ) {
/* wrong tid */
if (!m_transactions.contains( tid ) && !m_done.contains( tid) )
return;
if (m_mode == New )
/* reverse map eek */
for (DialogMap::Iterator it = m_editing.begin(); it != m_editing.end(); ++it )
if ( it.data() == tid ) {
it.key()->hide();
delete it.key();
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 );
}
/**
* Connect to the done Signal. SIGNAL( done(int, TransactionID ) )
* This signal gets emitted whenever a Record was accepted or rejected
*
* @param rec The object where the slot belongs to
* @param slot The slot which should be called. See the needed parameter above
*/
template<class Dialog, class Record, typename Id>
void OModalHelper<Dialog, Record, Id>::connectDone( QObject* rec, const char* slot ) {
QObject::connect(m_signal, SIGNAL(done(int, TransactionID) ),
@@ -374,32 +382,327 @@ void OModalHelper<Dialog, Record, Id>::connectRejected( QObject* rec, const char
* In the case where the record is already present the parameter gets discarded.
* If you want the new record to be taken you need to cancel the Transaction first
*
* @param id The Identification of the Record. For PIM it would uid()
* @param rec The record we want to be edited
*
* @returns This functions returns the TransactionId assigned to the record
*
*/
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
* Or we need to add it.
*/
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