summaryrefslogtreecommitdiff
authorzecke <zecke>2003-08-31 15:20:46 (UTC)
committer zecke <zecke>2003-08-31 15:20:46 (UTC)
commitce4a99860d28e003871994cca88a82133c1921a7 (patch) (unidiff)
treeb1ad7486a1703d772d96e1aecd0a49cfcfa90959
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 (more/less context) (show whitespace changes)
-rw-r--r--apps/Examples/pim.desktop8
-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
-rw-r--r--packages1
8 files changed, 582 insertions, 0 deletions
diff --git a/apps/Examples/pim.desktop b/apps/Examples/pim.desktop
new file mode 100644
index 0000000..9c7988a
--- a/dev/null
+++ b/apps/Examples/pim.desktop
@@ -0,0 +1,8 @@
1[Desktop Entry]
2Exec=simple-pim
3Icon=Example
4Type=Example
5Name=Simple PIM Viewer
6Comment=An Example Program
7Name[pt]=Exemplo
8Comment[pt]=Um programa de exemplo
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 @@
1.moc
2.obj
3Makefile \ 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 @@
1 config SIMPLE_PIM_EXAMPLE
2 boolean "Mainwindow with PIM and QCOP usage"
3 default "y"
4 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 @@
1CONFIG += qt warn_on quick-app
2
3
4TARGET = simple-pim
5
6HEADERS = simple.h
7SOURCES = simple.cpp
8
9
10INCLUDEPATH += $(OPIEDIR)/include
11DEPENDPATH += $(OPIEDIR)/include
12
13
14# we now also include opie
15LIBS += -lqpe -lopie
16
17include ( $(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 @@
1Package: opie-main-tab-example
2Files: bin/main-tab apps/Examples/main-tab.desktop
3Priority: optional
4Section: opie/applications
5Maintainer: Holger 'zecke' Freyther <zecke@handhelds.org>
6Architecture: arm
7Depends: task-opie-minimal, opie-pics
8Description: A simple example
9Version: $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 @@
1#include <qaction.h> // action
2#include <qmenubar.h> // menubar
3#include <qtoolbar.h> // toolbar
4#include <qlabel.h> // a label
5#include <qpushbutton.h> // the header file for the QPushButton
6#include <qlayout.h>
7#include <qtimer.h> // we use it for the singleShot
8#include <qdatetime.h> // for QDate
9#include <qtextview.h> // a rich text widget
10#include <qdialog.h>
11#include <qwhatsthis.h> // for whats this
12
13#include <qpe/qpeapplication.h> // the QPEApplication
14#include <qpe/resource.h>
15#include <qpe/sound.h>
16#include <qpe/qcopenvelope_qws.h>
17#include <qpe/datebookmonth.h>
18#include <qpe/timestring.h>
19
20#include <opie/oapplicationfactory.h> // a template + macro to save the main method and allow quick launching
21#include <opie/otabwidget.h>
22#include <opie/owait.h>
23
24#include "simple.h"
25
26/*
27 * implementation of simple
28 */
29
30/*
31 * The factory is used for quicklaunching
32 * 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
33 *
34 * Depending on the global quick launch setting this will create
35 * either a main method or one for our component plugin system
36 */
37
38OPIE_EXPORT_APP( OApplicationFactory<MainWindow> )
39
40MainWindow::MainWindow(QWidget *parent, const char* name, WFlags fl )
41 : QMainWindow( parent, name, fl ) {
42 setCaption(tr("My MainWindow") );
43
44 m_desktopChannel = 0;
45 m_loading = 0;
46
47 initUI();
48
49
50 /*
51 * Tab widget as central
52 */
53 m_tab = new OTabWidget(this);
54
55 setCentralWidget( m_tab );
56
57 m_todoView = new PIMListView(m_tab, "Todo view" );
58 m_tab->addTab( m_todoView,"todo/TodoList", tr("Todos") );
59
60 m_dateView = new PIMListView(m_tab, "Datebook view" );
61 m_tab->addTab( m_dateView, "datebook/DateBook", tr("Events") );
62
63 /* now connect the actions */
64 /*
65 * we connect the activated to our show
66 * and on activation we will show a detailed
67 * summary of the record
68 */
69 connect(m_fire, SIGNAL(activated() ),
70 this, SLOT(slotShow() ) );
71
72 /*
73 * We will change the date
74 */
75 connect(m_dateAction, SIGNAL(activated() ),
76 this, SLOT(slotDate() ) );
77
78 /*
79 * connect the show signal of the PIMListView
80 * to a slot to show a dialog
81 */
82 connect(m_todoView, SIGNAL(showRecord(const OPimRecord& ) ),
83 this, SLOT(slotShowRecord(const OPimRecord& ) ) );
84 connect(m_dateView, SIGNAL(showRecord(const OPimRecord& ) ),
85 this, SLOT(slotShowRecord(const OPimRecord& ) ) );
86
87 /*
88 * Now comes the important lines of code for this example
89 * We do not directly call load but delay loading until
90 * all Events are dispatches and handled.
91 * SO we will load once our window is mapped to screen
92 * to achieve that we use a QTimer::singleShot
93 * After 10 milli seconds the timer fires and on TimerEvent
94 * out slot slotLoad will be called
95 * Remember this a Constructor to construct your object and not
96 * to load
97 */
98 QTimer::singleShot( 10, this, SLOT(slotLoad() ) );
99}
100
101MainWindow::~MainWindow() {
102 // again nothing to delete because Qt takes care
103}
104
105
106void MainWindow::setDocument( const QString& /*str*/ ) {
107}
108
109
110void MainWindow::initUI() {
111
112 setToolBarsMovable( false );
113
114 QToolBar *menuBarHolder = new QToolBar( this );
115
116 menuBarHolder->setHorizontalStretchable( true );
117 QMenuBar *mb = new QMenuBar( menuBarHolder );
118 QToolBar *tb = new QToolBar( this );
119
120 QPopupMenu *fileMenu = new QPopupMenu( this );
121
122
123 QAction *a = new QAction( tr("Quit"), Resource::loadIconSet("quit_icon"),
124 QString::null, 0, this, "quit_action" );
125 /*
126 * Connect quit to the QApplication quit slot
127 */
128 connect(a, SIGNAL(activated() ),
129 qApp, SLOT(quit() ) );
130 a->addTo( fileMenu );
131
132 a = new QAction(tr("View Current"),
133 Resource::loadIconSet("zoom"),
134 QString::null, 0, this, "view current");
135 /* a simple whats this online explanation of out button */
136 a->setWhatsThis(tr("Views the current record") );
137 /* or QWhatsThis::add(widget, "description" ); */
138
139 /* see the power? */
140 a->addTo( fileMenu );
141 a->addTo( tb );
142 m_fire = a;
143
144 a = new QAction(tr("Choose Date"),
145 Resource::loadIconSet("day"),
146 QString::null, 0, this, "choose date" );
147 a->addTo( fileMenu );
148 a->addTo( tb );
149 m_dateAction = a;
150
151 mb->insertItem(tr("File"), fileMenu );
152
153}
154
155void MainWindow::slotLoad() {
156 /*
157 * There is no real shared access in the PIM API
158 * It wasn't finish cause of health problems of one
159 * of the authors so we do something fancy and use QCOP
160 * the IPC system to get a current copy
161 */
162 /* NOTES to QCOP: QCOP operates over channels and use QDataStream
163 * to send data. You can check if a channel isRegistered or hook
164 * yourself to that channel. A Channel is QCString and normally
165 * prefix with QPE/ and then the system in example QPE/System,
166 * QPE/Desktop a special channel is the application channel
167 * it QPE/Application/appname this channel gets created on app
168 * startup by QPEApplication. QCOP is asynchronous
169 *
170 * To send you'll use QCopEnevelope
171 *
172 */
173 /*
174 * What we will do is first is get to know if either
175 * datebook or todolist are running if so we will kindly
176 * asked to save the data for us.
177 * If neither are running we can load directly
178 */
179 if (!QCopChannel::isRegistered("QPE/Application/todolist") &&
180 !QCopChannel::isRegistered("QPE/Application/datebook") ) {
181 m_db.load();
182 m_tb.load();
183 return slotLoadForDay( QDate::currentDate() );
184 }
185
186 /*
187 * prepare our answer machine the QCopChannel
188 * QPE/Desktop will send "flushDone(QString)" when
189 * the flush is done it emits a signal on receive
190 */
191 m_desktopChannel = new QCopChannel("QPE/Desktop");
192 connect(m_desktopChannel, SIGNAL(received(const QCString&, const QByteArray& ) ),
193 this, SLOT(slotDesktopReceive(const QCString&, const QByteArray& ) ) );
194 /* the numberof synced channels will be set to zero */
195 m_synced = 0;
196
197 /*
198 * We use {} around the QCopEnvelope because it sends its
199 * data on destruction of QCopEnvelope with
200 */
201 /* check again if not present increment synced*/
202 if ( QCopChannel::isRegistered("QPE/Application/todolist") ) {
203 QCopEnvelope env("QPE/Application/todolist", "flush()" );
204 // env << data; but we do not have any parameters here
205 }else
206 m_synced++;
207
208 if ( QCopChannel::isRegistered("QPE/Application/datebook") ) {
209 QCopEnvelope env("QPE/Application/datebook", "flush()" );
210 }else
211 m_synced++;
212
213 /* we will provide a wait scrren */
214 m_loading = new OWait(this, "wait screen" );
215}
216
217void MainWindow::slotDesktopReceive(const QCString& cmd, const QByteArray& data ) {
218 /* the bytearray was filled with the QDataStream now
219 * we open it read only to get the value(s)
220 */
221 QDataStream stream(data, IO_ReadOnly );
222 /*
223 * we're only interested in the flushDone
224 */
225 if ( cmd == "flushDone(QString)" ) {
226 QString appname;
227 stream >> appname; // get the first argument out of stream
228 if (appname == QString::fromLatin1("datebook") ||
229 appname == QString::fromLatin1("todolist") )
230 m_synced++;
231 }
232
233 /*
234 * If we synced both we can go ahead
235 * In future this is not needed anymore when we finally
236 * implemented X-Ref and other PIM features
237 */
238 if (m_synced >= 2 ) {
239 delete m_loading;
240 delete m_desktopChannel;
241 /* now we finally can start doing the actual loading */
242 m_tb.load();
243 m_db.load();
244 {
245 /* tell the applications to reload */
246 QCopEnvelope("QPE/Application/todolist", "reload()");
247 QCopEnvelope("QPE/Application/datebook", "reload()");
248 }
249 slotLoadForDay( QDate::currentDate() );
250 }
251
252}
253
254/* overloaded member for shortcoming of libqpe */
255void MainWindow::slotLoadForDay(int y, int m, int d) {
256 /* year,month, day */
257 slotLoadForDay( QDate(y, m, d ) );
258}
259
260void MainWindow::slotLoadForDay(const QDate& date) {
261
262
263 /* all todos for today including the ones without dueDate */
264 m_todoView->set( m_tb.effectiveToDos(date, date ) );
265 m_dateView->set( m_db.effectiveEvents( date, date ) );
266}
267
268/* we want to show the current record */
269void MainWindow::slotShow() {
270 /* we only added PIMListViews so we can safely cast */
271 PIMListView *view = static_cast<PIMListView*>(m_tab->currentWidget() );
272
273 /* ask the view to send a signal */
274 view->showCurrentRecord();
275
276}
277
278/* as answer this slot will be called */
279void MainWindow::slotShowRecord( const OPimRecord& rec) {
280 /* got a parent but still is a toplevel MODAL dialog */
281 QDialog* dia = new QDialog(this,"dialog",TRUE );
282 QVBoxLayout *box = new QVBoxLayout( dia );
283 dia->setCaption( tr("View Record") );
284
285
286 QTextView *view = new QTextView(dia );
287 view->setText( rec.toRichText() );
288 box->addWidget( view );
289 /*
290 * execute via QPEApplication
291 * this allows QPEApplication to make a sane decision
292 * on the size
293 */
294 dia->showMaximized();
295 QPEApplication::execDialog( dia );
296 delete dia;
297}
298
299
300void MainWindow::slotDate() {
301 /*
302 * called by the action we will show a Popup
303 * at the current mouse position with a DateChooser
304 * to select the day
305 */
306 qWarning("slot Date");
307 QPopupMenu *menu = new QPopupMenu();
308 /* A Month to select a date from TRUE for auto close */
309 DateBookMonth *month = new DateBookMonth(menu, 0, true );
310 connect(month, SIGNAL(dateClicked(int, int, int) ),
311 this, SLOT(slotLoadForDay(int, int, int) ) );
312
313 menu->insertItem( month );
314
315 menu->exec( QCursor::pos() );
316
317 /*
318 * we do not need to delete month because
319 * we delete its parent menu
320 */
321
322 delete menu;
323}
324
325/*
326 * An anonymous namespace this symbol is only available here
327 * so truely private
328 */
329namespace {
330 /* not static cause namespace does that what static would do */
331 const int RTTI = 5050;
332 /*
333 * every ListView got Items. we've special pim items
334 * holding ownership and the pointer to a pim record
335 * it can't hold a pimrecord directly because this
336 * would introduce slicing... any break
337 */
338 /*
339 * A struct is a special class. Everything is public by
340 * default.
341 */
342 struct PIMListViewItem : public QListViewItem {
343 /*
344 *currently no hierachies are planed for the example
345 * so only one constructor with a QListView as parent
346 */
347 PIMListViewItem( QListView*, OPimRecord* record );
348 ~PIMListViewItem();
349
350 /* used by the QListViewItem to easily allow identifiying of different
351 * items. Values greater than 1000 should be used */
352 int rtti()const;
353 OPimRecord* record()const;
354
355 private:
356 OPimRecord* m_record;
357 };
358
359 PIMListViewItem::PIMListViewItem( QListView *p, OPimRecord* rec )
360 : QListViewItem(p), m_record( rec ) {
361 }
362
363 PIMListViewItem::~PIMListViewItem() {
364 /* we've the onwership so we need to delete it */
365 delete m_record;
366 }
367
368 OPimRecord* PIMListViewItem::record()const {
369 return m_record;
370 }
371
372}
373
374
375PIMListView::PIMListView( QWidget* widget, const char* name, WFlags fl )
376 : QListView(widget, name, fl )
377{
378 addColumn("Summary");
379}
380
381PIMListView::~PIMListView() {
382
383}
384
385void PIMListView::set( OTodoAccess::List list ) {
386 /* clear first and then add new items */
387 clear();
388
389 OTodoAccess::List::Iterator it;
390 for (it = list.begin(); it != list.end(); ++it ) {
391 /*
392 * make a new item which automatically gets added to the listview
393 * and call the copy c'tor to create a new OTodo
394 */
395 PIMListViewItem *i = new PIMListViewItem(this, new OTodo( *it ) );
396 i->setText(0, (*it).summary() );
397 }
398}
399
400void PIMListView::set( const OEffectiveEvent::ValueList& lst ) {
401 /* clear first and then add items */
402 clear();
403
404 OEffectiveEvent::ValueList::ConstIterator it;
405 for ( it = lst.begin(); it != lst.end(); ++it ) {
406 PIMListViewItem *i = new PIMListViewItem(this, new OEvent( (*it).event() ) );
407 i->setText( 0, PIMListView::makeString( (*it) ) );
408 }
409
410}
411
412void PIMListView::showCurrentRecord() {
413 /* it could be possible that their is no currentItem */
414 if (!currentItem() )
415 return;
416
417 /*
418 * we only add PIMListViewItems so it is save
419 * to do this case. If this would not be the case
420 * use rtti() to check in a switch() case
421 */
422 PIMListViewItem *item = static_cast<PIMListViewItem*>( currentItem() );
423
424 /* finally you see how to emit a signal */
425 emit showRecord( (*item->record() ) );
426}
427
428QString PIMListView::makeString( const OEffectiveEvent& ev ) {
429 QString str;
430 str += ev.description();
431 if ( !ev.event().isAllDay() ) {
432 if ( ev.startDate() != ev.endDate() ) {
433 str += tr("Start ") + TimeString::timeString( ev.event().startDateTime().time() );
434 str += " - " + TimeString::longDateString( ev.startDate() );
435 str += tr("End ") + TimeString::timeString( ev.event().endDateTime().time() );
436 str += " - " + TimeString::longDateString( ev.endDate() );
437 }else{
438 str += tr("Time ") + TimeString::timeString( ev.startTime() );
439 str += " - " + TimeString::timeString( ev.endTime() );
440 }
441 }else
442 str += tr(" This is an All-Day Event");
443
444 return str;
445}
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 @@
1
2/*
3 * A Simple widget with a button to quit
4 *
5 */
6
7/*
8 * The below sequence is called a guard and guards
9 * against multiple inclusion of header files
10 * NOTE: you need to use unique names among the header files
11 */
12#ifndef QUIET_SIMPLE_DEMO_H
13#define QUIET_SIMPLE_DEMO_H
14
15
16
17
18#include <qmainwindow.h> // from this class we will inherit
19#include <qlistview.h> // A ListView for our PIM records
20
21#include <opie/otodoaccess.h>
22#include <opie/odatebookaccess.h>
23
24class QPushButton; // forward declaration to not include the header. This can save time when compiling
25class QAction;
26class PIMListView;
27class QDate;
28class QCopChannel;
29class OWait;
30class OTabWidget;
31
32/*
33 * A mainwindow is a special QWidget it helps layouting
34 * toolbar, statusbar, menubar. Got dockable areas
35 * So in one sentence it is a MainWindow :)
36 */
37class MainWindow : public QMainWindow {
38 Q_OBJECT
39public:
40 static QString appName() { return QString::fromLatin1("simple-pim"); }
41 MainWindow( QWidget* parent, const char* name, WFlags fl );
42 ~MainWindow();
43
44public slots:
45 void setDocument( const QString& );
46private slots:
47 void slotDesktopReceive( const QCString&, const QByteArray& );
48 void slotLoad();
49 void slotLoadForDay(int, int, int );
50 void slotLoadForDay(const QDate&);
51 void slotShow();
52 void slotDate();
53 void slotShowRecord( const OPimRecord& );
54
55private:
56 void initUI();
57 QAction *m_fire;
58 QAction *m_dateAction;
59 OTabWidget* m_tab;
60
61 OTodoAccess m_tb;
62 ODateBookAccess m_db;
63 PIMListView *m_todoView;
64 PIMListView *m_dateView;
65
66 int m_synced; // a counter for synced objects..
67 QCopChannel *m_desktopChannel;
68 OWait *m_loading;
69};
70
71/*
72 * Instead of the simple QWidgets we will design
73 * a new widget based on a QListView
74 * it should show either Todos or EffectiveEvents
75 */
76class PIMListView : public QListView {
77 Q_OBJECT
78public:
79 PIMListView( QWidget* parent, const char* name, WFlags fl= 0 );
80 ~PIMListView();
81
82
83 void set( OTodoAccess::List );
84 void set( const OEffectiveEvent::ValueList& );
85 void showCurrentRecord();
86
87signals:
88 void showRecord( const OPimRecord& );
89
90private:
91 static QString makeString( const OEffectiveEvent& ev );
92
93};
94
95#endif
diff --git a/packages b/packages
index 232f2d9..e1a8e86 100644
--- a/packages
+++ b/packages
@@ -177,3 +177,4 @@ CONFIG_MAIN_TAB_EXAMPLE examples/main-tab example.pro
177 CONFIG_SIMPLE_EXAMPLE examples/simpleexample.pro 177 CONFIG_SIMPLE_EXAMPLE examples/simpleexample.pro
178 CONFIG_SIMPLE_ICON examples/simple-iconexample.pro 178 CONFIG_SIMPLE_ICON examples/simple-iconexample.pro
179 CONFIG_SIMPLE_MAIN examples/simple-mainexample.pro 179 CONFIG_SIMPLE_MAIN examples/simple-mainexample.pro
180 CONFIG_SIMPLE_PIM examples/simple-pimexample.pro \ No newline at end of file