summaryrefslogtreecommitdiff
path: root/examples/simple-pim
authorzecke <zecke>2003-08-31 15:20:46 (UTC)
committer zecke <zecke>2003-08-31 15:20:46 (UTC)
commitce4a99860d28e003871994cca88a82133c1921a7 (patch) (side-by-side diff)
treeb1ad7486a1703d772d96e1aecd0a49cfcfa90959 /examples/simple-pim
parentd868ed99b6018a969239d079767925c929c71fad (diff)
downloadopie-ce4a99860d28e003871994cca88a82133c1921a7.zip
opie-ce4a99860d28e003871994cca88a82133c1921a7.tar.gz
opie-ce4a99860d28e003871994cca88a82133c1921a7.tar.bz2
Add an Example showing the udage of QCOP, PIM API and
some other nice parts
Diffstat (limited to 'examples/simple-pim') (more/less context) (ignore whitespace changes)
-rw-r--r--examples/simple-pim/.cvsignore3
-rw-r--r--examples/simple-pim/config.in4
-rw-r--r--examples/simple-pim/example.pro17
-rw-r--r--examples/simple-pim/opie-simple.control9
-rw-r--r--examples/simple-pim/simple.cpp445
-rw-r--r--examples/simple-pim/simple.h95
6 files changed, 573 insertions, 0 deletions
diff --git a/examples/simple-pim/.cvsignore b/examples/simple-pim/.cvsignore
new file mode 100644
index 0000000..da6fea3
--- a/dev/null
+++ b/examples/simple-pim/.cvsignore
@@ -0,0 +1,3 @@
+.moc
+.obj
+Makefile \ No newline at end of file
diff --git a/examples/simple-pim/config.in b/examples/simple-pim/config.in
new file mode 100644
index 0000000..5d80f21
--- a/dev/null
+++ b/examples/simple-pim/config.in
@@ -0,0 +1,4 @@
+ config SIMPLE_PIM_EXAMPLE
+ boolean "Mainwindow with PIM and QCOP usage"
+ default "y"
+ depends ( LIBQPE || LIBQPE-X11 ) && EXAMPLES && LIBOPIE
diff --git a/examples/simple-pim/example.pro b/examples/simple-pim/example.pro
new file mode 100644
index 0000000..c3aab53
--- a/dev/null
+++ b/examples/simple-pim/example.pro
@@ -0,0 +1,17 @@
+CONFIG += qt warn_on quick-app
+
+
+TARGET = simple-pim
+
+HEADERS = simple.h
+SOURCES = simple.cpp
+
+
+INCLUDEPATH += $(OPIEDIR)/include
+DEPENDPATH += $(OPIEDIR)/include
+
+
+# we now also include opie
+LIBS += -lqpe -lopie
+
+include ( $(OPIEDIR)/include.pro )
diff --git a/examples/simple-pim/opie-simple.control b/examples/simple-pim/opie-simple.control
new file mode 100644
index 0000000..8416ad2
--- a/dev/null
+++ b/examples/simple-pim/opie-simple.control
@@ -0,0 +1,9 @@
+Package: opie-main-tab-example
+Files: bin/main-tab apps/Examples/main-tab.desktop
+Priority: optional
+Section: opie/applications
+Maintainer: Holger 'zecke' Freyther <zecke@handhelds.org>
+Architecture: arm
+Depends: task-opie-minimal, opie-pics
+Description: A simple example
+Version: $QPE_VERSION$EXTRAVERSION
diff --git a/examples/simple-pim/simple.cpp b/examples/simple-pim/simple.cpp
new file mode 100644
index 0000000..3e9fcd3
--- a/dev/null
+++ b/examples/simple-pim/simple.cpp
@@ -0,0 +1,445 @@
+#include <qaction.h> // action
+#include <qmenubar.h> // menubar
+#include <qtoolbar.h> // toolbar
+#include <qlabel.h> // a label
+#include <qpushbutton.h> // the header file for the QPushButton
+#include <qlayout.h>
+#include <qtimer.h> // we use it for the singleShot
+#include <qdatetime.h> // for QDate
+#include <qtextview.h> // a rich text widget
+#include <qdialog.h>
+#include <qwhatsthis.h> // for whats this
+
+#include <qpe/qpeapplication.h> // the QPEApplication
+#include <qpe/resource.h>
+#include <qpe/sound.h>
+#include <qpe/qcopenvelope_qws.h>
+#include <qpe/datebookmonth.h>
+#include <qpe/timestring.h>
+
+#include <opie/oapplicationfactory.h> // a template + macro to save the main method and allow quick launching
+#include <opie/otabwidget.h>
+#include <opie/owait.h>
+
+#include "simple.h"
+
+/*
+ * implementation of simple
+ */
+
+/*
+ * The factory is used for quicklaunching
+ * It needs a constructor ( c'tor ) with at least QWidget, const char* and WFlags as parameter and a static QString appName() matching the TARGET of the .pro
+ *
+ * Depending on the global quick launch setting this will create
+ * either a main method or one for our component plugin system
+ */
+
+OPIE_EXPORT_APP( OApplicationFactory<MainWindow> )
+
+MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl )
+ : QMainWindow( parent, name, fl ) {
+ setCaption(tr("My MainWindow") );
+
+ m_desktopChannel = 0;
+ m_loading = 0;
+
+ initUI();
+
+
+ /*
+ * Tab widget as central
+ */
+ m_tab = new OTabWidget(this);
+
+ setCentralWidget( m_tab );
+
+ m_todoView = new PIMListView(m_tab, "Todo view" );
+ m_tab->addTab( m_todoView,"todo/TodoList", tr("Todos") );
+
+ m_dateView = new PIMListView(m_tab, "Datebook view" );
+ m_tab->addTab( m_dateView, "datebook/DateBook", tr("Events") );
+
+ /* now connect the actions */
+ /*
+ * we connect the activated to our show
+ * and on activation we will show a detailed
+ * summary of the record
+ */
+ connect(m_fire, SIGNAL(activated() ),
+ this, SLOT(slotShow() ) );
+
+ /*
+ * We will change the date
+ */
+ connect(m_dateAction, SIGNAL(activated() ),
+ this, SLOT(slotDate() ) );
+
+ /*
+ * connect the show signal of the PIMListView
+ * to a slot to show a dialog
+ */
+ connect(m_todoView, SIGNAL(showRecord(const OPimRecord& ) ),
+ this, SLOT(slotShowRecord(const OPimRecord& ) ) );
+ connect(m_dateView, SIGNAL(showRecord(const OPimRecord& ) ),
+ this, SLOT(slotShowRecord(const OPimRecord& ) ) );
+
+ /*
+ * Now comes the important lines of code for this example
+ * We do not directly call load but delay loading until
+ * all Events are dispatches and handled.
+ * SO we will load once our window is mapped to screen
+ * to achieve that we use a QTimer::singleShot
+ * After 10 milli seconds the timer fires and on TimerEvent
+ * out slot slotLoad will be called
+ * Remember this a Constructor to construct your object and not
+ * to load
+ */
+ QTimer::singleShot( 10, this, SLOT(slotLoad() ) );
+}
+
+MainWindow::~MainWindow() {
+ // again nothing to delete because Qt takes care
+}
+
+
+void MainWindow::setDocument( const QString& /*str*/ ) {
+}
+
+
+void MainWindow::initUI() {
+
+ setToolBarsMovable( false );
+
+ QToolBar *menuBarHolder = new QToolBar( this );
+
+ menuBarHolder->setHorizontalStretchable( true );
+ QMenuBar *mb = new QMenuBar( menuBarHolder );
+ QToolBar *tb = new QToolBar( this );
+
+ QPopupMenu *fileMenu = new QPopupMenu( this );
+
+
+ QAction *a = new QAction( tr("Quit"), Resource::loadIconSet("quit_icon"),
+ QString::null, 0, this, "quit_action" );
+ /*
+ * Connect quit to the QApplication quit slot
+ */
+ connect(a, SIGNAL(activated() ),
+ qApp, SLOT(quit() ) );
+ a->addTo( fileMenu );
+
+ a = new QAction(tr("View Current"),
+ Resource::loadIconSet("zoom"),
+ QString::null, 0, this, "view current");
+ /* a simple whats this online explanation of out button */
+ a->setWhatsThis(tr("Views the current record") );
+ /* or QWhatsThis::add(widget, "description" ); */
+
+ /* see the power? */
+ a->addTo( fileMenu );
+ a->addTo( tb );
+ m_fire = a;
+
+ a = new QAction(tr("Choose Date"),
+ Resource::loadIconSet("day"),
+ QString::null, 0, this, "choose date" );
+ a->addTo( fileMenu );
+ a->addTo( tb );
+ m_dateAction = a;
+
+ mb->insertItem(tr("File"), fileMenu );
+
+}
+
+void MainWindow::slotLoad() {
+ /*
+ * There is no real shared access in the PIM API
+ * It wasn't finish cause of health problems of one
+ * of the authors so we do something fancy and use QCOP
+ * the IPC system to get a current copy
+ */
+ /* NOTES to QCOP: QCOP operates over channels and use QDataStream
+ * to send data. You can check if a channel isRegistered or hook
+ * yourself to that channel. A Channel is QCString and normally
+ * prefix with QPE/ and then the system in example QPE/System,
+ * QPE/Desktop a special channel is the application channel
+ * it QPE/Application/appname this channel gets created on app
+ * startup by QPEApplication. QCOP is asynchronous
+ *
+ * To send you'll use QCopEnevelope
+ *
+ */
+ /*
+ * What we will do is first is get to know if either
+ * datebook or todolist are running if so we will kindly
+ * asked to save the data for us.
+ * If neither are running we can load directly
+ */
+ if (!QCopChannel::isRegistered("QPE/Application/todolist") &&
+ !QCopChannel::isRegistered("QPE/Application/datebook") ) {
+ m_db.load();
+ m_tb.load();
+ return slotLoadForDay( QDate::currentDate() );
+ }
+
+ /*
+ * prepare our answer machine the QCopChannel
+ * QPE/Desktop will send "flushDone(QString)" when
+ * the flush is done it emits a signal on receive
+ */
+ m_desktopChannel = new QCopChannel("QPE/Desktop");
+ connect(m_desktopChannel, SIGNAL(received(const QCString&, const QByteArray& ) ),
+ this, SLOT(slotDesktopReceive(const QCString&, const QByteArray& ) ) );
+ /* the numberof synced channels will be set to zero */
+ m_synced = 0;
+
+ /*
+ * We use {} around the QCopEnvelope because it sends its
+ * data on destruction of QCopEnvelope with
+ */
+ /* check again if not present increment synced*/
+ if ( QCopChannel::isRegistered("QPE/Application/todolist") ) {
+ QCopEnvelope env("QPE/Application/todolist", "flush()" );
+ // env << data; but we do not have any parameters here
+ }else
+ m_synced++;
+
+ if ( QCopChannel::isRegistered("QPE/Application/datebook") ) {
+ QCopEnvelope env("QPE/Application/datebook", "flush()" );
+ }else
+ m_synced++;
+
+ /* we will provide a wait scrren */
+ m_loading = new OWait(this, "wait screen" );
+}
+
+void MainWindow::slotDesktopReceive(const QCString& cmd, const QByteArray& data ) {
+ /* the bytearray was filled with the QDataStream now
+ * we open it read only to get the value(s)
+ */
+ QDataStream stream(data, IO_ReadOnly );
+ /*
+ * we're only interested in the flushDone
+ */
+ if ( cmd == "flushDone(QString)" ) {
+ QString appname;
+ stream >> appname; // get the first argument out of stream
+ if (appname == QString::fromLatin1("datebook") ||
+ appname == QString::fromLatin1("todolist") )
+ m_synced++;
+ }
+
+ /*
+ * If we synced both we can go ahead
+ * In future this is not needed anymore when we finally
+ * implemented X-Ref and other PIM features
+ */
+ if (m_synced >= 2 ) {
+ delete m_loading;
+ delete m_desktopChannel;
+ /* now we finally can start doing the actual loading */
+ m_tb.load();
+ m_db.load();
+ {
+ /* tell the applications to reload */
+ QCopEnvelope("QPE/Application/todolist", "reload()");
+ QCopEnvelope("QPE/Application/datebook", "reload()");
+ }
+ slotLoadForDay( QDate::currentDate() );
+ }
+
+}
+
+/* overloaded member for shortcoming of libqpe */
+void MainWindow::slotLoadForDay(int y, int m, int d) {
+ /* year,month, day */
+ slotLoadForDay( QDate(y, m, d ) );
+}
+
+void MainWindow::slotLoadForDay(const QDate& date) {
+
+
+ /* all todos for today including the ones without dueDate */
+ m_todoView->set( m_tb.effectiveToDos(date, date ) );
+ m_dateView->set( m_db.effectiveEvents( date, date ) );
+}
+
+/* we want to show the current record */
+void MainWindow::slotShow() {
+ /* we only added PIMListViews so we can safely cast */
+ PIMListView *view = static_cast<PIMListView*>(m_tab->currentWidget() );
+
+ /* ask the view to send a signal */
+ view->showCurrentRecord();
+
+}
+
+/* as answer this slot will be called */
+void MainWindow::slotShowRecord( const OPimRecord& rec) {
+ /* got a parent but still is a toplevel MODAL dialog */
+ QDialog* dia = new QDialog(this,"dialog",TRUE );
+ QVBoxLayout *box = new QVBoxLayout( dia );
+ dia->setCaption( tr("View Record") );
+
+
+ QTextView *view = new QTextView(dia );
+ view->setText( rec.toRichText() );
+ box->addWidget( view );
+ /*
+ * execute via QPEApplication
+ * this allows QPEApplication to make a sane decision
+ * on the size
+ */
+ dia->showMaximized();
+ QPEApplication::execDialog( dia );
+ delete dia;
+}
+
+
+void MainWindow::slotDate() {
+ /*
+ * called by the action we will show a Popup
+ * at the current mouse position with a DateChooser
+ * to select the day
+ */
+ qWarning("slot Date");
+ QPopupMenu *menu = new QPopupMenu();
+ /* A Month to select a date from TRUE for auto close */
+ DateBookMonth *month = new DateBookMonth(menu, 0, true );
+ connect(month, SIGNAL(dateClicked(int, int, int) ),
+ this, SLOT(slotLoadForDay(int, int, int) ) );
+
+ menu->insertItem( month );
+
+ menu->exec( QCursor::pos() );
+
+ /*
+ * we do not need to delete month because
+ * we delete its parent menu
+ */
+
+ delete menu;
+}
+
+/*
+ * An anonymous namespace this symbol is only available here
+ * so truely private
+ */
+namespace {
+ /* not static cause namespace does that what static would do */
+ const int RTTI = 5050;
+ /*
+ * every ListView got Items. we've special pim items
+ * holding ownership and the pointer to a pim record
+ * it can't hold a pimrecord directly because this
+ * would introduce slicing... any break
+ */
+ /*
+ * A struct is a special class. Everything is public by
+ * default.
+ */
+ struct PIMListViewItem : public QListViewItem {
+ /*
+ *currently no hierachies are planed for the example
+ * so only one constructor with a QListView as parent
+ */
+ PIMListViewItem( QListView*, OPimRecord* record );
+ ~PIMListViewItem();
+
+ /* used by the QListViewItem to easily allow identifiying of different
+ * items. Values greater than 1000 should be used */
+ int rtti()const;
+ OPimRecord* record()const;
+
+ private:
+ OPimRecord* m_record;
+ };
+
+ PIMListViewItem::PIMListViewItem( QListView *p, OPimRecord* rec )
+ : QListViewItem(p), m_record( rec ) {
+ }
+
+ PIMListViewItem::~PIMListViewItem() {
+ /* we've the onwership so we need to delete it */
+ delete m_record;
+ }
+
+ OPimRecord* PIMListViewItem::record()const {
+ return m_record;
+ }
+
+}
+
+
+PIMListView::PIMListView( QWidget* widget, const char* name, WFlags fl )
+ : QListView(widget, name, fl )
+{
+ addColumn("Summary");
+}
+
+PIMListView::~PIMListView() {
+
+}
+
+void PIMListView::set( OTodoAccess::List list ) {
+ /* clear first and then add new items */
+ clear();
+
+ OTodoAccess::List::Iterator it;
+ for (it = list.begin(); it != list.end(); ++it ) {
+ /*
+ * make a new item which automatically gets added to the listview
+ * and call the copy c'tor to create a new OTodo
+ */
+ PIMListViewItem *i = new PIMListViewItem(this, new OTodo( *it ) );
+ i->setText(0, (*it).summary() );
+ }
+}
+
+void PIMListView::set( const OEffectiveEvent::ValueList& lst ) {
+ /* clear first and then add items */
+ clear();
+
+ OEffectiveEvent::ValueList::ConstIterator it;
+ for ( it = lst.begin(); it != lst.end(); ++it ) {
+ PIMListViewItem *i = new PIMListViewItem(this, new OEvent( (*it).event() ) );
+ i->setText( 0, PIMListView::makeString( (*it) ) );
+ }
+
+}
+
+void PIMListView::showCurrentRecord() {
+ /* it could be possible that their is no currentItem */
+ if (!currentItem() )
+ return;
+
+ /*
+ * we only add PIMListViewItems so it is save
+ * to do this case. If this would not be the case
+ * use rtti() to check in a switch() case
+ */
+ PIMListViewItem *item = static_cast<PIMListViewItem*>( currentItem() );
+
+ /* finally you see how to emit a signal */
+ emit showRecord( (*item->record() ) );
+}
+
+QString PIMListView::makeString( const OEffectiveEvent& ev ) {
+ QString str;
+ str += ev.description();
+ if ( !ev.event().isAllDay() ) {
+ if ( ev.startDate() != ev.endDate() ) {
+ str += tr("Start ") + TimeString::timeString( ev.event().startDateTime().time() );
+ str += " - " + TimeString::longDateString( ev.startDate() );
+ str += tr("End ") + TimeString::timeString( ev.event().endDateTime().time() );
+ str += " - " + TimeString::longDateString( ev.endDate() );
+ }else{
+ str += tr("Time ") + TimeString::timeString( ev.startTime() );
+ str += " - " + TimeString::timeString( ev.endTime() );
+ }
+ }else
+ str += tr(" This is an All-Day Event");
+
+ return str;
+}
diff --git a/examples/simple-pim/simple.h b/examples/simple-pim/simple.h
new file mode 100644
index 0000000..bf9ede7
--- a/dev/null
+++ b/examples/simple-pim/simple.h
@@ -0,0 +1,95 @@
+
+/*
+ * A Simple widget with a button to quit
+ *
+ */
+
+/*
+ * The below sequence is called a guard and guards
+ * against multiple inclusion of header files
+ * NOTE: you need to use unique names among the header files
+ */
+#ifndef QUIET_SIMPLE_DEMO_H
+#define QUIET_SIMPLE_DEMO_H
+
+
+
+
+#include <qmainwindow.h> // from this class we will inherit
+#include <qlistview.h> // A ListView for our PIM records
+
+#include <opie/otodoaccess.h>
+#include <opie/odatebookaccess.h>
+
+class QPushButton; // forward declaration to not include the header. This can save time when compiling
+class QAction;
+class PIMListView;
+class QDate;
+class QCopChannel;
+class OWait;
+class OTabWidget;
+
+/*
+ * A mainwindow is a special QWidget it helps layouting
+ * toolbar, statusbar, menubar. Got dockable areas
+ * So in one sentence it is a MainWindow :)
+ */
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ static QString appName() { return QString::fromLatin1("simple-pim"); }
+ MainWindow( QWidget* parent, const char* name, WFlags fl );
+ ~MainWindow();
+
+public slots:
+ void setDocument( const QString& );
+private slots:
+ void slotDesktopReceive( const QCString&, const QByteArray& );
+ void slotLoad();
+ void slotLoadForDay(int, int, int );
+ void slotLoadForDay(const QDate&);
+ void slotShow();
+ void slotDate();
+ void slotShowRecord( const OPimRecord& );
+
+private:
+ void initUI();
+ QAction *m_fire;
+ QAction *m_dateAction;
+ OTabWidget* m_tab;
+
+ OTodoAccess m_tb;
+ ODateBookAccess m_db;
+ PIMListView *m_todoView;
+ PIMListView *m_dateView;
+
+ int m_synced; // a counter for synced objects..
+ QCopChannel *m_desktopChannel;
+ OWait *m_loading;
+};
+
+/*
+ * Instead of the simple QWidgets we will design
+ * a new widget based on a QListView
+ * it should show either Todos or EffectiveEvents
+ */
+class PIMListView : public QListView {
+ Q_OBJECT
+public:
+ PIMListView( QWidget* parent, const char* name, WFlags fl= 0 );
+ ~PIMListView();
+
+
+ void set( OTodoAccess::List );
+ void set( const OEffectiveEvent::ValueList& );
+ void showCurrentRecord();
+
+signals:
+ void showRecord( const OPimRecord& );
+
+private:
+ static QString makeString( const OEffectiveEvent& ev );
+
+};
+
+#endif