author | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
commit | ea3945a9bd8f9830f70b1efa133f9df13b19362f (patch) (side-by-side diff) | |
tree | f2ea22cc50e9aa8aa73ee7dea148f41c563c9666 /noncore/unsupported | |
parent | 1c6f490e8541626f68422e0a3a7c7281d7f5b7d3 (diff) | |
download | opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.zip opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.gz opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.bz2 |
libopie1 goes into unsupported
124 files changed, 29474 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/.cvsignore b/noncore/unsupported/libopie/.cvsignore new file mode 100644 index 0000000..f76e42e --- a/dev/null +++ b/noncore/unsupported/libopie/.cvsignore @@ -0,0 +1,7 @@ +*.moc +Makefile* +moc_* +orecurrancebase.cpp +orecurrancebase.h +otimepickerbase.cpp +otimepickerbase.h diff --git a/noncore/unsupported/libopie/colordialog.cpp b/noncore/unsupported/libopie/colordialog.cpp new file mode 100644 index 0000000..b2854a6 --- a/dev/null +++ b/noncore/unsupported/libopie/colordialog.cpp @@ -0,0 +1,856 @@ +/**************************************************************************** +** $Id$ +** +** Implementation of OColorDialog class +** +** Created : 990222 +** +** Copyright (C) 1999-2000 Trolltech AS. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "colordialog.h" + +#include "qpainter.h" +#include "qlayout.h" +#include "qlabel.h" +#include "qpushbutton.h" +#include "qlineedit.h" +#include "qimage.h" +#include "qpixmap.h" +#include "qdrawutil.h" +#include "qvalidator.h" +#include "qapplication.h" + +static inline void rgb2hsv( QRgb rgb, int&h, int&s, int&v ) +{ + QColor c; + c.setRgb( rgb ); + c.getHsv(h,s,v); +} + +/* + * avoid clashes with the original Qt + */ +namespace { + +class QColorPicker : public QFrame +{ + Q_OBJECT +public: + QColorPicker(QWidget* parent=0, const char* name=0); + ~QColorPicker(); + +public slots: + void setCol( int h, int s ); + +signals: + void newCol( int h, int s ); + +protected: + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void drawContents(QPainter* p); + void mouseMoveEvent( QMouseEvent * ); + void mousePressEvent( QMouseEvent * ); + +private: + int hue; + int sat; + + QPoint colPt(); + int huePt( const QPoint &pt ); + int satPt( const QPoint &pt ); + void setCol( const QPoint &pt ); + + QPixmap *pix; +}; + +static int pWidth = 200; +static int pHeight = 200; + +class QColorLuminancePicker : public QWidget +{ + Q_OBJECT +public: + QColorLuminancePicker(QWidget* parent=0, const char* name=0); + ~QColorLuminancePicker(); + +public slots: + void setCol( int h, int s, int v ); + void setCol( int h, int s ); + +signals: + void newHsv( int h, int s, int v ); + +protected: +// QSize sizeHint() const; +// QSizePolicy sizePolicy() const; + void paintEvent( QPaintEvent*); + void mouseMoveEvent( QMouseEvent * ); + void mousePressEvent( QMouseEvent * ); + +private: + enum { foff = 3, coff = 4 }; //frame and contents offset + int val; + int hue; + int sat; + + int y2val( int y ); + int val2y( int val ); + void setVal( int v ); + + QPixmap *pix; +}; + + +int QColorLuminancePicker::y2val( int y ) +{ + int d = height() - 2*coff - 1; + return 255 - (y - coff)*255/d; +} + +int QColorLuminancePicker::val2y( int v ) +{ + int d = height() - 2*coff - 1; + return coff + (255-v)*d/255; +} + +QColorLuminancePicker::QColorLuminancePicker(QWidget* parent, + const char* name) + :QWidget( parent, name ) +{ + hue = 100; val = 100; sat = 100; + pix = 0; + // setBackgroundMode( NoBackground ); +} + +QColorLuminancePicker::~QColorLuminancePicker() +{ + delete pix; +} + +void QColorLuminancePicker::mouseMoveEvent( QMouseEvent *m ) +{ + setVal( y2val(m->y()) ); +} +void QColorLuminancePicker::mousePressEvent( QMouseEvent *m ) +{ + setVal( y2val(m->y()) ); +} + +void QColorLuminancePicker::setVal( int v ) +{ + if ( val == v ) + return; + val = QMAX( 0, QMIN(v,255)); + delete pix; pix=0; + repaint( FALSE ); //### + emit newHsv( hue, sat, val ); +} + +//receives from a hue,sat chooser and relays. +void QColorLuminancePicker::setCol( int h, int s ) +{ + setCol( h, s, val ); + emit newHsv( h, s, val ); +} + +void QColorLuminancePicker::paintEvent( QPaintEvent * ) +{ + int w = width() - 5; + + QRect r( 0, foff, w, height() - 2*foff ); + int wi = r.width() - 2; + int hi = r.height() - 2; + if ( !pix || pix->height() != hi || pix->width() != wi ) { + delete pix; + QImage img( wi, hi, 32 ); + int y; + for ( y = 0; y < hi; y++ ) { + QColor c( hue, sat, y2val(y+coff), QColor::Hsv ); + QRgb r = c.rgb(); + int x; + for ( x = 0; x < wi; x++ ) + img.setPixel( x, y, r ); + } + pix = new QPixmap; + pix->convertFromImage(img); + } + QPainter p(this); + p.drawPixmap( 1, coff, *pix ); + QColorGroup g = colorGroup(); + qDrawShadePanel( &p, r, g, TRUE ); + p.setPen( g.foreground() ); + p.setBrush( g.foreground() ); + QPointArray a; + int y = val2y(val); + a.setPoints( 3, w, y, w+5, y+5, w+5, y-5 ); + erase( w, 0, 5, height() ); + p.drawPolygon( a ); +} + +void QColorLuminancePicker::setCol( int h, int s , int v ) +{ + val = v; + hue = h; + sat = s; + delete pix; pix=0; + repaint( FALSE );//#### +} + +QPoint QColorPicker::colPt() +{ return QPoint( (360-hue)*(pWidth-1)/360, (255-sat)*(pHeight-1)/255 ); } +int QColorPicker::huePt( const QPoint &pt ) +{ return 360 - pt.x()*360/(pWidth-1); } +int QColorPicker::satPt( const QPoint &pt ) +{ return 255 - pt.y()*255/(pHeight-1) ; } +void QColorPicker::setCol( const QPoint &pt ) +{ setCol( huePt(pt), satPt(pt) ); } + +QColorPicker::QColorPicker(QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + hue = 0; sat = 0; + setCol( 150, 255 ); + + QImage img( pWidth, pHeight, 32 ); + int x,y; + for ( y = 0; y < pHeight; y++ ) + for ( x = 0; x < pWidth; x++ ) { + QPoint p( x, y ); + img.setPixel( x, y, QColor(huePt(p), satPt(p), + 200, QColor::Hsv).rgb() ); + } + pix = new QPixmap; + pix->convertFromImage(img); + setBackgroundMode( NoBackground ); +} + +QColorPicker::~QColorPicker() +{ + delete pix; +} + +QSize QColorPicker::sizeHint() const +{ + return QSize( pWidth + 2*frameWidth(), pHeight + 2*frameWidth() ); +} + +QSizePolicy QColorPicker::sizePolicy() const +{ + return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); +} + +void QColorPicker::setCol( int h, int s ) +{ + int nhue = QMIN( QMAX(0,h), 360 ); + int nsat = QMIN( QMAX(0,s), 255); + if ( nhue == hue && nsat == sat ) + return; + QRect r( colPt(), QSize(20,20) ); + hue = nhue; sat = nsat; + r = r.unite( QRect( colPt(), QSize(20,20) ) ); + r.moveBy( contentsRect().x()-9, contentsRect().y()-9 ); + // update( r ); + repaint( r, FALSE ); +} + +void QColorPicker::mouseMoveEvent( QMouseEvent *m ) +{ + QPoint p = m->pos() - contentsRect().topLeft(); + setCol( p ); + emit newCol( hue, sat ); +} + +void QColorPicker::mousePressEvent( QMouseEvent *m ) +{ + QPoint p = m->pos() - contentsRect().topLeft(); + setCol( p ); + emit newCol( hue, sat ); +} + +void QColorPicker::drawContents(QPainter* p) +{ + QRect r = contentsRect(); + + p->drawPixmap( r.topLeft(), *pix ); + QPoint pt = colPt() + r.topLeft(); + p->setPen( QPen(black) ); + + p->fillRect( pt.x()-9, pt.y(), 20, 2, black ); + p->fillRect( pt.x(), pt.y()-9, 2, 20, black ); + +} + +class QColorShowLabel; + + + +class QColIntValidator: public QIntValidator +{ +public: + QColIntValidator( int bottom, int top, + QWidget * parent, const char *name = 0 ) + :QIntValidator( bottom, top, parent, name ) {} + + QValidator::State validate( QString &, int & ) const; +}; + +QValidator::State QColIntValidator::validate( QString &s, int &pos ) const +{ + State state = QIntValidator::validate(s,pos); + if ( state == Valid ) { + long int val = s.toLong(); + // This is not a general solution, assumes that top() > 0 and + // bottom >= 0 + if ( val < 0 ) { + s = "0"; + pos = 1; + } else if ( val > top() ) { + s.setNum( top() ); + pos = s.length(); + } + } + return state; +} + + + +class QColNumLineEdit : public QLineEdit +{ +public: + QColNumLineEdit( QWidget *parent, const char* name = 0 ) + : QLineEdit( parent, name ) { setMaxLength( 3 );} + QSize sizeHint() const { + return QSize( 30, //##### + QLineEdit::sizeHint().height() ); } + void setNum( int i ) { + QString s; + s.setNum(i); + bool block = signalsBlocked(); + blockSignals(TRUE); + setText( s ); + blockSignals(block); + } + int val() const { return text().toInt(); } +}; + + +class QColorShower : public QWidget +{ + Q_OBJECT +public: + QColorShower( QWidget *parent, const char *name = 0 ); + + //things that don't emit signals + void setHsv( int h, int s, int v ); + + int currentAlpha() const { return alphaEd->val(); } + void setCurrentAlpha( int a ) { alphaEd->setNum( a ); } + void showAlpha( bool b ); + + + QRgb currentColor() const { return curCol; } + +public slots: + void setRgb( QRgb rgb ); + +signals: + void newCol( QRgb rgb ); +private slots: + void rgbEd(); + void hsvEd(); +private: + void showCurrentColor(); + int hue, sat, val; + QRgb curCol; + QColNumLineEdit *hEd; + QColNumLineEdit *sEd; + QColNumLineEdit *vEd; + QColNumLineEdit *rEd; + QColNumLineEdit *gEd; + QColNumLineEdit *bEd; + QColNumLineEdit *alphaEd; + QLabel *alphaLab; + QColorShowLabel *lab; + bool rgbOriginal; +}; + +class QColorShowLabel : public QFrame +{ + Q_OBJECT + +public: + QColorShowLabel( QWidget *parent ) :QFrame( parent ) { + setFrameStyle( QFrame::Panel|QFrame::Sunken ); + setBackgroundMode( PaletteBackground ); + setAcceptDrops( TRUE ); + mousePressed = FALSE; + } + void setColor( QColor c ) { col = c; } + +signals: + void colorDropped( QRgb ); + +protected: + void drawContents( QPainter *p ); + void mousePressEvent( QMouseEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); + +private: + QColor col; + bool mousePressed; + QPoint pressPos; + +}; + +void QColorShowLabel::drawContents( QPainter *p ) +{ + p->fillRect( contentsRect(), col ); +} + +void QColorShower::showAlpha( bool b ) +{ + if ( b ) { + alphaLab->show(); + alphaEd->show(); + } else { + alphaLab->hide(); + alphaEd->hide(); + } +} + +void QColorShowLabel::mousePressEvent( QMouseEvent *e ) +{ + mousePressed = TRUE; + pressPos = e->pos(); +} + +void QColorShowLabel::mouseReleaseEvent( QMouseEvent * ) +{ + if ( !mousePressed ) + return; + mousePressed = FALSE; +} + +QColorShower::QColorShower( QWidget *parent, const char *name ) + :QWidget( parent, name) +{ + curCol = qRgb( -1, -1, -1 ); + QColIntValidator *val256 = new QColIntValidator( 0, 255, this ); + QColIntValidator *val360 = new QColIntValidator( 0, 360, this ); + + QGridLayout *gl = new QGridLayout( this, 1, 1, 2 ); + gl->setMargin( 0 ); + lab = new QColorShowLabel( this ); + lab->setMinimumWidth( 60 ); //### + gl->addMultiCellWidget(lab, 0,-1,0,0); + connect( lab, SIGNAL( colorDropped(QRgb) ), + this, SIGNAL( newCol(QRgb) ) ); + connect( lab, SIGNAL( colorDropped(QRgb) ), + this, SLOT( setRgb(QRgb) ) ); + + hEd = new QColNumLineEdit( this ); + hEd->setValidator( val360 ); + QLabel *l = new QLabel( hEd, OColorDialog::tr("Hue:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 0, 1 ); + gl->addWidget( hEd, 0, 2 ); + + sEd = new QColNumLineEdit( this ); + sEd->setValidator( val256 ); + l = new QLabel( sEd, OColorDialog::tr("Sat:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 1, 1 ); + gl->addWidget( sEd, 1, 2 ); + + vEd = new QColNumLineEdit( this ); + vEd->setValidator( val256 ); + l = new QLabel( vEd, OColorDialog::tr("Val:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 2, 1 ); + gl->addWidget( vEd, 2, 2 ); + + rEd = new QColNumLineEdit( this ); + rEd->setValidator( val256 ); + l = new QLabel( rEd, OColorDialog::tr("Red:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 0, 3 ); + gl->addWidget( rEd, 0, 4 ); + + gEd = new QColNumLineEdit( this ); + gEd->setValidator( val256 ); + l = new QLabel( gEd, OColorDialog::tr("Green:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 1, 3 ); + gl->addWidget( gEd, 1, 4 ); + + bEd = new QColNumLineEdit( this ); + bEd->setValidator( val256 ); + l = new QLabel( bEd, OColorDialog::tr("Blue:"), this ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 2, 3 ); + gl->addWidget( bEd, 2, 4 ); + + alphaEd = new QColNumLineEdit( this ); + alphaEd->setValidator( val256 ); + alphaLab = new QLabel( alphaEd, OColorDialog::tr("Alpha channel:"), this ); + alphaLab->setAlignment( AlignRight|AlignVCenter ); + gl->addMultiCellWidget( alphaLab, 3, 3, 1, 3 ); + gl->addWidget( alphaEd, 3, 4 ); + alphaEd->hide(); + alphaLab->hide(); + + connect( hEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + connect( sEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + connect( vEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + + connect( rEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); + connect( gEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); + connect( bEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); +} + +void QColorShower::showCurrentColor() +{ + lab->setColor( currentColor() ); + lab->repaint(FALSE); //### +} + +void QColorShower::rgbEd() +{ + rgbOriginal = TRUE; + curCol = qRgb( rEd->val(), gEd->val(), bEd->val() ); + rgb2hsv(currentColor(), hue, sat, val ); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + showCurrentColor(); + emit newCol( currentColor() ); +} + +void QColorShower::hsvEd() +{ + rgbOriginal = FALSE; + hue = hEd->val(); + sat = sEd->val(); + val = vEd->val(); + + curCol = QColor( hue, sat, val, QColor::Hsv ).rgb(); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + showCurrentColor(); + emit newCol( currentColor() ); +} + +void QColorShower::setRgb( QRgb rgb ) +{ + rgbOriginal = TRUE; + curCol = rgb; + + rgb2hsv( currentColor(), hue, sat, val ); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + showCurrentColor(); +} + +void QColorShower::setHsv( int h, int s, int v ) +{ + rgbOriginal = FALSE; + hue = h; val = v; sat = s; //Range check### + curCol = QColor( hue, sat, val, QColor::Hsv ).rgb(); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + + showCurrentColor(); +} + +} + +class OColorDialogPrivate : public QObject +{ +Q_OBJECT +public: + OColorDialogPrivate( OColorDialog *p ); + QRgb currentColor() const { return cs->currentColor(); } + void setCurrentColor( const QRgb& rgb ); + + int currentAlpha() const { return cs->currentAlpha(); } + void setCurrentAlpha( int a ) { cs->setCurrentAlpha( a ); } + void showAlpha( bool b ) { cs->showAlpha( b ); } + +private slots: + void newHsv( int h, int s, int v ); + void newColorTypedIn( QRgb rgb ); +private: + QColorPicker *cp; + QColorLuminancePicker *lp; + QColorShower *cs; +}; + +//sets all widgets to display h,s,v +void OColorDialogPrivate::newHsv( int h, int s, int v ) +{ + cs->setHsv( h, s, v ); + cp->setCol( h, s ); + lp->setCol( h, s, v ); +} + +//sets all widgets to display rgb +void OColorDialogPrivate::setCurrentColor( const QRgb& rgb ) +{ + cs->setRgb( rgb ); + newColorTypedIn( rgb ); +} + +//sets all widgets exept cs to display rgb +void OColorDialogPrivate::newColorTypedIn( QRgb rgb ) +{ + int h, s, v; + rgb2hsv(rgb, h, s, v ); + cp->setCol( h, s ); + lp->setCol( h, s, v); +} + +OColorDialogPrivate::OColorDialogPrivate( OColorDialog *dialog ) : + QObject(dialog) +{ + int border = 2; + QVBoxLayout *topLay = new QVBoxLayout( dialog, border, 2 ); + + QHBoxLayout *pickLay = new QHBoxLayout( topLay ); + + + cp = new QColorPicker( dialog ); + cp->setFrameStyle( QFrame::Panel + QFrame::Sunken ); + pickLay->addWidget( cp ); + + pickLay->addStretch(); + + lp = new QColorLuminancePicker( dialog ); + lp->setFixedWidth( 20 ); //### + pickLay->addWidget( lp ); + + connect( cp, SIGNAL(newCol(int,int)), lp, SLOT(setCol(int,int)) ); + connect( lp, SIGNAL(newHsv(int,int,int)), this, SLOT(newHsv(int,int,int)) ); + + topLay->addStretch(); + + cs = new QColorShower( dialog ); + connect( cs, SIGNAL(newCol(QRgb)), this, SLOT(newColorTypedIn(QRgb))); + topLay->addWidget( cs ); + +} + + +// BEING REVISED: jo +/*! + \class ColorDialog ColorDialog.h + \brief The OColorDialog class provides a dialog widget for specifying colors. + \ingroup dialogs + + The color dialog's function is to allow users to choose colors - + for instance, you might use this in a drawing program to allow the + user to set the brush color. + + This version of Qt only provides modal color dialogs. The static + getColor() function shows the dialog and allows the user to specify a color, + while getRgba() does the same but allows the user to specify a color with an + alpha channel (transparency) value. + + The user can store customCount() different custom colors. The custom + colors are shared by all color dialogs, and remembered during the + execution of the program. Use setCustomColor() to set the + custom colors, and customColor() to get them. + + <img src=qcolordlg-m.png> <img src=qcolordlg-w.png> +*/ + +/*! + Constructs a default color dialog. Use setColor() for setting an initial value. + + \sa getColor() +*/ + +OColorDialog::OColorDialog(QWidget* parent, const char* name, bool modal) : + QDialog(parent, name, modal ) +{ + d = new OColorDialogPrivate( this ); +} + + +/*! + Pops up a modal color dialog letting the user choose a color and returns + that color. The color is initially set to \a initial. Returns an \link QColor::isValid() invalid\endlink color if the user cancels + the dialog. All colors allocated by the dialog will be deallocated + before this function returns. +*/ + +QColor OColorDialog::getColor( const QColor& initial, QWidget *parent, + const char *name ) +{ + int allocContext = QColor::enterAllocContext(); + OColorDialog *dlg = new OColorDialog( parent, name, TRUE ); //modal + if ( parent && parent->icon() && !parent->icon()->isNull() ) + dlg->setIcon( *parent->icon() ); + else if ( qApp->mainWidget() && qApp->mainWidget()->icon() && !qApp->mainWidget()->icon()->isNull() ) + dlg->setIcon( *qApp->mainWidget()->icon() ); + + dlg->setCaption( OColorDialog::tr( "Select color" ) ); + dlg->setColor( initial ); + dlg->showMaximized(); + int resultCode = dlg->exec(); + QColor::leaveAllocContext(); + QColor result; + if ( resultCode == QDialog::Accepted ) { + result = dlg->color(); + } else { + result = initial; + } + QColor::destroyAllocContext(allocContext); + delete dlg; + return result; +} + + +/*! + Pops up a modal color dialog, letting the user choose a color and an + alpha channel value. The color+alpha is initially set to \a initial. + + If \a ok is non-null, \c *ok is set to TRUE if the user clicked OK, + and FALSE if the user clicked Cancel. + + If the user clicks Cancel the \a initial value is returned. +*/ + +QRgb OColorDialog::getRgba( const QRgb& initial, bool *ok, + QWidget *parent, const char* name ) +{ + int allocContext = QColor::enterAllocContext(); + OColorDialog *dlg = new OColorDialog( parent, name, TRUE ); //modal + dlg->setColor( initial ); + dlg->setSelectedAlpha( qAlpha(initial) ); + dlg->showMaximized(); + int resultCode = dlg->exec(); + QColor::leaveAllocContext(); + QRgb result = initial; + if ( resultCode == QDialog::Accepted ) { + QRgb c = dlg->color().rgb(); + int alpha = dlg->selectedAlpha(); + result = qRgba( qRed(c), qGreen(c), qBlue(c), alpha ); + } + if ( ok ) + *ok = resultCode == QDialog::Accepted; + + QColor::destroyAllocContext(allocContext); + delete dlg; + return result; +} + + + + + +/*! + Returns the color currently selected in the dialog. + + \sa setColor() +*/ + +QColor OColorDialog::color() const +{ + return QColor(d->currentColor()); +} + + +/*! Destructs the dialog and frees any memory it allocated. + +*/ + +OColorDialog::~OColorDialog() +{ + //d inherits QObject, so it is deleted by Qt. +} + + +/*! + Sets the color shown in the dialog to \a c. + + \sa color() +*/ + +void OColorDialog::setColor( const QColor& c ) +{ + d->setCurrentColor( c.rgb() ); +} + + + + +/*! + Sets the initial alpha channel value to \a a, and show the alpha channel + entry box. +*/ + +void OColorDialog::setSelectedAlpha( int a ) +{ + d->showAlpha( TRUE ); + d->setCurrentAlpha( a ); +} + + +/*! + Returns the value selected for the alpha channel. +*/ + +int OColorDialog::selectedAlpha() const +{ + return d->currentAlpha(); +} + +#include "colordialog.moc" diff --git a/noncore/unsupported/libopie/colordialog.h b/noncore/unsupported/libopie/colordialog.h new file mode 100644 index 0000000..c825a83 --- a/dev/null +++ b/noncore/unsupported/libopie/colordialog.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** $Id$ +** +** Definition of OColorDialog class +** +** Created : 990222 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef OColorDialog_H +#define OColorDialog_H + +#ifndef QT_H +#include <qdialog.h> +#endif // QT_H + +class OColorDialogPrivate; + +/* + * @class OColorDialog + * @brief The OColorDialog class is a copy of QColorDialog for use in Opie. + * + * OColorDialog is a copy of TrollTech's QColorDialog for use in Opie. The default + * build of QT/Embedded used by Opie does not include QColorDialog, so it is provided + * here. It is renamed to prevent conflicts in the event the QColorDialog is included + * at a later date in QP/E. + * + * See http://doc.trolltech.com/2.3/qcolordialog.html for complete documentation of + * QColorDialog. + */ +class Q_EXPORT OColorDialog : public QDialog +{ + Q_OBJECT + +public: + static QColor getColor( const QColor&, QWidget *parent=0, const char* name=0 ); + static QRgb getRgba( const QRgb&, bool* ok = 0, + QWidget *parent=0, const char* name=0 ); + +private: + ~OColorDialog(); + + // FIXME add WFlags? -zecke + OColorDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE ); + void setColor( const QColor& ); + QColor color() const; + +private: + void setSelectedAlpha( int ); + int selectedAlpha() const; +private: + OColorDialogPrivate *d; + friend class OColorDialogPrivate; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + OColorDialog( const OColorDialog & ); + OColorDialog& operator=( const OColorDialog & ); +#endif +}; + +#endif diff --git a/noncore/unsupported/libopie/colorpopupmenu.cpp b/noncore/unsupported/libopie/colorpopupmenu.cpp new file mode 100644 index 0000000..03ad233 --- a/dev/null +++ b/noncore/unsupported/libopie/colorpopupmenu.cpp @@ -0,0 +1,172 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 S. Prud'homme <prudhomme@laposte.net> + Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "colorpopupmenu.h" +#include "colordialog.h" + +#include <qlayout.h> +#include <qpainter.h> + +OColorPanelButton::OColorPanelButton( const QColor& color, QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + m_color = color; + + setFixedSize( 16, 16 ); + setActive( FALSE ); +} + +OColorPanelButton::~OColorPanelButton() +{ +} + +void OColorPanelButton::setActive( bool active ) +{ + m_active = active; + + if ( m_active ) { + setFrameStyle( Panel | Sunken ); + } else { + setFrameStyle( NoFrame ); + } +} + +void OColorPanelButton::enterEvent( QEvent* ) +{ + if ( !m_active ) { + setFrameStyle( Panel | Sunken ); + } +} + +void OColorPanelButton::leaveEvent( QEvent* ) +{ + if ( !m_active ) { + setFrameStyle( NoFrame ); + } +} + +void OColorPanelButton::paintEvent( QPaintEvent* e ) +{ + QFrame::paintEvent( e ); + + QPainter painter; + painter.begin( this ); + painter.fillRect( 2, 2, 12, 12, m_color ); + painter.setPen( Qt::black ); + painter.drawRect( 2, 2, 12, 12 ); + painter.end(); +} + +void OColorPanelButton::mouseReleaseEvent( QMouseEvent* ) +{ + emit selected( m_color ); +} + +OColorPopupMenu::OColorPopupMenu( const QColor& color, QWidget* parent, const char* name ) + : QPopupMenu( parent, name ) +{ + m_color = color; + + colorPanel = new QWidget( this ); + + colorLayout = new QGridLayout(colorPanel, 5, 6); + + addColor(QColor(255, 255, 255), 0, 1); + addColor(QColor(192, 192, 192), 0, 2); + addColor(QColor(128, 128, 128), 0, 3); + addColor(QColor(64, 64, 64), 0, 4); + addColor(QColor(0, 0, 0), 0, 5); + + addColor(QColor(255, 0, 0), 1, 0); + addColor(QColor(255, 128, 0), 1, 1); + addColor(QColor(255, 255, 0), 1, 2); + addColor(QColor(128, 255, 0), 1, 3); + addColor(QColor(0, 255, 0), 1, 4); + addColor(QColor(0, 255, 128), 1, 5); + + addColor(QColor(128, 0, 0), 2, 0); + addColor(QColor(128, 64, 0), 2, 1); + addColor(QColor(128, 128, 0), 2, 2); + addColor(QColor(64, 128, 0), 2, 3); + addColor(QColor(0, 128, 0), 2, 4); + addColor(QColor(0, 128, 64), 2, 5); + + addColor(QColor(0, 255, 255), 3, 0); + addColor(QColor(0, 128, 255), 3, 1); + addColor(QColor(0, 0, 255), 3, 2); + addColor(QColor(128, 0, 255), 3, 3); + addColor(QColor(255, 0, 255), 3, 4); + addColor(QColor(255, 0, 128), 3, 5); + + addColor(QColor(0, 128, 128), 4, 0); + addColor(QColor(0, 64, 128), 4, 1); + addColor(QColor(0, 0, 128), 4, 2); + addColor(QColor(64, 0, 128), 4, 3); + addColor(QColor(128, 0, 128), 4, 4); + addColor(QColor(128, 0, 64), 4, 5); + + insertItem( colorPanel ); + insertSeparator(); + insertItem(tr("More"),this,SLOT( moreColorClicked())); + /* + QAction* chooseColorAction = new QAction( tr( "More" ), tr( "More..." ), 0, colorPanel, "More" ); + connect( chooseColorAction, SIGNAL( activated() ), this, SLOT( moreColorClicked() ) ); + chooseColorAction->addTo( this ); + */ + activateItemAt( 0 ); +} + +OColorPopupMenu::~OColorPopupMenu() +{ +} + +void OColorPopupMenu::addColor( const QColor& color, int row, int col ) +{ + OColorPanelButton* panelButton = new OColorPanelButton( color, colorPanel ); + connect( panelButton, SIGNAL( selected(const QColor&) ), this, SLOT( buttonSelected(const QColor&) ) ); + colorLayout->addWidget( panelButton, row, col ); +} + +void OColorPopupMenu::buttonSelected( const QColor& color ) +{ + m_color = color; + emit colorSelected( color ); + hide(); +} + +void OColorPopupMenu::moreColorClicked() +{ + QColor color = OColorDialog::getColor( m_color ); + m_color = color; + emit colorSelected( color ); + hide(); +} diff --git a/noncore/unsupported/libopie/colorpopupmenu.h b/noncore/unsupported/libopie/colorpopupmenu.h new file mode 100644 index 0000000..98d67cc --- a/dev/null +++ b/noncore/unsupported/libopie/colorpopupmenu.h @@ -0,0 +1,255 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 S. Prud'homme <prudhomme@laposte.net> + Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef COLORPOPUPMENU_H +#define COLORPOPUPMENU_H + +#include <qframe.h> +#include <qpopupmenu.h> + +class QWidget; +class QGridLayout; + +/** + * @class OColorPanelButton + * @brief The OColorPanelButton class provides a button for color selection. + * + * @see OColorPopupMenu + * + * The OColorPanelButton class provides a button for color selection. The button + * is drawn with the desired color and no border. This class is used internally + * by the OColorPopupMenu class to displaying colors in its menu. + */ +class OColorPanelButton : public QFrame +{ + Q_OBJECT + +public: + +/** + * @fn OColorPanelButton( const QColor& color, QWidget* parent = 0, const char* name = 0 ) + * @brief Object constructor. + * + * @param color Desired color. + * @param parent Pointer to parent of this control. + * @param name Name of control. + * + * Constructs a new ColorPanelButton control with parent, name and desired color. + */ + OColorPanelButton(const QColor& color, QWidget* parent = 0, const char* name = 0); + +/** + * @fn ~OColorPanelButton() + * @brief Object destructor. + */ + ~OColorPanelButton(); + +/** + * @fn setActive( bool active ) + * @brief Sets button selection state. + * + * @param active Boolean indicator of new button state. + * + * Changes button selection state. If button is selected, a highlighted border + * is drawn. + */ + void setActive(bool active); + +/** + * @fn enterEvent( QEvent* e ) + * @brief Reimplemented for internal reasons. + * + * @param e Event currently being processed. + * + * Reimplemented to ensure correct display of button based on whether it is + * active or not. + */ + void enterEvent(QEvent* e); + +/** + * @fn leaveEvent( QEvent* e ) + * @brief Reimplemented for internal reasons. + * + * @param e Event currently being processed. + * + * Reimplemented to ensure correct display of button based on whether it is + * active or not. + */ + void leaveEvent(QEvent* e); + +/** + * @fn paintEvent( QPaintEvent* e ) + * @brief Reimplemented for internal reasons. + * + * @param e Event currently being processed. + * @reimp + * Reimplemented to ensure correct display of button. + */ + void paintEvent(QPaintEvent* e); + +/** + * @fn mouseReleaseEvent( QMouseEvent* e ) + * @brief Slot executed when button is pressed. + * + * @param e Mouse event currently being processed. + * + * @see selected() + * + * This slot executes when the button has been pressed. It emits the selected + * signal as notification that it has been pressed. + */ + void mouseReleaseEvent(QMouseEvent* e); + +signals: + +/** + * @fn selected( const QColor& color ) + * @brief Signal to indicate button has been pressed. + * + * @param color Button color. + * + * This signal is emitted when the button is pressed. It provides the color + * associated to this button. + */ + void selected(const QColor&); + +private: + QColor m_color; + bool m_active : 1; + class ColorPanelButtonPrivate; + ColorPanelButtonPrivate *d; +}; + +/** + * @class OColorPopupMenu + * @brief The OColorPopupMenu class provides a small color selection + * popup menu. + * + * OColorPopupMenu is a derivation of TrollTech's QPopupMenu and provides + * a small color selection popup menu which can be attached to another control + * such as a toolbar button of menu item. + * + * The popup menu displays 30 default colors available in a grid, and also + * includes an option at the bottom to display a color selection dialog box for + * finer color control. + */ +class OColorPopupMenu : public QPopupMenu +{ + Q_OBJECT + +public: + +/** + * @fn OColorPopupMenu( const QColor& color, QWidget* parent = 0, const char* name = 0 ) + * @brief Object constructor. + * + * @param color Initial color selected in menu. + * @param parent Pointer to parent of this control. + * @param name Name of control. + * + * Constructs a new OColorPopupMenu control with parent, name and initial color selected. + */ + // FIXME add Wflags? -zecke + OColorPopupMenu( const QColor& color, QWidget* parent = 0, const char* name = 0 ); + +/** + * @fn ~OColorPopupMenu() + * @brief Object destructor. + */ + ~OColorPopupMenu(); + +private: + class ColorPopupMenuPrivate; + ColorPopupMenuPrivate *d; + QColor m_color; + QWidget* colorPanel; + QGridLayout* colorLayout; + +/** + * @fn addColor( const QColor& color, int row, int col ) + * @brief Adds color selection option to popup menu. + * + * @param color Color to be displayed in menu. + * @param row Row where color is to appear in menu. + * @param col Column where color is to appear in menu. + * + * Adds a color selection option to popup menu. Used internally when + * initially constructing the menu control. + */ + void addColor( const QColor& color, int row, int col ); + +signals: + +/** + * @fn colorSelected( const QColor& color ) + * @brief Signal to indicate color chosen from the menu. + * + * @param color Color selected from the menu. + * + * This signal is emitted when a color has been selected either directly from + * the menu, or chosen from the color selection dialog. + */ + void colorSelected( const QColor& color ); + +protected slots: + +/** + * @fn buttonSelected( const QColor& color ) + * @brief Slot to process selected color. + * + * @param color Color selected from the menu. + * + * @see colorSelected() + * + * This slot executes when a color has been selected from the menu. It performs + * two functions: + * - Emit the colorSelected signal with the color selected. + * - Hide the menu. + */ + void buttonSelected( const QColor& color ); + +/** + * @fn moreColorClicked() + * @brief Slot to process display color selection dialog. + * + * @see colorSelected() + * + * This slot executes when the 'More...' option is selected at the bottom of the menu. + * It performs the following functions: + * - Constructs and executes a OColorDialog to allow finer color selection. + * - Emit the colorSelected signal with the color selected. + * - Hide the menu. + */ + void moreColorClicked(); +}; + +#endif // COLORPOPUPMENUANEL_H diff --git a/noncore/unsupported/libopie/config.in b/noncore/unsupported/libopie/config.in new file mode 100644 index 0000000..e8bc2e2 --- a/dev/null +++ b/noncore/unsupported/libopie/config.in @@ -0,0 +1,4 @@ + config LIBOPIE + boolean "libopie1 (compatibility only, use libopie2* for new applications)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) diff --git a/noncore/unsupported/libopie/libopie.pro b/noncore/unsupported/libopie/libopie.pro new file mode 100644 index 0000000..783c11d --- a/dev/null +++ b/noncore/unsupported/libopie/libopie.pro @@ -0,0 +1,102 @@ +TEMPLATE = lib +CONFIG += qte warn_on +HEADERS = ofontmenu.h \ + ocolorbutton.h \ + ofiledialog.h ofileselector.h \ + ofileselector_p.h \ + ocheckitem.h \ + xmltree.h \ + colordialog.h colorpopupmenu.h \ + oclickablelabel.h oprocctrl.h \ + oprocess.h odevice.h odevicebutton.h \ + otimepicker.h otabwidget.h \ + otabbar.h otabinfo.h \ + ofontselector.h \ + pim/opimrecord.h \ + pim/otodo.h \ + pim/orecordlist.h \ + pim/opimaccesstemplate.h \ + pim/opimaccessbackend.h \ + pim/otodoaccess.h \ + pim/otodoaccessbackend.h \ + pim/oconversion.h \ + pim/ocontact.h \ + pim/ocontactfields.h \ + pim/ocontactaccess.h \ + pim/ocontactaccessbackend.h \ + pim/ocontactaccessbackend_xml.h \ + pim/ocontactaccessbackend_vcard.h \ + pim/obackendfactory.h \ + pim/opimcache.h \ + pim/otodoaccessvcal.h \ + pim/orecur.h \ + pim/opimstate.h \ + pim/opimxrefpartner.h \ + pim/opimxref.h \ + pim/opimxrefmanager.h \ + pim/opimmaintainer.h \ + pim/opimnotify.h \ + pim/opimnotifymanager.h \ + pim/opimmainwindow.h \ + pim/opimresolver.h \ + pim/oevent.h \ + pim/otimezone.h \ + pim/odatebookaccess.h \ + pim/odatebookaccessbackend.h \ + pim/odatebookaccessbackend_xml.h \ + orecurrancewidget.h \ + oticker.h owait.h + +SOURCES = ofontmenu.cc \ + ocolorbutton.cpp \ + sharp_compat.cpp \ + xmltree.cc \ + ofiledialog.cc ofileselector.cpp \ + ocheckitem.cpp \ + colordialog.cpp \ + colorpopupmenu.cpp oclickablelabel.cpp \ + oprocctrl.cpp oprocess.cpp \ + odevice.cpp odevicebutton.cpp otimepicker.cpp \ + otabwidget.cpp otabbar.cpp \ + ofontselector.cpp \ + pim/otodo.cpp \ + pim/opimrecord.cpp \ + pim/otodoaccess.cpp \ + pim/otodoaccessbackend.cpp \ + pim/otodoaccessxml.cpp \ + pim/oconversion.cpp \ + pim/ocontact.cpp \ + pim/ocontactfields.cpp \ + pim/ocontactaccess.cpp \ + pim/ocontactaccessbackend_vcard.cpp \ + pim/ocontactaccessbackend_xml.cpp \ + pim/otodoaccessvcal.cpp \ + pim/orecur.cpp \ + pim/opimstate.cpp \ + pim/opimxrefpartner.cpp \ + pim/opimxref.cpp \ + pim/opimxrefmanager.cpp \ + pim/opimmaintainer.cpp \ + pim/opimnotify.cpp \ + pim/opimnotifymanager.cpp \ + pim/opimmainwindow.cpp \ + pim/opimresolver.cpp \ + pim/oevent.cpp \ + pim/otimezone.cpp \ + pim/odatebookaccess.cpp \ + pim/odatebookaccessbackend.cpp \ + pim/odatebookaccessbackend_xml.cpp \ + orecurrancewidget.cpp \ + oticker.cpp owait.cpp + +TARGET = opie +INCLUDEPATH += $(OPIEDIR)/include +DESTDIR = $(OPIEDIR)/lib$(PROJMAK) + +LIBS += -lqpe + +INTERFACES = otimepickerbase.ui orecurrancebase.ui +TARGET = opie + + +include ( $(OPIEDIR)/include.pro ) diff --git a/noncore/unsupported/libopie/libopie1.control b/noncore/unsupported/libopie/libopie1.control new file mode 100644 index 0000000..5b6825e --- a/dev/null +++ b/noncore/unsupported/libopie/libopie1.control @@ -0,0 +1,11 @@ +Package: libopie1 +Files: lib/libopie.so.1.0.0 lib/libopie.so.1.0 lib/libopie.so.1 +Priority: optional +Section: opie/system +Maintainer: Opie Team <opie@handhelds.org> +Architecture: arm +Depends: libqte2 (>=$QTE_VERSION), libqpe1, opie-pics +Provides: libopie +Replaces: libopie +Description: Opie library +Version: $QPE_VERSION$EXTRAVERSION diff --git a/noncore/unsupported/libopie/libopie1.postinst b/noncore/unsupported/libopie/libopie1.postinst new file mode 100755 index 0000000..0c37b3d --- a/dev/null +++ b/noncore/unsupported/libopie/libopie1.postinst @@ -0,0 +1,4 @@ +#!/bin/sh + +[ -x /sbin/ldconfig ] && /sbin/ldconfig +exit 0 diff --git a/noncore/unsupported/libopie/oapplicationfactory.h b/noncore/unsupported/libopie/oapplicationfactory.h new file mode 100644 index 0000000..ab88d80 --- a/dev/null +++ b/noncore/unsupported/libopie/oapplicationfactory.h @@ -0,0 +1,264 @@ +/* + This work is derived from: + ---- + The Loki Library + Copyright (c) 2001 by Andrei Alexandrescu + This code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design + Patterns Applied". Copyright (c) 2001. Addison-Wesley. + Permission to use, copy, modify, distribute and sell this software for any + purpose is hereby granted without fee, provided that the above copyright + notice appear in all copies and that both that copyright notice and this + permission notice appear in supporting documentation. + The author or Addison-Welsey Longman make no representations about the + suitability of this software for any purpose. It is provided "as is" + without express or implied warranty. + ---- + + And KGenericFactor et all from Simon Hausmann <tronical@kde.org> + +*/ + +#include <qstring.h> +#include <qmetaobject.h> + +#include <qtopia/qcom.h> +#include <qtopia/applicationinterface.h> + +namespace Opie { + struct NullType; + + template <class T, class U> + struct Typelist + { + typedef T Head; + typedef U Tail; + }; + template< + typename T1 = NullType, typename T2 = NullType, typename T3 = NullType, + typename T4 = NullType, typename T5 = NullType, typename T6 = NullType, + typename T7 = NullType, typename T8 = NullType, typename T9 = NullType, + typename T10 = NullType, typename T11 = NullType, typename T12 = NullType, + typename T13 = NullType, typename T14 = NullType, typename T15 = NullType, + typename T16 = NullType, typename T17 = NullType, typename T18 = NullType + > + struct MakeTypelist{ + private: + typedef typename MakeTypelist + < + T2 , T3 , T4 , + T5 , T6 , T7 , + T8 , T9 , T10, + T11, T12, T13, + T14, T15, T16, + T17, T18 + > + ::Result TailResult; + +public: + typedef Typelist<T1, TailResult> Result; +}; + +template<> +struct MakeTypelist<> +{ + typedef NullType Result; +}; + +} + +/** + * To allow your application to be quick launched some one needs + * to create the QWidget. + * This is this factory. Make surce your widget has static QString Widget::appName() + * as one of its functions. + * + * This template takes one QWidget and initialized it in the form of + * MyWidget::MyWidget( QWidget* parent, const char* name, WFlags f ); + * + * To use it on your app do that: + * typedef OApplicationFactory<MyWidget> MyFactory; + * OPIE_EXPORT_APP( MyFactory ) + * + */ +template <class Product> +struct OApplicationFactory : public ApplicationInterface { + QRESULT queryInterface( const QUuid &uuid, QUnknownInterface **iface ) { + *iface = 0; + if ( uuid == IID_QUnknown ) *iface = this; + else if ( uuid == IID_QtopiaApplication ) *iface = this; + else return QS_FALSE; + (*iface)->addRef(); + return QS_OK; + } + + /* + * + */ + virtual QWidget *createMainWindow( const QString& appName, QWidget* parent, + const char* name, Qt::WFlags f ) { + if (appName == Product::appName() ) + return new Product(parent, name, f ); + else + return 0l; + } + + virtual QStringList applications()const { + QStringList list; + list << Product::appName() ; + + return list; + } + Q_REFCOUNT + +}; + + +/* Internal */ + +template< class Product > +struct OPrivate { + inline static QWidget *multiFactory( const QString& appName, QWidget* parent, + const char* name, Qt::WFlags fl ) { + if ( appName == Product::appName() ) + return new Product( parent, name, fl ); + else + return 0; + } + + inline static QStringList multiString( const QStringList& _list ) { + QStringList list = _list; + list << Product::appName(); + return list; + } +}; + +template <> +struct OPrivate<Opie::NullType > { + inline static QWidget* multiFactory ( const QString& , QWidget* , + const char* , Qt::WFlags ) { + return 0l; + } + inline static QStringList multiString( const QStringList& _list ) { + return _list; + } +}; + +/* +template <> +struct OPrivate <Opie::NullType, Opie::NullType > { + inline static QWidget* multiFactory( const QString& , QWidget* , + const char* , Qt::WFlags ) { + return 0l; + } + + inline static QStringList multiString( const QStringList& _list ) { + return _list; + } +}; +*/ + +template <class Product, class ProductListTail> +struct OPrivate< Opie::Typelist<Product, ProductListTail> > { + inline static QWidget* multiFactory( const QString& appName, QWidget* parent, + const char* name, Qt::WFlags fl) { + QWidget* wid = OPrivate<Product>::multiFactory( appName, parent, name, fl ); + + if (!wid ) + wid = OPrivate<ProductListTail>::multiFactory( appName, parent, name, fl ); + + return wid; + } + + inline static QStringList multiString( const QStringList& _list ) { + QStringList list = _list; + + list = OPrivate<Product>::multiString( list ); + list = OPrivate<ProductListTail>::multiString( list ); + + return list; + } +}; + + + + + + + + +/* Internal END */ + +/* + * If you want to export more than one Widget use that function + * Make sure all your Widgets provide the appName() static method + * otherwise you'll get a compiler error + * + * typedef Opie::MakeTypeList<MyWidget, MyDialog, MyMediaPlayer >::Result MyTypes; + * OPIE_EXPORT_APP( OApplicationFactory<MyTypes> ) + */ + +template<class Product, class ProductListTail> +struct OApplicationFactory< Opie::Typelist<Product, ProductListTail > > + : ApplicationInterface { + QRESULT queryInterface( const QUuid &uuid, QUnknownInterface **iface ) { + *iface = 0; + if ( uuid == IID_QUnknown ) *iface = this; + else if ( uuid ==IID_QtopiaApplication ) *iface = this; + else return QS_FALSE; + (*iface)->addRef(); + return QS_OK; + } + + QWidget* createMainWindow ( const QString& appName, QWidget* parent, + const char* name, Qt::WFlags fl ) { + qWarning("StringList is %s", applications().join(":").latin1() ); + return OPrivate< Opie::Typelist<Product, ProductListTail > >::multiFactory( appName, parent, name, fl ); + } + + QStringList applications()const { + QStringList _list; + return OPrivate< Opie::Typelist<Product, ProductListTail> >::multiString( _list ); + } + + Q_REFCOUNT +}; + + +/* If the library version should be build */ +#ifdef OPIE_APP_INTERFACE +#define OPIE_EXPORT_APP( factory ) Q_EXPORT_INTERFACE() { Q_CREATE_INSTANCE( factory ) } +#else + +#include <qpe/qpeapplication.h> + +#define OPIE_EXPORT_APP( Factory ) \ +int main( int argc, char **argv ) { \ + QPEApplication a(argc, argv ); \ + QWidget *mw = 0;\ +\ + /* method from TT */ \ + QString executableName = QString::fromLatin1( argv[0] ); \ + executableName = executableName.right(executableName.length() \ + - executableName.findRev('/') - 1); \ + \ + Factory f; \ + QStringList list = f.applications(); \ + if (list.contains(executableName) ) \ + mw = f.createMainWindow(executableName, 0, 0, 0 ); \ + else \ + mw = f.createMainWindow( list[0], 0, 0, 0 ); \ +\ + if( mw ) { \ + if ( mw->metaObject()->slotNames().contains("setDocument(const QString&)" ) ) \ + a.showMainDocumentWidget( mw ); \ + else \ + a.showMainWidget( mw ); \ +\ + int rv = a.exec(); \ + delete mw; \ + return rv; \ + }else \ + return -1; \ +} +#endif diff --git a/noncore/unsupported/libopie/ocheckitem.cpp b/noncore/unsupported/libopie/ocheckitem.cpp new file mode 100644 index 0000000..cd763c1 --- a/dev/null +++ b/noncore/unsupported/libopie/ocheckitem.cpp @@ -0,0 +1,105 @@ +/********************************************************************** +** Copyright (C) 2002 Stefan Eilers (se, eilers.stefan@epost.de +** +** This file may be distributed and/or modified under the terms of the +** GNU Library General Public License version 2 as published by the +** Free Software Foundation and appearing in the file LICENSE.GPL +** included in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +**********************************************************************/ + + +#include "ocheckitem.h" + +/** + * Constructs an CheckItem with a QTable as parent + * and a sort key for. + * The sort key will be used by QTable to sort the table later + * @param t The parent QTable where the check item belongs + * @param key A sort key + */ +OCheckItem::OCheckItem( QTable *t, const QString &key ) + : QTableItem( t, Never, "" ), m_checked( FALSE ), m_sortKey( key ) +{ +} + +/** + * reimplemted for internal reasons + * @return Returns the sort key of the Item + * @see QTableItem + */ +QString OCheckItem::key() const +{ + return m_sortKey; +} + +/** + * This method can check or uncheck the item. It will + * call QTable to update the cell. + * + * @param b Whether to check or uncheck the item + */ +void OCheckItem::setChecked( bool b ) +{ + m_checked = b; + table()->updateCell( row(), col() ); +} + +/** + * This will toggle the item. If it is checked it'll get + * unchecked by this method or vice versa. + */ +void OCheckItem::toggle() +{ + m_checked = !m_checked; +} + +/** + * This will return the state of the item. + * + * @return Returns true if the item is checked + */ +bool OCheckItem::isChecked() const +{ + return m_checked; +} + +/** + * @internal + * This paints the item + */ +void OCheckItem::paint( QPainter *p, const QColorGroup &cg, const QRect &cr, + bool ) +{ + p->fillRect( 0, 0, cr.width(), cr.height(), cg.brush( QColorGroup::Base ) ); + + int marg = ( cr.width() - BoxSize ) / 2; + int x = 0; + int y = ( cr.height() - BoxSize ) / 2; + p->setPen( QPen( cg.text() ) ); + p->drawRect( x + marg, y, BoxSize, BoxSize ); + p->drawRect( x + marg+1, y+1, BoxSize-2, BoxSize-2 ); + p->setPen( darkGreen ); + x += 1; + y += 1; + if ( m_checked ) { + QPointArray a( 7*2 ); + int i, xx, yy; + xx = x+1+marg; + yy = y+2; + for ( i=0; i<3; i++ ) { + a.setPoint( 2*i, xx, yy ); + a.setPoint( 2*i+1, xx, yy+2 ); + xx++; yy++; + } + yy -= 2; + for ( i=3; i<7; i++ ) { + a.setPoint( 2*i, xx, yy ); + a.setPoint( 2*i+1, xx, yy+2 ); + xx++; yy--; + } + p->drawLineSegments( a ); + } +} diff --git a/noncore/unsupported/libopie/ocheckitem.h b/noncore/unsupported/libopie/ocheckitem.h new file mode 100644 index 0000000..82ee3d0 --- a/dev/null +++ b/noncore/unsupported/libopie/ocheckitem.h @@ -0,0 +1,62 @@ +/********************************************************************** +** Copyright (C) 2002 Stefan Eilers (se, eilers.stefan@epost.de) +** +** This file may be distributed and/or modified under the terms of the +** GNU Library General Public License version 2 as published by the +** Free Software Foundation and appearing in the file LICENSE.GPL +** included in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +**********************************************************************/ +#include <qtable.h> + +#ifndef CHECKITEM_H__ +#define CHECKITEM_H__ + +/** + * This class represents a checkable QTableItem. This can + * be added to any QTable. + * + * + * @see QTable + * @see QTableItem + * @short An checkable QTableItem + * @version 1.0 + * @author Stefan Eilers ( eilers@handhelds.org ) + */ + +class OCheckItem : public QTableItem +{ +public: + /** The size of a box currently unused */ + enum Size { BoxSize = 10 }; + OCheckItem( QTable *t, const QString &sortkey ); + + virtual void setChecked( bool b ); + virtual void toggle(); + bool isChecked() const; + /** + * @short Set the sort key + * @reimp + */ + void setKey( const QString &key ) { m_sortKey = key; } + virtual QString key() const; + + /** + * foo + * @internal + */ + void paint( QPainter *p, const QColorGroup &cg, const QRect &cr, bool selected ); + + //static const int BoxSize = 10; + +private: + class OCheckItemPrivate; + OCheckItemPrivate *d; + bool m_checked: 1; + QString m_sortKey; + +}; + +#endif diff --git a/noncore/unsupported/libopie/oclickablelabel.cpp b/noncore/unsupported/libopie/oclickablelabel.cpp new file mode 100644 index 0000000..bc7037b --- a/dev/null +++ b/noncore/unsupported/libopie/oclickablelabel.cpp @@ -0,0 +1,117 @@ +#include "oclickablelabel.h" +#include <stdio.h> + +/** + * This constructs the clickable ButtonLabel + * + * @param parent The parent of this label + * @param name A name of this label @see QObject + * @param fl The windowing flags + */ +OClickableLabel::OClickableLabel(QWidget* parent, + const char* name, + WFlags fl) : + QLabel(parent,name,fl) +{ + textInverted=false; + isToggle=false; + isDown=false; + showState(false); + setFrameShadow(Sunken); +} + +/** + * This method makes the label behave as a toggle button + * + * @param t Whether or not to behave like a toggle button + */ +void OClickableLabel::setToggleButton(bool t) { + isToggle=t; +} + +/** + * @internal + */ +void OClickableLabel::mousePressEvent( QMouseEvent * /*e*/ ) { + if (isToggle && isDown) { + showState(false); + } else { + showState(true); + } +} + +/** + * @internal + */ +void OClickableLabel::mouseReleaseEvent( QMouseEvent *e ) { + if (rect().contains(e->pos()) && isToggle) isDown=!isDown; + + if (isToggle && isDown) { + showState(true); + } else { + showState(false); + } + + if (rect().contains(e->pos())) { + if (isToggle) { + emit toggled(isDown); + } + emit clicked(); + } +} + +/** + * @internal + */ +void OClickableLabel::mouseMoveEvent( QMouseEvent *e ) { + if (rect().contains(e->pos())) { + if (isToggle && isDown) { + showState(false); + } else { + showState(true); + } + } else { + if (isToggle && isDown) { + showState(true); + } else { + showState(false); + } + } +} + +/** + * this toggles the label and inverts the color of + * the label + * @param on + */ +void OClickableLabel::showState(bool on) { + if (on) { + //setFrameShape(Panel); + setInverted(true); + setBackgroundMode(PaletteHighlight); + } else { + //setFrameShape(NoFrame); + setInverted(false); + setBackgroundMode(PaletteBackground); + } + repaint(); +} + +void OClickableLabel::setInverted(bool on) { + if ( (!textInverted && on) || (textInverted && !on) ) { + QPalette pal=palette(); + QColor col=pal.color(QPalette::Normal, QColorGroup::Foreground); + col.setRgb(255-col.red(),255-col.green(),255-col.blue()); + pal.setColor(QPalette::Normal, QColorGroup::Foreground, col); + setPalette(pal); + textInverted=!textInverted; + } +} + +/** + * @param on if the Label is down or up + */ +void OClickableLabel::setOn(bool on) { + isDown=on; + showState(isDown); +} diff --git a/noncore/unsupported/libopie/oclickablelabel.h b/noncore/unsupported/libopie/oclickablelabel.h new file mode 100644 index 0000000..f93ade0 --- a/dev/null +++ b/noncore/unsupported/libopie/oclickablelabel.h @@ -0,0 +1,68 @@ +#ifndef CLICKABLELABEL +#define CLICKABLELABEL + +#include <qlabel.h> + +/** + * This class is a special QLabel which can behave + * as a QPushButton or QToggleButton. + * The reason to use a clickable is if you want to save space + * or you want to skip the border of a normal button + * + * <pre> + * QLabel* lbl = new OClickableLabel( parent, "PushLabel" ); + * lbl->setPixmap( "config" ); + * QWhatsThis::add( lbl, tr("Click here to do something") ); + * </pre> + * + * @short A Label behaving as button + * @author Hakan Ardo, Maximillian Reiß ( harlekin@handhelds.org ) + * @see QLabel + * @see QPushButton + * @see QToggleButton + * @version 1.0 + */ + +class OClickableLabel: public QLabel +{ + Q_OBJECT +public: + OClickableLabel(QWidget* parent = 0, const char* name = 0, + WFlags fl = 0); + void setToggleButton(bool t); + + protected: + /** @internal */ + void mousePressEvent( QMouseEvent *e ); + /** @internal */ + void mouseReleaseEvent( QMouseEvent *e ); + /** @internal */ + void mouseMoveEvent( QMouseEvent *e ); + + public slots: + void setOn(bool on); + signals: + /** + * emitted when the labels gets clicked + */ + void clicked(); + + /** + * emitted when the labels gets toggled + * @param on the new new state of the label + */ + void toggled(bool on); + private: + bool isToggle : 1; + bool isDown : 1; + bool textInverted : 1; + + void showState(bool on); + void setInverted(bool on); + + private: + class Private; + Private *d; // private d pointer +}; + +#endif diff --git a/noncore/unsupported/libopie/ocolorbutton.cpp b/noncore/unsupported/libopie/ocolorbutton.cpp new file mode 100644 index 0000000..298dba2 --- a/dev/null +++ b/noncore/unsupported/libopie/ocolorbutton.cpp @@ -0,0 +1,139 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Robert Griebl <sandman@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <opie/colorpopupmenu.h> +#include <opie/ocolorbutton.h> + +#include <qpe/resource.h> + +struct OColorButtonPrivate { + QPopupMenu *m_menu; + QColor m_color; +}; + + +/** + * This concstructs a Color Button with @param color as the start color + * It'll use a OColorPopupMenu internally + * + * @param parent The parent of the Color Button + * @param color The color from where to start on + * @param name @see QObject + */ +OColorButton::OColorButton ( QWidget *parent, const QColor &color, const char *name ) + : QPushButton ( parent, name ) +{ + d = new OColorButtonPrivate; + + d-> m_menu = new OColorPopupMenu ( color, 0, 0 ); + setPopup ( d-> m_menu ); +// setPopupDelay ( 0 ); + connect ( d-> m_menu, SIGNAL( colorSelected(const QColor&)), this, SLOT( updateColor(const QColor&))); + + updateColor ( color ); + + QSize s = sizeHint ( ) + QSize ( 12, 0 ); + setMinimumSize ( s ); + setMaximumSize ( s. width ( ) * 2, s. height ( )); +} + +/** + * This destructs the object + */ +OColorButton::~OColorButton ( ) +{ + delete d; +} + +/** + * @return Returns the current color of the button + */ +QColor OColorButton::color ( ) const +{ + return d-> m_color; +} + +/** + * This method sets the color of the button + * @param c The color to be set. + */ +void OColorButton::setColor ( const QColor &c ) +{ + updateColor ( c ); +} + +/** + * @internal + */ +void OColorButton::updateColor ( const QColor &c ) +{ + d-> m_color = c; + + QImage img ( 16, 16, 32 ); + img. fill ( 0 ); + + int r, g, b; + c. rgb ( &r, &g, &b ); + + int w = img. width ( ); + int h = img. height ( ); + + int dx = w * 20 / 100; // 15% + int dy = h * 20 / 100; + + for ( int y = 0; y < h; y++ ) { + for ( int x = 0; x < w; x++ ) { + double alpha = 1.0; + + if ( x < dx ) + alpha *= ( double ( x + 1 ) / dx ); + else if ( x >= w - dx ) + alpha *= ( double ( w - x ) / dx ); + if ( y < dy ) + alpha *= ( double ( y + 1 ) / dy ); + else if ( y >= h - dy ) + alpha *= ( double ( h - y ) / dy ); + + int a = int ( alpha * 255.0 ); + if ( a < 0 ) + a = 0; + if ( a > 255 ) + a = 255; + + img. setPixel ( x, y, qRgba ( r, g, b, a )); + } + } + img. setAlphaBuffer ( true ); + + QPixmap pix; + pix. convertFromImage ( img ); + setPixmap ( pix ); + + emit colorSelected ( c ); +} + diff --git a/noncore/unsupported/libopie/ocolorbutton.h b/noncore/unsupported/libopie/ocolorbutton.h new file mode 100644 index 0000000..6196c83 --- a/dev/null +++ b/noncore/unsupported/libopie/ocolorbutton.h @@ -0,0 +1,73 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Robert Griebl <sandman@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef __OPIE_OCOLORBUTTON_H__ +#define __OPIE_OCOLORBUTTON_H__ + +#include <qpushbutton.h> + +class OColorButtonPrivate; +class QColor; + +/** + * + * @short A Button which will show a OColorPopupMenu + * @author Robert Griebl ( sandman@handhelds.org ) + * @version 1.0 + * @see QPushButton + */ +class OColorButton : public QPushButton { + Q_OBJECT +public: + // FIXME Wflags? -zecke + OColorButton ( QWidget *parent = 0, const QColor & = black, const char *name = 0 ); + virtual ~OColorButton ( ); + + QColor color ( ) const; + +signals: + /** + * emitted when a color gets selected + */ + void colorSelected ( const QColor & ); + +public slots: + virtual void setColor ( const QColor & ); + +protected slots: + /** + * @internal + */ + virtual void updateColor ( const QColor & ); + +private: + OColorButtonPrivate *d; +}; + +#endif + diff --git a/noncore/unsupported/libopie/odevice.cpp b/noncore/unsupported/libopie/odevice.cpp new file mode 100644 index 0000000..9d0bbbf --- a/dev/null +++ b/noncore/unsupported/libopie/odevice.cpp @@ -0,0 +1,2827 @@ +/* This file is part of the OPIE libraries + Copyright (C) 2002 Robert Griebl (sandman@handhelds.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <signal.h> +#include <sys/time.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif +#include <math.h> + + +#include <qfile.h> +#include <qtextstream.h> +#include <qpe/sound.h> +#include <qpe/resource.h> +#include <qpe/config.h> +#include <qpe/qcopenvelope_qws.h> + +#include "odevice.h" + +#include <qwindowsystem_qws.h> + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class ODeviceData { +public: + QString m_vendorstr; + OVendor m_vendor; + + QString m_modelstr; + OModel m_model; + + QString m_systemstr; + OSystem m_system; + + QString m_sysverstr; + + Transformation m_rotation; + ODirection m_direction; + + QValueList <ODeviceButton> *m_buttons; + uint m_holdtime; + QStrList *m_cpu_frequencies; + +}; + +class iPAQ : public ODevice, public QWSServer::KeyboardFilter { +protected: + virtual void init ( ); + virtual void initButtons ( ); + +public: + virtual bool setSoftSuspend ( bool soft ); + + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + + virtual void alarmSound ( ); + + virtual QValueList <OLed> ledList ( ) const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState ( OLed led ) const; + virtual bool setLedState ( OLed led, OLedState st ); + + virtual bool hasLightSensor ( ) const; + virtual int readLightSensor ( ); + virtual int lightSensorResolution ( ) const; + +protected: + virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent ( QTimerEvent *te ); + + int m_power_timer; + + OLedState m_leds [2]; +}; + +class Jornada : public ODevice { +protected: + virtual void init ( ); + //virtual void initButtons ( ); +public: + virtual bool setSoftSuspend ( bool soft ); + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + static bool isJornada(); + +}; + +class Zaurus : public ODevice { +protected: + virtual void init ( ); + virtual void initButtons ( ); + +public: + virtual bool setSoftSuspend ( bool soft ); + + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + + virtual void alarmSound ( ); + virtual void keySound ( ); + virtual void touchSound ( ); + + virtual QValueList <OLed> ledList ( ) const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState ( OLed led ) const; + virtual bool setLedState ( OLed led, OLedState st ); + + bool hasHingeSensor() const; + OHingeStatus readHingeSensor(); + + static bool isZaurus(); + + // Does this break BC? + virtual bool suspend ( ); + Transformation rotation ( ) const; + ODirection direction ( ) const; + +protected: + virtual void buzzer ( int snd ); + + OLedState m_leds [1]; + bool m_embedix; + void virtual_hook( int id, void *data ); +}; + +class SIMpad : public ODevice, public QWSServer::KeyboardFilter { +protected: + virtual void init ( ); + virtual void initButtons ( ); + +public: + virtual bool setSoftSuspend ( bool soft ); + virtual bool suspend(); + + virtual bool setDisplayStatus( bool on ); + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + + virtual void alarmSound ( ); + + virtual QValueList <OLed> ledList ( ) const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState ( OLed led ) const; + virtual bool setLedState ( OLed led, OLedState st ); + +protected: + virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent ( QTimerEvent *te ); + + int m_power_timer; + + OLedState m_leds [1]; //FIXME check if really only one +}; + +class Ramses : public ODevice, public QWSServer::KeyboardFilter { +protected: + virtual void init ( ); + +public: + virtual bool setSoftSuspend ( bool soft ); + virtual bool suspend ( ); + + virtual bool setDisplayStatus( bool on ); + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + virtual bool setDisplayContrast ( int b ); + virtual int displayContrastResolution ( ) const; + +protected: + virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent ( QTimerEvent *te ); + + int m_power_timer; +}; + +struct i_button { + uint model; + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} ipaq_buttons [] = { + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/ipaq_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/ipaq_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx, + Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/ipaq_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), + "devicebuttons/ipaq_mail", + "mail", "raise()", + "mail", "newMail()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/ipaq_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F24, QT_TRANSLATE_NOOP("Button", "Record Button"), + "devicebuttons/ipaq_record", + "QPE/VMemo", "toggleRecord()", + "sound", "raise()" }, +}; + +struct z_button { + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} z_buttons [] = { + { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/z_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/z_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/z_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/z_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), + "devicebuttons/z_mail", + "mail", "raise()", + "mail", "newMail()" }, +}; + +struct z_button z_buttons_c700 [] = { + { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/z_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/z_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/z_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/z_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Qt::Key_F14, QT_TRANSLATE_NOOP("Button", "Display Rotate"), + "devicebuttons/z_hinge", + "QPE/Rotation", "rotateDefault()", + "QPE/Dummy", "doNothing()" }, +}; + +struct s_button { + uint model; + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} simpad_buttons [] = { + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Lower+Up"), + "devicebuttons/simpad_lower_up", + "datebook", "nextView()", + "today", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Lower+Down"), + "devicebuttons/simpad_lower_down", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Lower+Right"), + "devicebuttons/simpad_lower_right", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Lower+Left"), + "devicebuttons/simpad_lower_left", + "mail", "raise()", + "mail", "newMail()" }, + + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F5, QT_TRANSLATE_NOOP("Button", "Upper+Up"), + "devicebuttons/simpad_upper_up", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F6, QT_TRANSLATE_NOOP("Button", "Upper+Down"), + "devicebuttons/simpad_upper_down", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F7, QT_TRANSLATE_NOOP("Button", "Upper+Right"), + "devicebuttons/simpad_upper_right", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Upper+Left"), + "devicebuttons/simpad_upper_left", + "QPE/Rotation", "flip()", + "QPE/Rotation", "flip()" }, + /* + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), + "devicebuttons/simpad_lower_upper", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), + "devicebuttons/simpad_upper_lower", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + */ +}; + +class Yopy : public ODevice { +protected: + virtual void init ( ); + virtual void initButtons ( ); + +public: + virtual bool suspend ( ); + + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution ( ) const; + + static bool isYopy ( ); +}; + +struct yopy_button { + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} yopy_buttons [] = { + { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Action Button"), + "devicebuttons/yopy_action", + "datebook", "nextView()", + "today", "raise()" }, + { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "OK Button"), + "devicebuttons/yopy_ok", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "End Button"), + "devicebuttons/yopy_end", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, +}; + +static QCString makeChannel ( const char *str ) +{ + if ( str && !::strchr ( str, '/' )) + return QCString ( "QPE/Application/" ) + str; + else + return str; +} + +static inline bool isQWS() +{ + return qApp ? ( qApp-> type ( ) == QApplication::GuiServer ) : false; +} + +ODevice *ODevice::inst ( ) +{ + static ODevice *dev = 0; + + if ( !dev ) { + if ( QFile::exists ( "/proc/hal/model" )) + dev = new iPAQ ( ); + else if ( Zaurus::isZaurus() ) + dev = new Zaurus ( ); + else if ( QFile::exists ( "/proc/ucb1x00" ) && QFile::exists ( "/proc/cs3" )) + dev = new SIMpad ( ); + else if ( Yopy::isYopy() ) + dev = new Yopy ( ); + else if ( Jornada::isJornada() ) + dev = new Jornada ( ); + else if ( QFile::exists ( "/proc/sys/board/sys_name" )) + dev = new Ramses ( ); + else + dev = new ODevice ( ); + dev-> init ( ); + } + return dev; +} + + +/************************************************** + * + * common + * + **************************************************/ + + +ODevice::ODevice ( ) +{ + d = new ODeviceData; + + d-> m_modelstr = "Unknown"; + d-> m_model = Model_Unknown; + d-> m_vendorstr = "Unknown"; + d-> m_vendor = Vendor_Unknown; + d-> m_systemstr = "Unknown"; + d-> m_system = System_Unknown; + d-> m_sysverstr = "0.0"; + d-> m_rotation = Rot0; + d-> m_direction = CW; + + d-> m_holdtime = 1000; // 1000ms + d-> m_buttons = 0; + d-> m_cpu_frequencies = new QStrList; +} + +void ODevice::systemMessage ( const QCString &msg, const QByteArray & ) +{ + if ( msg == "deviceButtonMappingChanged()" ) { + reloadButtonMapping ( ); + } +} + +void ODevice::init ( ) +{ +} + +/** + * This method initialises the button mapping + */ +void ODevice::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + // Simulation uses iPAQ 3660 device buttons + + qDebug ( "init Buttons" ); + d-> m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { + i_button *ib = ipaq_buttons + i; + ODeviceButton b; + + if (( ib-> model & Model_iPAQ_H36xx ) == Model_iPAQ_H36xx ) { + b. setKeycode ( ib-> code ); + b. setUserText ( QObject::tr ( "Button", ib-> utext )); + b. setPixmap ( Resource::loadPixmap ( ib-> pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib-> fpressedservice ), ib-> fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib-> fheldservice ), ib-> fheldaction )); + d-> m_buttons-> append ( b ); + } + } + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received(const QCString&,const QByteArray&)), this, SLOT( systemMessage(const QCString&,const QByteArray&))); +} + +ODevice::~ODevice ( ) +{ +// we leak m_devicebuttons and m_cpu_frequency +// but it's a singleton and it is not so importantant +// -zecke + delete d; +} + +bool ODevice::setSoftSuspend ( bool /*soft*/ ) +{ + return false; +} + +//#include <linux/apm_bios.h> + +#define APM_IOC_SUSPEND OD_IO( 'A', 2 ) + +/** + * This method will try to suspend the device + * It only works if the user is the QWS Server and the apm application + * is installed. + * It tries to suspend and then waits some time cause some distributions + * do have asynchronus apm implementations. + * This method will either fail and return false or it'll suspend the + * device and return once the device got woken up + * + * @return if the device got suspended + */ +bool ODevice::suspend ( ) +{ + qDebug("ODevice::suspend"); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + if ( d-> m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices + return false; + + bool res = false; + + struct timeval tvs, tvn; + ::gettimeofday ( &tvs, 0 ); + + ::sync ( ); // flush fs caches + res = ( ::system ( "apm --suspend" ) == 0 ); + + // This is needed because the iPAQ apm implementation is asynchronous and we + // can not be sure when exactly the device is really suspended + // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. + + if ( res ) { + do { // wait at most 1.5 sec: either suspend didn't work or the device resumed + ::usleep ( 200 * 1000 ); + ::gettimeofday ( &tvn, 0 ); + } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 1500 ); + } + + return res; +} + +//#include <linux/fb.h> better not rely on kernel headers in userspace ... + +#define FBIOBLANK OD_IO( 'F', 0x11 ) // 0x4611 + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +/** + * This sets the display on or off + */ +bool ODevice::setDisplayStatus ( bool on ) +{ + qDebug("ODevice::setDisplayStatus(%d)", on); + + if ( d-> m_model == Model_Unknown ) + return false; + + bool res = false; + int fd; + +#ifdef QT_QWS_DEVFS + if (( fd = ::open ( "/dev/fb/0", O_RDWR )) >= 0 ) { +#else + if (( fd = ::open ( "/dev/fb0", O_RDWR )) >= 0 ) { +#endif + res = ( ::ioctl ( fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN ) == 0 ); + ::close ( fd ); + } + return res; +} + +/** + * This sets the display brightness + * + * @param p The brightness to be set on a scale from 0 to 255 + * @return success or failure + */ +bool ODevice::setDisplayBrightness ( int p) +{ + Q_UNUSED( p ) + return false; +} + +/** + * @return returns the number of steppings on the brightness slider + * in the Light-'n-Power settings. + */ +int ODevice::displayBrightnessResolution ( ) const +{ + return 16; +} + +/** + * This sets the display contrast + * @param p The contrast to be set on a scale from 0 to 255 + * @return success or failure + */ +bool ODevice::setDisplayContrast ( int p) +{ + Q_UNUSED( p ) + return false; +} + +/** + * @return return the max value for the brightness settings slider + * or 0 if the device doesn't support setting of a contrast + */ +int ODevice::displayContrastResolution ( ) const +{ + return 0; +} + +/** + * This returns the vendor as string + * @return Vendor as QString + */ +QString ODevice::vendorString ( ) const +{ + return d-> m_vendorstr; +} + +/** + * This returns the vendor as one of the values of OVendor + * @return OVendor + */ +OVendor ODevice::vendor ( ) const +{ + return d-> m_vendor; +} + +/** + * This returns the model as a string + * @return A string representing the model + */ +QString ODevice::modelString ( ) const +{ + return d-> m_modelstr; +} + +/** + * This does return the OModel used + */ +OModel ODevice::model ( ) const +{ + return d-> m_model; +} + +/** + * This does return the systen name + */ +QString ODevice::systemString ( ) const +{ + return d-> m_systemstr; +} + +/** + * Return System as OSystem value + */ +OSystem ODevice::system ( ) const +{ + return d-> m_system; +} + +/** + * @return the version string of the base system + */ +QString ODevice::systemVersionString ( ) const +{ + return d-> m_sysverstr; +} + +/** + * @return the current Transformation + */ +Transformation ODevice::rotation ( ) const +{ + VirtRotation rot; + ODevice* that =(ODevice* )this; + that->virtual_hook( VIRTUAL_ROTATION, &rot ); + return rot.trans; +} + +/** + * @return the current rotation direction + */ +ODirection ODevice::direction ( ) const +{ + VirtDirection dir; + ODevice* that =(ODevice* )this; + that->virtual_hook( VIRTUAL_DIRECTION, &dir ); + return dir.direct; +} + +/** + * This plays an alarmSound + */ +void ODevice::alarmSound ( ) +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + + if ( snd. isFinished ( )) + snd. play ( ); +#endif +} + +/** + * This plays a key sound + */ +void ODevice::keySound ( ) +{ +#ifndef QT_NO_SOUND + static Sound snd ( "keysound" ); + + if ( snd. isFinished ( )) + snd. play ( ); +#endif +} + +/** + * This plays a touch sound + */ +void ODevice::touchSound ( ) +{ +#ifndef QT_NO_SOUND + static Sound snd ( "touchsound" ); + + if ( snd. isFinished ( )) + snd. play ( ); +#endif +} + +/** + * This method will return a list of leds + * available on this device + * @return a list of LEDs. + */ +QValueList <OLed> ODevice::ledList ( ) const +{ + return QValueList <OLed> ( ); +} + +/** + * This does return the state of the LEDs + */ +QValueList <OLedState> ODevice::ledStateList ( OLed /*which*/ ) const +{ + return QValueList <OLedState> ( ); +} + +/** + * @return the state for a given OLed + */ +OLedState ODevice::ledState ( OLed /*which*/ ) const +{ + return Led_Off; +} + +/** + * Set the state for a LED + * @param which Which OLed to use + * @param st The state to set + * @return success or failure + */ +bool ODevice::setLedState ( OLed which, OLedState st ) +{ + Q_UNUSED( which ) + Q_UNUSED( st ) + return false; +} + +/** + * @return if the device has a light sensor + */ +bool ODevice::hasLightSensor ( ) const +{ + return false; +} + +/** + * @return a value from the light sensor + */ +int ODevice::readLightSensor ( ) +{ + return -1; +} + +/** + * @return the light sensor resolution + */ +int ODevice::lightSensorResolution ( ) const +{ + return 0; +} + +/** + * @return if the device has a hinge sensor + */ +bool ODevice::hasHingeSensor ( ) const +{ + VirtHasHinge hing; + ODevice* that =(ODevice* )this; + that->virtual_hook( VIRTUAL_HAS_HINGE, &hing ); + return hing.hasHinge; +} + +/** + * @return a value from the hinge sensor + */ +OHingeStatus ODevice::readHingeSensor ( ) +{ + VirtHingeStatus hing; + virtual_hook( VIRTUAL_HINGE, &hing ); + return hing.hingeStat; +} + +/** + * @return a list with CPU frequencies supported by the hardware + */ +const QStrList &ODevice::allowedCpuFrequencies ( ) const +{ + return *d->m_cpu_frequencies; +} + + +/** + * Set desired CPU frequency + * + * @param index index into d->m_cpu_frequencies of the frequency to be set + */ +bool ODevice::setCurrentCpuFrequency(uint index) +{ + if (index >= d->m_cpu_frequencies->count()) + return false; + + char *freq = d->m_cpu_frequencies->at(index); + qWarning("set freq to %s", freq); + + int fd; + + if ((fd = ::open("/proc/sys/cpu/0/speed", O_WRONLY)) >= 0) { + char writeCommand[50]; + const int count = sprintf(writeCommand, "%s\n", freq); + int res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + return res; + } + + return false; +} + + +/** + * @return a list of hardware buttons + */ +const QValueList <ODeviceButton> &ODevice::buttons ( ) +{ + initButtons ( ); + + return *d-> m_buttons; +} + +/** + * @return The amount of time that would count as a hold + */ +uint ODevice::buttonHoldTime ( ) const +{ + return d-> m_holdtime; +} + +/** + * This method return a ODeviceButton for a key code + * or 0 if no special hardware button is available for the device + * + * @return The devicebutton or 0l + * @see ODeviceButton + */ +const ODeviceButton *ODevice::buttonForKeycode ( ushort code ) +{ + initButtons ( ); + + for ( QValueListConstIterator<ODeviceButton> it = d-> m_buttons-> begin ( ); it != d-> m_buttons-> end ( ); ++it ) { + if ( (*it). keycode ( ) == code ) + return &(*it); + } + return 0; +} + +void ODevice::reloadButtonMapping ( ) +{ + initButtons ( ); + + Config cfg ( "ButtonSettings" ); + + for ( uint i = 0; i < d-> m_buttons-> count ( ); i++ ) { + ODeviceButton &b = ( *d-> m_buttons ) [i]; + QString group = "Button" + QString::number ( i ); + + QCString pch, hch; + QCString pm, hm; + QByteArray pdata, hdata; + + if ( cfg. hasGroup ( group )) { + cfg. setGroup ( group ); + pch = cfg. readEntry ( "PressedActionChannel" ). latin1 ( ); + pm = cfg. readEntry ( "PressedActionMessage" ). latin1 ( ); + // pdata = decodeBase64 ( buttonFile. readEntry ( "PressedActionArgs" )); + + hch = cfg. readEntry ( "HeldActionChannel" ). latin1 ( ); + hm = cfg. readEntry ( "HeldActionMessage" ). latin1 ( ); + // hdata = decodeBase64 ( buttonFile. readEntry ( "HeldActionArgs" )); + } + + b. setPressedAction ( OQCopMessage ( pch, pm, pdata )); + + b. setHeldAction ( OQCopMessage ( hch, hm, hdata )); + } +} + +void ODevice::remapPressedAction ( int button, const OQCopMessage &action ) +{ + initButtons ( ); + + QString mb_chan; + + if ( button >= (int) d-> m_buttons-> count ( )) + return; + + ODeviceButton &b = ( *d-> m_buttons ) [button]; + b. setPressedAction ( action ); + + mb_chan=b. pressedAction ( ). channel ( ); + + Config buttonFile ( "ButtonSettings" ); + buttonFile. setGroup ( "Button" + QString::number ( button )); + buttonFile. writeEntry ( "PressedActionChannel", (const char*) mb_chan); + buttonFile. writeEntry ( "PressedActionMessage", (const char*) b. pressedAction ( ). message ( )); + +// buttonFile. writeEntry ( "PressedActionArgs", encodeBase64 ( b. pressedAction ( ). data ( ))); + + QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); +} + +void ODevice::remapHeldAction ( int button, const OQCopMessage &action ) +{ + initButtons ( ); + + if ( button >= (int) d-> m_buttons-> count ( )) + return; + + ODeviceButton &b = ( *d-> m_buttons ) [button]; + b. setHeldAction ( action ); + + Config buttonFile ( "ButtonSettings" ); + buttonFile. setGroup ( "Button" + QString::number ( button )); + buttonFile. writeEntry ( "HeldActionChannel", (const char *) b. heldAction ( ). channel ( )); + buttonFile. writeEntry ( "HeldActionMessage", (const char *) b. heldAction ( ). message ( )); + +// buttonFile. writeEntry ( "HeldActionArgs", decodeBase64 ( b. heldAction ( ). data ( ))); + + QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); +} +void ODevice::virtual_hook(int id, void* data){ + switch( id ) { + case VIRTUAL_ROTATION:{ + VirtRotation* rot = reinterpret_cast<VirtRotation*>( data ); + rot->trans = d->m_rotation; + break; + } + case VIRTUAL_DIRECTION:{ + VirtDirection *dir = reinterpret_cast<VirtDirection*>( data ); + dir->direct = d->m_direction; + break; + } + case VIRTUAL_HAS_HINGE:{ + VirtHasHinge *hin = reinterpret_cast<VirtHasHinge*>( data ); + hin->hasHinge = false; + break; + } + case VIRTUAL_HINGE:{ + VirtHingeStatus *hin = reinterpret_cast<VirtHingeStatus*>( data ); + hin->hingeStat = CASE_UNKNOWN; + break; + } + } +} + +/************************************************** + * + * Yopy 3500/3700 + * + **************************************************/ + +bool Yopy::isYopy ( ) +{ + QFile f( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine ( ) ) { + if ( line. left ( 8 ) == "Hardware" ) { + int loc = line. find ( ":" ); + if ( loc != -1 ) { + QString model = + line. mid ( loc + 2 ). simplifyWhiteSpace( ); + return ( model == "Yopy" ); + } + } + } + } + return false; +} + +void Yopy::init ( ) +{ + d-> m_vendorstr = "G.Mate"; + d-> m_vendor = Vendor_GMate; + d-> m_modelstr = "Yopy3700"; + d-> m_model = Model_Yopy_3700; + d-> m_rotation = Rot0; + + d-> m_systemstr = "Linupy"; + d-> m_system = System_Linupy; + + QFile f ( "/etc/issue" ); + if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + ts.readLine(); + d-> m_sysverstr = ts. readLine ( ); + f. close ( ); + } +} + +void Yopy::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + d-> m_buttons = new QValueList <ODeviceButton>; + + for (uint i = 0; i < ( sizeof( yopy_buttons ) / sizeof(yopy_button)); i++) { + + yopy_button *ib = yopy_buttons + i; + + ODeviceButton b; + + b. setKeycode ( ib-> code ); + b. setUserText ( QObject::tr ( "Button", ib-> utext )); + b. setPixmap ( Resource::loadPixmap ( ib-> pix )); + b. setFactoryPresetPressedAction + (OQCopMessage(makeChannel(ib->fpressedservice), ib->fpressedaction)); + b. setFactoryPresetHeldAction + (OQCopMessage(makeChannel(ib->fheldservice), ib->fheldaction)); + + d-> m_buttons-> append ( b ); + } + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel("QPE/System", this); + connect(sysch, SIGNAL(received(const QCString&,const QByteArray&)), + this, SLOT(systemMessage(const QCString&,const QByteArray&))); +} + +bool Yopy::suspend() +{ + /* Opie for Yopy does not implement its own power management at the + moment. The public version runs parallel to X, and relies on the + existing power management features. */ + return false; +} + +bool Yopy::setDisplayBrightness(int /*bright*/) +{ + /* The code here works, but is disabled as the current version runs + parallel to X, and relies on the existing backlight demon. */ +#if 0 + if ( QFile::exists("/proc/sys/pm/light") ) { + int fd = ::open("/proc/sys/pm/light", O_WRONLY); + if (fd >= 0 ) { + if (bright) + ::write(fd, "1\n", 2); + else + ::write(fd, "0\n", 2); + ::close(fd); + return true; + } + } +#endif + return false; +} + +int Yopy::displayBrightnessResolution() const +{ + return 2; +} + +/************************************************** + * + * iPAQ + * + **************************************************/ + +void iPAQ::init ( ) +{ + d-> m_vendorstr = "HP"; + d-> m_vendor = Vendor_HP; + + QFile f ( "/proc/hal/model" ); + + if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + + d-> m_modelstr = "H" + ts. readLine ( ); + + if ( d-> m_modelstr == "H3100" ) + d-> m_model = Model_iPAQ_H31xx; + else if ( d-> m_modelstr == "H3600" ) + d-> m_model = Model_iPAQ_H36xx; + else if ( d-> m_modelstr == "H3700" ) + d-> m_model = Model_iPAQ_H37xx; + else if ( d-> m_modelstr == "H3800" ) + d-> m_model = Model_iPAQ_H38xx; + else if ( d-> m_modelstr == "H3900" ) + d-> m_model = Model_iPAQ_H39xx; + else if ( d-> m_modelstr == "H5400" ) + d-> m_model = Model_iPAQ_H5xxx; + else + d-> m_model = Model_Unknown; + + f. close ( ); + } + + switch ( d-> m_model ) { + case Model_iPAQ_H31xx: + case Model_iPAQ_H38xx: + d-> m_rotation = Rot90; + break; + case Model_iPAQ_H36xx: + case Model_iPAQ_H37xx: + case Model_iPAQ_H39xx: + + default: + d-> m_rotation = Rot270; + break; + case Model_iPAQ_H5xxx: + d-> m_rotation = Rot0; + } + + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + d-> m_systemstr = "Familiar"; + d-> m_system = System_Familiar; + + QTextStream ts ( &f ); + d-> m_sysverstr = ts. readLine ( ). mid ( 10 ); + + f. close ( ); + } else { + f. setName ( "/etc/oz_version" ); + + if ( f. open ( IO_ReadOnly )) { + d-> m_systemstr = "OpenEmbedded/iPaq"; + d-> m_system = System_Familiar; + + QTextStream ts ( &f ); + ts.setDevice ( &f ); + d-> m_sysverstr = ts. readLine ( ); + f. close ( ); + } + } + + + + + + m_leds [0] = m_leds [1] = Led_Off; + + m_power_timer = 0; + +} + +void iPAQ::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + if ( isQWS( ) ) + QWSServer::setKeyboardFilter ( this ); + + d-> m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { + i_button *ib = ipaq_buttons + i; + ODeviceButton b; + + if (( ib-> model & d-> m_model ) == d-> m_model ) { + b. setKeycode ( ib-> code ); + b. setUserText ( QObject::tr ( "Button", ib-> utext )); + b. setPixmap ( Resource::loadPixmap ( ib-> pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib-> fpressedservice ), ib-> fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib-> fheldservice ), ib-> fheldaction )); + + d-> m_buttons-> append ( b ); + } + } + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received(const QCString&,const QByteArray&)), this, SLOT( systemMessage(const QCString&,const QByteArray&))); +} + + +//#include <linux/h3600_ts.h> // including kernel headers is evil ... + +typedef struct { + unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */ + unsigned char TotalTime; /* Units of 5 seconds */ + unsigned char OnTime; /* units of 100m/s */ + unsigned char OffTime; /* units of 100m/s */ +} LED_IN; + +typedef struct { + unsigned char mode; + unsigned char pwr; + unsigned char brightness; +} FLITE_IN; + +#define LED_ON OD_IOW( 'f', 5, LED_IN ) +#define FLITE_ON OD_IOW( 'f', 7, FLITE_IN ) + + +QValueList <OLed> iPAQ::ledList ( ) const +{ + QValueList <OLed> vl; + vl << Led_Power; + + if ( d-> m_model == Model_iPAQ_H38xx ) + vl << Led_BlueTooth; + return vl; +} + +QValueList <OLedState> iPAQ::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Power ) + vl << Led_Off << Led_On << Led_BlinkSlow << Led_BlinkFast; + else if ( l == Led_BlueTooth && d-> m_model == Model_iPAQ_H38xx ) + vl << Led_Off; // << Led_On << ??? + + return vl; +} + +OLedState iPAQ::ledState ( OLed l ) const +{ + switch ( l ) { + case Led_Power: + return m_leds [0]; + case Led_BlueTooth: + return m_leds [1]; + default: + return Led_Off; + } +} + +bool iPAQ::setLedState ( OLed l, OLedState st ) +{ + static int fd = ::open ( "/dev/touchscreen/0", O_RDWR | O_NONBLOCK ); + + if ( l == Led_Power ) { + if ( fd >= 0 ) { + LED_IN leds; + ::memset ( &leds, 0, sizeof( leds )); + leds. TotalTime = 0; + leds. OnTime = 0; + leds. OffTime = 1; + leds. OffOnBlink = 2; + + switch ( st ) { + case Led_Off : leds. OffOnBlink = 0; break; + case Led_On : leds. OffOnBlink = 1; break; + case Led_BlinkSlow: leds. OnTime = 10; leds. OffTime = 10; break; + case Led_BlinkFast: leds. OnTime = 5; leds. OffTime = 5; break; + } + + if ( ::ioctl ( fd, LED_ON, &leds ) >= 0 ) { + m_leds [0] = st; + return true; + } + } + } + return false; +} + + +bool iPAQ::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) +{ + int newkeycode = keycode; + + switch ( keycode ) { + // H38xx/H39xx have no "Q" key anymore - this is now the Mail key + case HardKey_Menu: { + if (( d-> m_model == Model_iPAQ_H38xx ) || + ( d-> m_model == Model_iPAQ_H39xx ) || + ( d-> m_model == Model_iPAQ_H5xxx)) { + newkeycode = HardKey_Mail; + } + break; + } + + // Rotate cursor keys 180° or 270° + case Key_Left : + case Key_Right: + case Key_Up : + case Key_Down : { + + if (( d-> m_model == Model_iPAQ_H31xx ) || + ( d-> m_model == Model_iPAQ_H38xx )) { + newkeycode = Key_Left + ( keycode - Key_Left + 2 ) % 4; + } + // Rotate the cursor keys by 270° + // keycode - Key_Left = position of the button starting from left clockwise + // add the rotation to it and modolo. No we've the original offset + // add the offset to the Key_Left key + if ( d-> m_model == Model_iPAQ_H5xxx ) + newkeycode = Key_Left + ( keycode - Key_Left + 3 ) % 4; + break; + } + + // map Power Button short/long press to F34/F35 + case Key_SysReq: { + if ( isPress ) { + if ( m_power_timer ) + killTimer ( m_power_timer ); + m_power_timer = startTimer ( 500 ); + } + else if ( m_power_timer ) { + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, false, false ); + } + newkeycode = Key_unknown; + break; + } + } + + if ( newkeycode != keycode ) { + if ( newkeycode != Key_unknown ) + QWSServer::sendKeyEvent ( -1, newkeycode, modifiers, isPress, autoRepeat ); + return true; + } + else + return false; +} + +void iPAQ::timerEvent ( QTimerEvent * ) +{ + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); +} + + +void iPAQ::alarmSound ( ) +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + int fd; + int vol; + bool vol_reset = false; + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play ( ); + while ( !snd. isFinished ( )) + qApp-> processEvents ( ); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } +#endif +} + + +bool iPAQ::setSoftSuspend ( bool soft ) +{ + bool res = false; + int fd; + + if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { + if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) + res = true; + else + ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); + + ::close ( fd ); + } + else + ::perror ( "/proc/sys/ts/suspend_button_mode" ); + + return res; +} + + +bool iPAQ::setDisplayBrightness ( int bright ) +{ + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 0 ) + bright = 0; + + if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { + FLITE_IN bl; + bl. mode = 1; + bl. pwr = bright ? 1 : 0; + bl. brightness = ( bright * ( displayBrightnessResolution ( ) - 1 ) + 127 ) / 255; + res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); + ::close ( fd ); + } + return res; +} + +int iPAQ::displayBrightnessResolution ( ) const +{ + switch ( model ( )) { + case Model_iPAQ_H31xx: + case Model_iPAQ_H36xx: + case Model_iPAQ_H37xx: + return 128; // really 256, but >128 could damage the LCD + + case Model_iPAQ_H38xx: + case Model_iPAQ_H39xx: + return 64; + case Model_iPAQ_H5xxx: + return 255; + + default: + return 2; + } +} + + +bool iPAQ::hasLightSensor ( ) const +{ + return true; +} + +int iPAQ::readLightSensor ( ) +{ + int fd; + int val = -1; + + if (( fd = ::open ( "/proc/hal/light_sensor", O_RDONLY )) >= 0 ) { + char buffer [8]; + + if ( ::read ( fd, buffer, 5 ) == 5 ) { + char *endptr; + + buffer [4] = 0; + val = ::strtol ( buffer + 2, &endptr, 16 ); + + if ( *endptr != 0 ) + val = -1; + } + ::close ( fd ); + } + + return val; +} + +int iPAQ::lightSensorResolution ( ) const +{ + return 256; +} + +/************************************************** + * + * Zaurus + * + **************************************************/ + +// Check whether this device is the sharp zaurus.. +// FIXME This gets unnecessary complicated. We should think about splitting the Zaurus +// class up into individual classes. We need three classes +// +// Zaurus-Collie (SA-model w/ 320x240 lcd, for SL5500 and SL5000) +// Zaurus-Poodle (PXA-model w/ 320x240 lcd, for SL5600) +// Zaurus-Corgi (PXA-model w/ 640x480 lcd, for C700, C750, C760, and C860) +// +// Only question right now is: Do we really need to do it? Because as soon +// as the OpenZaurus kernel is ready, there will be a unified interface for all +// Zaurus models (concerning apm, backlight, buttons, etc.) +// +// Comments? - mickeyl. + +bool Zaurus::isZaurus() +{ + + // If the special devices by embedix exist, it is quite simple: it is a Zaurus ! + if ( QFile::exists ( "/dev/sharp_buz" ) || QFile::exists ( "/dev/sharp_led" ) ){ + return true; + } + + // On non-embedix kernels, we have to look closer. + bool is_zaurus = false; + QFile f ( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QString model; + QFile f ( "/proc/cpuinfo" ); + + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine ( ) ) { + if ( line. left ( 8 ) == "Hardware" ) + break; + } + int loc = line. find ( ":" ); + if ( loc != -1 ) + model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); + + if ( model == "Sharp-Collie" + || model == "Collie" + || model == "SHARP Corgi" + || model == "SHARP Shepherd" + || model == "SHARP Poodle" + || model == "SHARP Husky" + ) + is_zaurus = true; + + } + return is_zaurus; +} + + +void Zaurus::init ( ) +{ + d-> m_vendorstr = "Sharp"; + d-> m_vendor = Vendor_Sharp; + m_embedix = true; // Not openzaurus means: It has an embedix kernel ! + + // QFile f ( "/proc/filesystems" ); + QString model; + + // It isn't a good idea to check the system configuration to + // detect the distribution ! + // Otherwise it may happen that any other distribution is detected as openzaurus, just + // because it uses a jffs2 filesystem.. + // (eilers) + // if ( f. open ( IO_ReadOnly ) && ( QTextStream ( &f ). read ( ). find ( "\tjffs2\n" ) >= 0 )) { + QFile f ("/etc/oz_version"); + if ( f.exists() ){ + d-> m_vendorstr = "OpenZaurus Team"; + d-> m_systemstr = "OpenZaurus"; + d-> m_system = System_OpenZaurus; + + if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + d-> m_sysverstr = ts. readLine ( );//. mid ( 10 ); + f. close ( ); + } + + // Openzaurus sometimes uses the embedix kernel! + // => Check whether this is an embedix kernel + FILE *uname = popen("uname -r", "r"); + QString line; + if ( f.open(IO_ReadOnly, uname) ) { + QTextStream ts ( &f ); + line = ts. readLine ( ); + int loc = line. find ( "embedix" ); + if ( loc != -1 ) + m_embedix = true; + else + m_embedix = false; + f. close ( ); + } + pclose(uname); + } + else { + d-> m_systemstr = "Zaurus"; + d-> m_system = System_Zaurus; + } + + f. setName ( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine ( ) ) { + if ( line. left ( 8 ) == "Hardware" ) + break; + } + int loc = line. find ( ":" ); + if ( loc != -1 ) + model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); + } + + if ( model == "SHARP Corgi" ) { + d-> m_model = Model_Zaurus_SLC7x0; + d-> m_modelstr = "Zaurus SL-C700"; + } else if ( model == "SHARP Shepherd" ) { + d-> m_model = Model_Zaurus_SLC7x0; + d-> m_modelstr = "Zaurus SL-C750"; + } else if ( model == "SHARP Husky" ) { + d-> m_model = Model_Zaurus_SLC7x0; + d-> m_modelstr = "Zaurus SL-C760"; + } else if ( model == "SHARP Poodle" ) { + d-> m_model = Model_Zaurus_SLB600; + d-> m_modelstr = "Zaurus SL-B500 or SL-5600"; + } else if ( model == "Sharp-Collie" || model == "Collie" ) { + d-> m_model = Model_Zaurus_SL5500; + d-> m_modelstr = "Zaurus SL-5500 or SL-5000d"; + } else { + d-> m_model = Model_Zaurus_SL5500; + d-> m_modelstr = "Zaurus (Model unknown)"; + } + + switch ( d-> m_model ) { + case Model_Zaurus_SLA300: + d-> m_rotation = Rot0; + break; + case Model_Zaurus_SLC7x0: + d-> m_rotation = rotation(); + d-> m_direction = direction(); + break; + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + d-> m_rotation = Rot270; + break; + } + m_leds [0] = Led_Off; +} + +void Zaurus::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + d-> m_buttons = new QValueList <ODeviceButton>; + + struct z_button * pz_buttons; + int buttoncount; + switch ( d-> m_model ) { + case Model_Zaurus_SLC7x0: + pz_buttons = z_buttons_c700; + buttoncount = ARRAY_SIZE(z_buttons_c700); + break; + default: + pz_buttons = z_buttons; + buttoncount = ARRAY_SIZE(z_buttons); + break; + } + + for ( int i = 0; i < buttoncount; i++ ) { + struct z_button *zb = pz_buttons + i; + ODeviceButton b; + + b. setKeycode ( zb-> code ); + b. setUserText ( QObject::tr ( "Button", zb-> utext )); + b. setPixmap ( Resource::loadPixmap ( zb-> pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( zb-> fpressedservice ), + zb-> fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( zb-> fheldservice ), + zb-> fheldaction )); + + d-> m_buttons-> append ( b ); + } + + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received(const QCString&,const QByteArray&)), + this, SLOT( systemMessage(const QCString&,const QByteArray&))); +} + +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +//#include <asm/sharp_char.h> // including kernel headers is evil ... + +#define SHARP_DEV_IOCTL_COMMAND_START 0x5680 + +#define SHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) + +#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ +#define SHARP_BUZ_KEYSOUND 2 /* key sound */ +#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ + +/* --- for SHARP_BUZZER device --- */ + +//#define SHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +//#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) + +#define SHARP_BUZZER_SETVOLUME (SHARP_BUZZER_IOCTL_START+1) +#define SHARP_BUZZER_GETVOLUME (SHARP_BUZZER_IOCTL_START+2) +#define SHARP_BUZZER_ISSUPPORTED (SHARP_BUZZER_IOCTL_START+3) +#define SHARP_BUZZER_SETMUTE (SHARP_BUZZER_IOCTL_START+4) +#define SHARP_BUZZER_STOPSOUND (SHARP_BUZZER_IOCTL_START+5) + +//#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ +//#define SHARP_BUZ_KEYSOUND 2 /* key sound */ + +//#define SHARP_PDA_ILLCLICKSOUND 3 /* illegal click */ +//#define SHARP_PDA_WARNSOUND 4 /* warning occurred */ +//#define SHARP_PDA_ERRORSOUND 5 /* error occurred */ +//#define SHARP_PDA_CRITICALSOUND 6 /* critical error occurred */ +//#define SHARP_PDA_SYSSTARTSOUND 7 /* system start */ +//#define SHARP_PDA_SYSTEMENDSOUND 8 /* system shutdown */ +//#define SHARP_PDA_APPSTART 9 /* application start */ +//#define SHARP_PDA_APPQUIT 10 /* application ends */ + +//#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ +//#define SHARP_BUZ_DAILY_ALARM 12 /* daily alarm */ +//#define SHARP_BUZ_GOT_PHONE_CALL 13 /* phone call sound */ +//#define SHARP_BUZ_GOT_MAIL 14 /* mail sound */ +// + +#define SHARP_LED_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +#define SHARP_LED_SETSTATUS (SHARP_LED_IOCTL_START+1) + +#define SHARP_IOCTL_GET_ROTATION 0x413c + +typedef struct sharp_led_status { + int which; /* select which LED status is wanted. */ + int status; /* set new led status if you call SHARP_LED_SETSTATUS */ +} sharp_led_status; + +#define SHARP_LED_MAIL_EXISTS 9 /* mail status (exists or not) */ + +#define LED_MAIL_NO_UNREAD_MAIL 0 /* for SHARP_LED_MAIL_EXISTS */ +#define LED_MAIL_NEWMAIL_EXISTS 1 /* for SHARP_LED_MAIL_EXISTS */ +#define LED_MAIL_UNREAD_MAIL_EX 2 /* for SHARP_LED_MAIL_EXISTS */ + +// #include <asm/sharp_apm.h> // including kernel headers is evil ... + +#define APM_IOCGEVTSRC OD_IOR( 'A', 203, int ) +#define APM_IOCSEVTSRC OD_IORW( 'A', 204, int ) +#define APM_EVT_POWER_BUTTON (1 << 0) + +#define FL_IOCTL_STEP_CONTRAST 100 + + +void Zaurus::buzzer ( int sound ) +{ +#ifndef QT_NO_SOUND + QString soundname; + + // Not all devices have real sound + if ( d->m_model == Model_Zaurus_SLC7x0 + || d->m_model == Model_Zaurus_SLB600 ){ + + switch ( sound ){ + case SHARP_BUZ_SCHEDULE_ALARM: + soundname = "alarm"; + break; + case SHARP_BUZ_TOUCHSOUND: + soundname = "touchsound"; + break; + case SHARP_BUZ_KEYSOUND: + soundname = "keysound"; + break; + default: + soundname = "alarm"; + + } + } + + // If a soundname is defined, we expect that this device has + // sound capabilities.. Otherwise we expect to have the buzzer + // device.. + if ( !soundname.isEmpty() ){ + int fd; + int vol; + bool vol_reset = false; + + Sound snd ( soundname ); + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play ( ); + while ( !snd. isFinished ( )) + qApp-> processEvents ( ); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } + } else { + int fd = ::open ( "/dev/sharp_buz", O_WRONLY|O_NONBLOCK ); + + if ( fd >= 0 ) { + ::ioctl ( fd, SHARP_BUZZER_MAKESOUND, sound ); + ::close ( fd ); + } + + } +#endif +} + + +void Zaurus::alarmSound ( ) +{ + buzzer ( SHARP_BUZ_SCHEDULE_ALARM ); +} + +void Zaurus::touchSound ( ) +{ + buzzer ( SHARP_BUZ_TOUCHSOUND ); +} + +void Zaurus::keySound ( ) +{ + buzzer ( SHARP_BUZ_KEYSOUND ); +} + + +QValueList <OLed> Zaurus::ledList ( ) const +{ + QValueList <OLed> vl; + vl << Led_Mail; + return vl; +} + +QValueList <OLedState> Zaurus::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Mail ) + vl << Led_Off << Led_On << Led_BlinkSlow; + return vl; +} + +OLedState Zaurus::ledState ( OLed which ) const +{ + if ( which == Led_Mail ) + return m_leds [0]; + else + return Led_Off; +} + +bool Zaurus::setLedState ( OLed which, OLedState st ) +{ + if (!m_embedix) // Currently not supported on non_embedix kernels + return false; + + static int fd = ::open ( "/dev/sharp_led", O_RDWR|O_NONBLOCK ); + + if ( which == Led_Mail ) { + if ( fd >= 0 ) { + struct sharp_led_status leds; + ::memset ( &leds, 0, sizeof( leds )); + leds. which = SHARP_LED_MAIL_EXISTS; + bool ok = true; + + switch ( st ) { + case Led_Off : leds. status = LED_MAIL_NO_UNREAD_MAIL; break; + case Led_On : leds. status = LED_MAIL_NEWMAIL_EXISTS; break; + case Led_BlinkSlow: leds. status = LED_MAIL_UNREAD_MAIL_EX; break; + default : ok = false; + } + + if ( ok && ( ::ioctl ( fd, SHARP_LED_SETSTATUS, &leds ) >= 0 )) { + m_leds [0] = st; + return true; + } + } + } + return false; +} + +bool Zaurus::setSoftSuspend ( bool soft ) +{ + if (!m_embedix) { + /* non-Embedix kernels dont have kernel autosuspend */ + return ODevice::setSoftSuspend( soft ); + } + + bool res = false; + int fd; + + if ((( fd = ::open ( "/dev/apm_bios", O_RDWR )) >= 0 ) || + (( fd = ::open ( "/dev/misc/apm_bios",O_RDWR )) >= 0 )) { + + int sources = ::ioctl ( fd, APM_IOCGEVTSRC, 0 ); // get current event sources + + if ( sources >= 0 ) { + if ( soft ) + sources &= ~APM_EVT_POWER_BUTTON; + else + sources |= APM_EVT_POWER_BUTTON; + + if ( ::ioctl ( fd, APM_IOCSEVTSRC, sources ) >= 0 ) // set new event sources + res = true; + else + perror ( "APM_IOCGEVTSRC" ); + } + else + perror ( "APM_IOCGEVTSRC" ); + + ::close ( fd ); + } + else + perror ( "/dev/apm_bios or /dev/misc/apm_bios" ); + + return res; +} + + +bool Zaurus::setDisplayBrightness ( int bright ) +{ + //qDebug( "Zaurus::setDisplayBrightness( %d )", bright ); + bool res = false; + int fd; + + if ( bright > 255 ) bright = 255; + if ( bright < 0 ) bright = 0; + + if ( m_embedix ) + { + if ( d->m_model == Model_Zaurus_SLC7x0 ) + { + //qDebug( "using special treatment for devices with the corgi backlight interface" ); + // special treatment for devices with the corgi backlight interface + if (( fd = ::open ( "/proc/driver/fl/corgi-bl", O_WRONLY )) >= 0 ) + { + int value = ( bright == 1 ) ? 1 : bright * ( 17.0 / 255.0 ); + char writeCommand[100]; + const int count = sprintf( writeCommand, "0x%x\n", value ); + res = ( ::write ( fd, writeCommand, count ) != -1 ); + ::close ( fd ); + } + return res; + } + else + { + // standard treatment for devices with the dumb embedix frontlight interface + if (( fd = ::open ( "/dev/fl", O_WRONLY )) >= 0 ) { + int bl = ( bright * 4 + 127 ) / 255; // only 4 steps on zaurus + if ( bright && !bl ) + bl = 1; + res = ( ::ioctl ( fd, FL_IOCTL_STEP_CONTRAST, bl ) == 0 ); + ::close ( fd ); + } + } + } + else + { + // special treatment for the OpenZaurus unified interface + #define FB_BACKLIGHT_SET_BRIGHTNESS _IOW('F', 1, u_int) /* set brightness */ + if (( fd = ::open ( "/dev/fb0", O_WRONLY )) >= 0 ) { + res = ( ::ioctl ( fd , FB_BACKLIGHT_SET_BRIGHTNESS, bright ) == 0 ); + ::close ( fd ); + } + } + return res; +} + +bool Zaurus::suspend ( ) +{ + qDebug("ODevice::suspend"); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + if ( d-> m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices + return false; + + bool res = false; + + struct timeval tvs, tvn; + ::gettimeofday ( &tvs, 0 ); + + ::sync ( ); // flush fs caches + res = ( ::system ( "apm --suspend" ) == 0 ); + + // This is needed because the iPAQ apm implementation is asynchronous and we + // can not be sure when exactly the device is really suspended + // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. + + if ( res ) { + do { // Yes, wait 15 seconds. This APM bug sucks big time. + ::usleep ( 200 * 1000 ); + ::gettimeofday ( &tvn, 0 ); + } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 15000 ); + } + + QCopEnvelope ( "QPE/Rotation", "rotateDefault()" ); + return res; +} + + +Transformation Zaurus::rotation ( ) const +{ + Transformation rot; + int handle = 0; + int retval = 0; + + switch ( d-> m_model ) { + case Model_Zaurus_SLC7x0: + handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) { + return Rot270; + } else { + retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + + if (retval == 2 ) + rot = Rot0; + else + rot = Rot270; + } + break; + case Model_Zaurus_SLA300: + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + rot = d-> m_rotation; + break; + } + + return rot; +} +ODirection Zaurus::direction ( ) const +{ + ODirection dir; + int handle = 0; + int retval = 0; + switch ( d-> m_model ) { + case Model_Zaurus_SLC7x0: + handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) { + dir = CW; + } else { + retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + if (retval == 2 ) + dir = CCW; + else + dir = CW; + } + break; + case Model_Zaurus_SLA300: + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + dir = d-> m_direction; + break; + } + return dir; + +} + +int Zaurus::displayBrightnessResolution ( ) const +{ + if (m_embedix) + return d->m_model == Model_Zaurus_SLC7x0 ? 18 : 5; + else + return 256; +} + +bool Zaurus::hasHingeSensor() const +{ + return d->m_model == Model_Zaurus_SLC7x0; +} + +OHingeStatus Zaurus::readHingeSensor() +{ + int handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) + { + qWarning("Zaurus::readHingeSensor() - failed (%s)", "unknown reason" ); //FIXME: use strerror + return CASE_UNKNOWN; + } + else + { + int retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + if ( retval == CASE_CLOSED || retval == CASE_PORTRAIT || retval == CASE_LANDSCAPE ) + { + qDebug( "Zaurus::readHingeSensor() - result = %d", retval ); + return static_cast<OHingeStatus>( retval ); + } + else + { + qWarning("Zaurus::readHingeSensor() - couldn't compute hinge status!" ); + return CASE_UNKNOWN; + } + } +} + + +void Zaurus::virtual_hook( int id, void *data ) { + switch( id ) { + case VIRTUAL_ROTATION:{ + VirtRotation* rot = reinterpret_cast<VirtRotation*>( data ); + rot->trans = rotation(); + break; + } + case VIRTUAL_DIRECTION:{ + VirtDirection *dir = reinterpret_cast<VirtDirection*>( data ); + dir->direct = direction(); + break; + } + case VIRTUAL_HAS_HINGE:{ + VirtHasHinge *hin = reinterpret_cast<VirtHasHinge*>( data ); + hin->hasHinge = hasHingeSensor(); + break; + } + case VIRTUAL_HINGE:{ + VirtHingeStatus *hin = reinterpret_cast<VirtHingeStatus*>( data ); + hin->hingeStat = readHingeSensor(); + break; + } + default: + ODevice::virtual_hook( id, data ); + break; + } +} + +/************************************************** + * + * SIMpad + * + **************************************************/ + +void SIMpad::init ( ) +{ + d-> m_vendorstr = "SIEMENS"; + d-> m_vendor = Vendor_SIEMENS; + + QFile f ( "/proc/hal/model" ); + + //TODO Implement model checking + //FIXME For now we assume an SL4 + + d-> m_modelstr = "SL4"; + d-> m_model = Model_SIMpad_SL4; + + switch ( d-> m_model ) { + default: + d-> m_rotation = Rot0; + d-> m_direction = CCW; + d-> m_holdtime = 1000; // 1000ms + + break; + } + + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + d-> m_systemstr = "Familiar"; + d-> m_system = System_Familiar; + + QTextStream ts ( &f ); + d-> m_sysverstr = ts. readLine ( ). mid ( 10 ); + + f. close ( ); + } else { + f. setName ( "/etc/oz_version" ); + + if ( f. open ( IO_ReadOnly )) { + d-> m_systemstr = "OpenEmbedded/SIMpad"; + d-> m_system = System_OpenZaurus; + + QTextStream ts ( &f ); + ts.setDevice ( &f ); + d-> m_sysverstr = ts. readLine ( ); + f. close ( ); + } + } + + m_leds [0] = m_leds [1] = Led_Off; + + m_power_timer = 0; + +} + +void SIMpad::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + if ( isQWS( ) ) + QWSServer::setKeyboardFilter ( this ); + + d-> m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( simpad_buttons ) / sizeof( s_button )); i++ ) { + s_button *sb = simpad_buttons + i; + ODeviceButton b; + + if (( sb-> model & d-> m_model ) == d-> m_model ) { + b. setKeycode ( sb-> code ); + b. setUserText ( QObject::tr ( "Button", sb-> utext )); + b. setPixmap ( Resource::loadPixmap ( sb-> pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( sb-> fpressedservice ), sb-> fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( sb-> fheldservice ), sb-> fheldaction )); + + d-> m_buttons-> append ( b ); + } + } + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received(const QCString&,const QByteArray&)), this, SLOT( systemMessage(const QCString&,const QByteArray&))); +} + +// SIMpad boardcontrol register CS3 +#define SIMPAD_BOARDCONTROL "/proc/cs3" +#define SIMPAD_VCC_5V_EN 0x0001 // For 5V PCMCIA +#define SIMPAD_VCC_3V_EN 0x0002 // FOR 3.3V PCMCIA +#define SIMPAD_EN1 0x0004 // This is only for EPROM's +#define SIMPAD_EN0 0x0008 // Both should be enable for 3.3V or 5V +#define SIMPAD_DISPLAY_ON 0x0010 +#define SIMPAD_PCMCIA_BUFF_DIS 0x0020 +#define SIMPAD_MQ_RESET 0x0040 +#define SIMPAD_PCMCIA_RESET 0x0080 +#define SIMPAD_DECT_POWER_ON 0x0100 +#define SIMPAD_IRDA_SD 0x0200 // Shutdown for powersave +#define SIMPAD_RS232_ON 0x0400 +#define SIMPAD_SD_MEDIAQ 0x0800 // Shutdown for powersave +#define SIMPAD_LED2_ON 0x1000 +#define SIMPAD_IRDA_MODE 0x2000 // Fast/Slow IrDA mode +#define SIMPAD_ENABLE_5V 0x4000 // Enable 5V circuit +#define SIMPAD_RESET_SIMCARD 0x8000 + +//SIMpad touchscreen backlight strength control +#define SIMPAD_BACKLIGHT_CONTROL "/proc/driver/mq200/registers/PWM_CONTROL" +#define SIMPAD_BACKLIGHT_MASK 0x00a10044 + +QValueList <OLed> SIMpad::ledList ( ) const +{ + QValueList <OLed> vl; + vl << Led_Power; //FIXME which LED is LED2 ? The green one or the amber one? + //vl << Led_Mail; //TODO find out if LED1 is accessible anyway + return vl; +} + +QValueList <OLedState> SIMpad::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Power ) //FIXME which LED is LED2 ? The green one or the amber one? + vl << Led_Off << Led_On; + //else if ( l == Led_Mail ) //TODO find out if LED1 is accessible anyway + //vl << Led_Off; + return vl; +} + +OLedState SIMpad::ledState ( OLed l ) const +{ + switch ( l ) { + case Led_Power: + return m_leds [0]; + //case Led_Mail: + // return m_leds [1]; + default: + return Led_Off; + } +} + +bool SIMpad::setLedState ( OLed l, OLedState st ) +{ + static int fd = ::open ( SIMPAD_BOARDCONTROL, O_RDWR | O_NONBLOCK ); + + if ( l == Led_Power ) { + if ( fd >= 0 ) { + LED_IN leds; + ::memset ( &leds, 0, sizeof( leds )); + leds. TotalTime = 0; + leds. OnTime = 0; + leds. OffTime = 1; + leds. OffOnBlink = 2; + + switch ( st ) { + case Led_Off : leds. OffOnBlink = 0; break; + case Led_On : leds. OffOnBlink = 1; break; + case Led_BlinkSlow: leds. OnTime = 10; leds. OffTime = 10; break; + case Led_BlinkFast: leds. OnTime = 5; leds. OffTime = 5; break; + } + + { + /*TODO Implement this like that: + read from cs3 + && with SIMPAD_LED2_ON + write to cs3 */ + m_leds [0] = st; + return true; + } + } + } + return false; +} + + +bool SIMpad::filter ( int /*unicode*/, int /*keycode*/, int /*modifiers*/, bool /*isPress*/, bool /*autoRepeat*/ ) +{ + //TODO + return false; +} + +void SIMpad::timerEvent ( QTimerEvent * ) +{ + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); +} + + +void SIMpad::alarmSound ( ) +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + int fd; + int vol; + bool vol_reset = false; + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play ( ); + while ( !snd. isFinished ( )) + qApp-> processEvents ( ); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } +#endif +} + + +bool SIMpad::suspend ( ) // Must override because SIMpad does NOT have apm +{ + qDebug( "ODevice for SIMpad: suspend()" ); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + bool res = false; + + struct timeval tvs; + ::gettimeofday ( &tvs, 0 ); + + ::sync ( ); // flush fs caches + res = ( ::system ( "cat /dev/fb/0 >/tmp/.buffer; echo > /proc/sys/pm/suspend; cat /tmp/.buffer >/dev/fb/0" ) == 0 ); //TODO make better :) + + return res; +} + + +bool SIMpad::setSoftSuspend ( bool soft ) +{ + qDebug( "ODevice for SIMpad: UNHANDLED setSoftSuspend(%s)", soft? "on" : "off" ); + return false; +} + + +bool SIMpad::setDisplayStatus ( bool on ) +{ + qDebug( "ODevice for SIMpad: setDisplayStatus(%s)", on? "on" : "off" ); + + bool res = false; + + QString cmdline = QString().sprintf( "echo %s > /proc/cs3", on ? "0xd41a" : "0xd40a" ); //TODO make better :) + + res = ( ::system( (const char*) cmdline ) == 0 ); + + return res; +} + + +bool SIMpad::setDisplayBrightness ( int bright ) +{ + qDebug( "ODevice for SIMpad: setDisplayBrightness( %d )", bright ); + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 1 ) + bright = 0; + + if (( fd = ::open ( SIMPAD_BACKLIGHT_CONTROL, O_WRONLY )) >= 0 ) { + int value = 255 - bright; + const int mask = SIMPAD_BACKLIGHT_MASK; + value = value << 8; + value += mask; + char writeCommand[100]; + const int count = sprintf( writeCommand, "0x%x\n", value ); + res = ( ::write ( fd, writeCommand, count ) != -1 ); + ::close ( fd ); + } + return res; +} + + +int SIMpad::displayBrightnessResolution ( ) const +{ + return 255; // All SIMpad models share the same display +} + +/************************************************** + * + * Ramses + * + **************************************************/ + +void Ramses::init() +{ + d->m_vendorstr = "M und N"; + d->m_vendor = Vendor_MundN; + + QFile f("/proc/sys/board/ramses"); + + d->m_modelstr = "Ramses"; + d->m_model = Model_Ramses_MNCI; + + d->m_rotation = Rot90; + d->m_holdtime = 1000; + + f.setName("/etc/oz_version"); + + if (f.open(IO_ReadOnly)) { + d->m_systemstr = "OpenEmbedded/Ramses"; + d->m_system = System_OpenZaurus; + + QTextStream ts(&f); + ts.setDevice(&f); + d->m_sysverstr = ts.readLine(); + f.close(); + } + + m_power_timer = 0; + +#ifdef QT_QWS_ALLOW_OVERCLOCK +#warning *** Overclocking enabled - this may fry your hardware - you have been warned *** +#define OC(x...) x +#else +#define OC(x...) +#endif + + + // This table is true for a Intel XScale PXA 255 + + d->m_cpu_frequencies->append("99000"); // mem= 99, run= 99, turbo= 99, PXbus= 50 +OC( d->m_cpu_frequencies->append("118000"); ) // mem=118, run=118, turbo=118, PXbus= 59 OC'd mem + d->m_cpu_frequencies->append("199100"); // mem= 99, run=199, turbo=199, PXbus= 99 +OC( d->m_cpu_frequencies->append("236000"); ) // mem=118, run=236, turbo=236, PXbus=118 OC'd mem + d->m_cpu_frequencies->append("298600"); // mem= 99, run=199, turbo=298, PXbus= 99 +OC( d->m_cpu_frequencies->append("354000"); ) // mem=118, run=236, turbo=354, PXbus=118 OC'd mem + d->m_cpu_frequencies->append("398099"); // mem= 99, run=199, turbo=398, PXbus= 99 + d->m_cpu_frequencies->append("398100"); // mem= 99, run=398, turbo=398, PXbus=196 +OC( d->m_cpu_frequencies->append("471000"); ) // mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus + +} + +bool Ramses::filter(int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat) +{ + Q_UNUSED( keycode ); + Q_UNUSED( modifiers ); + Q_UNUSED( isPress ); + Q_UNUSED( autoRepeat ); + return false; +} + +void Ramses::timerEvent(QTimerEvent *) +{ + killTimer(m_power_timer); + m_power_timer = 0; + QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, true, false); + QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, false, false); +} + + +bool Ramses::setSoftSuspend(bool soft) +{ + qDebug("Ramses::setSoftSuspend(%d)", soft); +#if 0 + bool res = false; + int fd; + + if (((fd = ::open("/dev/apm_bios", O_RDWR)) >= 0) || + ((fd = ::open("/dev/misc/apm_bios",O_RDWR)) >= 0)) { + + int sources = ::ioctl(fd, APM_IOCGEVTSRC, 0); // get current event sources + + if (sources >= 0) { + if (soft) + sources &= ~APM_EVT_POWER_BUTTON; + else + sources |= APM_EVT_POWER_BUTTON; + + if (::ioctl(fd, APM_IOCSEVTSRC, sources) >= 0) // set new event sources + res = true; + else + perror("APM_IOCGEVTSRC"); + } + else + perror("APM_IOCGEVTSRC"); + + ::close(fd); + } + else + perror("/dev/apm_bios or /dev/misc/apm_bios"); + + return res; +#else + return true; +#endif +} + +bool Ramses::suspend ( ) +{ + qDebug("Ramses::suspend"); + return false; +} + +/** + * This sets the display on or off + */ +bool Ramses::setDisplayStatus(bool on) +{ + qDebug("Ramses::setDisplayStatus(%d)", on); +#if 0 + bool res = false; + int fd; + + if ((fd = ::open ("/dev/fb/0", O_RDWR)) >= 0) { + res = (::ioctl(fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN) == 0); + ::close(fd); + } + return res; +#else + return true; +#endif +} + + +/* + * We get something between 0..255 into us +*/ +bool Ramses::setDisplayBrightness(int bright) +{ + qDebug("Ramses::setDisplayBrightness(%d)", bright); + bool res = false; + int fd; + + // pwm1 brighness: 20 steps 500..0 (dunkel->hell) + + if (bright > 255 ) + bright = 255; + if (bright < 0) + bright = 0; + + // Turn backlight completely off + if ((fd = ::open("/proc/sys/board/lcd_backlight", O_WRONLY)) >= 0) { + char writeCommand[10]; + const int count = sprintf(writeCommand, "%d\n", bright ? 1 : 0); + res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + } + + // scale backlight brightness to hardware + bright = 500-(bright * 500 / 255); + if ((fd = ::open("/proc/sys/board/pwm1", O_WRONLY)) >= 0) { + qDebug(" %d -> pwm1", bright); + char writeCommand[100]; + const int count = sprintf(writeCommand, "%d\n", bright); + res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + } + return res; +} + + +int Ramses::displayBrightnessResolution() const +{ + return 32; +} + +bool Ramses::setDisplayContrast(int contr) +{ + qDebug("Ramses::setDisplayContrast(%d)", contr); + bool res = false; + int fd; + + // pwm0 contrast: 20 steps 79..90 (dunkel->hell) + + if (contr > 255 ) + contr = 255; + if (contr < 0) + contr = 0; + contr = 90 - (contr * 20 / 255); + + if ((fd = ::open("/proc/sys/board/pwm0", O_WRONLY)) >= 0) { + qDebug(" %d -> pwm0", contr); + char writeCommand[100]; + const int count = sprintf(writeCommand, "%d\n", contr); + res = (::write(fd, writeCommand, count) != -1); + res = true; + ::close(fd); + } + return res; +} + + +int Ramses::displayContrastResolution() const +{ + return 20; +} + + +/************************************************** + * * + * Jornada * + * * + **************************************************/ + + +bool Jornada::isJornada ( ) +{ + QFile f( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine ( ) ) { + if ( line. left ( 8 ) == "Hardware" ) { + int loc = line. find ( ":" ); + if ( loc != -1 ) { + QString model = + line. mid ( loc + 2 ). simplifyWhiteSpace( ); + return ( model == "HP Jornada 56x" ); + } + } + } + } + return false; +} + +void Jornada::init ( ) +{ + d-> m_vendorstr = "HP"; + d-> m_vendor = Vendor_HP; + d-> m_modelstr = "Jornada 56x"; + d-> m_model = Model_Jornada_56x; + d-> m_systemstr = "Familiar"; + d-> m_system = System_Familiar; + d-> m_rotation = Rot0; + + QFile f ( "/etc/familiar-version" ); + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + + QTextStream ts ( &f ); + d-> m_sysverstr = ts. readLine ( ). mid ( 10 ); + + f. close ( ); + } +} + +#if 0 +void Jornada::initButtons ( ) +{ + if ( d-> m_buttons ) + return; + + // Simulation uses iPAQ 3660 device buttons + + qDebug ( "init Buttons" ); + d-> m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { + i_button *ib = ipaq_buttons + i; + ODeviceButton b; + + if (( ib-> model & Model_iPAQ_H36xx ) == Model_iPAQ_H36xx ) { + b. setKeycode ( ib-> code ); + b. setUserText ( QObject::tr ( "Button", ib-> utext )); + b. setPixmap ( Resource::loadPixmap ( ib-> pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib-> fpressedservice ), ib-> fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib-> fheldservice ), ib-> fheldaction )); + d-> m_buttons-> append ( b ); + } + } + reloadButtonMapping ( ); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received(const QCString&,const QByteArray&)), this, SLOT( systemMessage(const QCString&,const QByteArray&))); +} +#endif +int Jornada::displayBrightnessResolution ( ) const +{ + return 255; +} + +bool Jornada::setDisplayBrightness ( int bright ) +{ + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 0 ) + bright = 0; + + if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { + FLITE_IN bl; + bl. mode = 1; + bl. pwr = bright ? 1 : 0; + bl. brightness = ( bright * ( displayBrightnessResolution ( ) - 1 ) + 127 ) / 255; + res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); + ::close ( fd ); + } + return res; +} + +bool Jornada::setSoftSuspend ( bool soft ) +{ + bool res = false; + int fd; + + if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { + if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) + res = true; + else + ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); + + ::close ( fd ); + } + else + ::perror ( "/proc/sys/ts/suspend_button_mode" ); + + return res; +} diff --git a/noncore/unsupported/libopie/odevice.h b/noncore/unsupported/libopie/odevice.h new file mode 100644 index 0000000..fc41079 --- a/dev/null +++ b/noncore/unsupported/libopie/odevice.h @@ -0,0 +1,302 @@ +/* This file is part of the OPIE libraries + Copyright (C) 2002 Robert Griebl (sandman@handhelds.org) + Copyright (C) 2003 Holger 'zecke' Freyther (zecke@handhelds.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _LIBOPIE_ODEVICE_H_ +#define _LIBOPIE_ODEVICE_H_ + +#include <qobject.h> +#include <qstring.h> +#include <qnamespace.h> +#include <qstrlist.h> + +#include <opie/odevicebutton.h> + +#include <qpe/qpeapplication.h> /* for Transformation enum.. */ + +class ODeviceData; + +namespace Opie { + +/** + * The available devices + */ +enum OModel { + Model_Unknown, // = 0 + + Model_Series_Mask = 0xff000000, + + Model_iPAQ = ( 1 << 24 ), + + Model_iPAQ_All = ( Model_iPAQ | 0xffffff ), + Model_iPAQ_H31xx = ( Model_iPAQ | 0x000001 ), + Model_iPAQ_H36xx = ( Model_iPAQ | 0x000002 ), + Model_iPAQ_H37xx = ( Model_iPAQ | 0x000004 ), + Model_iPAQ_H38xx = ( Model_iPAQ | 0x000008 ), + Model_iPAQ_H39xx = ( Model_iPAQ | 0x000010 ), + Model_iPAQ_H5xxx = ( Model_iPAQ | 0x000011 ), + + Model_Jornada = ( 6 << 24 ), + Model_Jornada_56x = ( Model_Jornada | 0x000001 ), + + Model_Zaurus = ( 2 << 24 ), + + Model_Zaurus_SL5000 = ( Model_Zaurus | 0x000001 ), + Model_Zaurus_SL5500 = ( Model_Zaurus | 0x000002 ), + Model_Zaurus_SLA300 = ( Model_Zaurus | 0x000003 ), + Model_Zaurus_SLB600 = ( Model_Zaurus | 0x000004 ), + Model_Zaurus_SLC7x0 = ( Model_Zaurus | 0x000005 ), + + Model_SIMpad = ( 3 << 24 ), + + Model_SIMpad_All = ( Model_SIMpad | 0xffffff ), + Model_SIMpad_CL4 = ( Model_SIMpad | 0x000001 ), + Model_SIMpad_SL4 = ( Model_SIMpad | 0x000002 ), + Model_SIMpad_SLC = ( Model_SIMpad | 0x000004 ), + Model_SIMpad_TSinus = ( Model_SIMpad | 0x000008 ), + + Model_Ramses = ( 4 << 24 ), + + Model_Ramses_All = ( Model_Ramses | 0xffffff ), + Model_Ramses_MNCI = ( Model_Ramses | 0x000001 ), + + Model_Yopy = ( 5 << 24 ), + + Model_Yopy_All = ( Model_Yopy | 0xffffff ), + Model_Yopy_3000 = ( Model_Yopy | 0x000001 ), + Model_Yopy_3500 = ( Model_Yopy | 0x000002 ), + Model_Yopy_3700 = ( Model_Yopy | 0x000003 ), + +}; + +/** + * The vendor of the device + */ +enum OVendor { + Vendor_Unknown, + + Vendor_HP, + Vendor_Sharp, + Vendor_SIEMENS, + Vendor_MundN, + Vendor_GMate, +}; + +/** + * The System used + */ +enum OSystem { + System_Unknown, + + System_Familiar, + System_Zaurus, + System_OpenZaurus, + System_Linupy, +}; + +enum OLedState { + Led_Off, + Led_On, + Led_BlinkSlow, + Led_BlinkFast +}; + +enum OLed { + Led_Mail, + Led_Power, + Led_BlueTooth +}; + +enum OHardKey { + HardKey_Datebook = Qt::Key_F9, + HardKey_Contacts = Qt::Key_F10, + HardKey_Menu = Qt::Key_F11, + HardKey_Home = Qt::Key_F12, + HardKey_Mail = Qt::Key_F13, + HardKey_Record = Qt::Key_F24, + HardKey_Suspend = Qt::Key_F34, + HardKey_Backlight = Qt::Key_F35, + HardKey_Action = Qt::Key_F10, + HardKey_OK = Qt::Key_F11, + HardKey_End = Qt::Key_F12, +}; + +enum ODirection { + CW = 0, + CCW = 1, + Flip = 2, +}; + +enum OHingeStatus { + CASE_CLOSED = 3, + CASE_PORTRAIT = 2, + CASE_LANDSCAPE = 0, + CASE_UNKNOWN = 1, +}; + +/** + * A singleton which gives informations about device specefic option + * like the Hardware used, LEDs, the Base Distribution and + * hardware key mappings. + * + * @short A small class for device specefic options + * @see QObject + * @author Robert Griebl + * @version 1.0 + */ +class ODevice : public QObject { + Q_OBJECT + +private: + /* disable copy */ + ODevice ( const ODevice & ); + +protected: + ODevice ( ); + virtual void init ( ); + virtual void initButtons ( ); + + ODeviceData *d; + +public: + // sandman do we want to allow destructions? -zecke? + virtual ~ODevice ( ); + + static ODevice *inst ( ); + + // information + + QString modelString ( ) const; + OModel model ( ) const; + inline OModel series ( ) const { return (OModel) ( model ( ) & Model_Series_Mask ); } + + QString vendorString ( ) const; + OVendor vendor ( ) const; + + QString systemString ( ) const; + OSystem system ( ) const; + + QString systemVersionString ( ) const; + + /*virtual*/ Transformation rotation ( ) const; + /*virtual*/ ODirection direction ( ) const; + +// system + + virtual bool setSoftSuspend ( bool on ); + virtual bool suspend ( ); + + virtual bool setDisplayStatus ( bool on ); + virtual bool setDisplayBrightness ( int brightness ); + virtual int displayBrightnessResolution ( ) const; + virtual bool setDisplayContrast ( int contrast ); + virtual int displayContrastResolution ( ) const; + + // don't add new virtual methods, use this: + // /*virtual */ void boo(int i ) { return virtual_hook(1,&i); }; + // and in your subclass do do overwrite + // protected virtual int virtual_hook(int, void *) + // which is defined below + + // input / output + //FIXME playAlarmSound and al might be better -zecke + virtual void alarmSound ( ); + virtual void keySound ( ); + virtual void touchSound ( ); + + virtual QValueList <OLed> ledList ( ) const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState ( OLed led ) const; + virtual bool setLedState ( OLed led, OLedState st ); + + virtual bool hasLightSensor ( ) const; + virtual int readLightSensor ( ); + virtual int lightSensorResolution ( ) const; + + /*virtual*/ bool hasHingeSensor ( ) const; + /*virtual*/ OHingeStatus readHingeSensor ( ); + + const QStrList &allowedCpuFrequencies() const; + bool setCurrentCpuFrequency(uint index); + + /** + * Returns the available buttons on this device. The number and location + * of buttons will vary depending on the device. Button numbers will be assigned + * by the device manufacturer and will be from most preferred button to least preffered + * button. Note that this list only contains "user mappable" buttons. + * + * @todo ### make const + */ + const QValueList<ODeviceButton> &buttons ( ) /** /todo ### make const */; + + /** + * Returns the DeviceButton for the \a keyCode. If \a keyCode is not found, it + * returns 0L + */ + const ODeviceButton *buttonForKeycode ( ushort keyCode ); + + /** + * Reassigns the pressed action for \a button. To return to the factory + * default pass an empty string as \a qcopMessage. + */ + void remapPressedAction ( int button, const OQCopMessage &qcopMessage ); + + /** + * Reassigns the held action for \a button. To return to the factory + * default pass an empty string as \a qcopMessage. + */ + void remapHeldAction ( int button, const OQCopMessage &qcopMessage ); + + /** + * How long (in ms) you have to press a button for a "hold" action + */ + uint buttonHoldTime ( ) const; + +signals: + void buttonMappingChanged ( ); + +private slots: + void systemMessage ( const QCString &, const QByteArray & ); + +protected: + void reloadButtonMapping ( ); + /* ugly virtual hook */ + virtual void virtual_hook( int id, void* data ); + +protected: + enum { VIRTUAL_ROTATION = 0x200, VIRTUAL_DIRECTION, + VIRTUAL_HAS_HINGE, VIRTUAL_HINGE }; + struct VirtRotation { + Transformation trans; + }; + struct VirtDirection { + ODirection direct; + }; + struct VirtHasHinge { + bool hasHinge; + }; + struct VirtHingeStatus { + OHingeStatus hingeStat; + }; +}; + +} + +#endif + diff --git a/noncore/unsupported/libopie/odevicebutton.cpp b/noncore/unsupported/libopie/odevicebutton.cpp new file mode 100644 index 0000000..647ac4b --- a/dev/null +++ b/noncore/unsupported/libopie/odevicebutton.cpp @@ -0,0 +1,237 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +#include <qpe/qcopenvelope_qws.h> +#include <opie/odevicebutton.h> + +using namespace Opie; + + +class OQCopMessageData { +public: + QCString m_channel; + QCString m_message; + QByteArray m_data; +}; + + +OQCopMessage::OQCopMessage ( ) + : d ( 0 ) +{ + init ( QCString ( ), QCString ( ), QByteArray ( )); +} + +OQCopMessage::OQCopMessage ( const OQCopMessage © ) + : d ( 0 ) +{ + init ( copy. channel ( ), copy. message ( ), copy. data ( )); +} + +OQCopMessage &OQCopMessage::operator = ( const OQCopMessage &assign ) +{ + init ( assign. channel ( ), assign. message ( ), assign. data ( )); + return *this; +} + +OQCopMessage::OQCopMessage ( const QCString &ch, const QCString &m, const QByteArray &arg ) + : d ( 0 ) +{ + init ( ch, m, arg ); +} + +void OQCopMessage::init ( const QCString &ch, const QCString &m, const QByteArray &arg ) +{ + if ( !d ) + d = new OQCopMessageData ( ); + d-> m_channel = ch; + d-> m_message = m; + d-> m_data = arg; +} + +bool OQCopMessage::send ( ) +{ + if ( d-> m_channel. isEmpty ( ) || d-> m_message. isEmpty ( ) ) + return false; + + QCopEnvelope e ( d-> m_channel, d-> m_message ); + + if ( d-> m_data. size ( )) + e. writeRawBytes ( d-> m_data. data ( ), d-> m_data. size ( )); + + return true; +} + +QCString OQCopMessage::channel ( ) const +{ + return d-> m_channel; +} + +QCString OQCopMessage::message ( ) const +{ + return d-> m_message; +} + +QByteArray OQCopMessage::data ( ) const +{ + return d-> m_data; +} + +bool OQCopMessage::isNull() const +{ + return d-> m_message.isNull() || d-> m_channel.isNull(); +} +void OQCopMessage::setChannel ( const QCString &ch ) +{ + d-> m_channel = ch; +} + +void OQCopMessage::setMessage ( const QCString &m ) +{ + d-> m_message = m; +} + +void OQCopMessage::setData ( const QByteArray &data ) +{ + d-> m_data = data; +} + +/*! \class Opie::ODeviceButton + \brief The Opie::ODeviceButton class represents a physical user mappable button on a Qtopia device. + + This class represents a physical button on a Qtopia device. A + device may have "user programmable" buttons. + The location and number of buttons will vary from device to + device. userText() and pixmap() may be used to describe this button + to the user in help documentation. + + \ingroup qtopiaemb + \internal +*/ + +ODeviceButton::ODeviceButton() +{ +} + +ODeviceButton::~ODeviceButton() +{ +} + +/*! + Returns the button's keycode. + */ +ushort ODeviceButton::keycode() const +{ + return m_Keycode; +} + + +/*! + This function returns a human readable, translated description of the button. + */ +QString ODeviceButton::userText() const +{ + return m_UserText; +} + +/*! + This function returns the pixmap for this button. If there isn't one + it will return an empty (null) pixmap. + */ +QPixmap ODeviceButton::pixmap() const +{ + return m_Pixmap; +} + +/*! + This function returns the factory preset (default) action for when this button + is pressed. The return value is a legal QCop message. + */ +OQCopMessage ODeviceButton::factoryPresetPressedAction() const +{ + return m_FactoryPresetPressedAction; +} + +/*! + This function returns the user assigned action for when this button is pressed. + If no action is assigned, factoryPresetAction() is returned. + */ +OQCopMessage ODeviceButton::pressedAction() const +{ + if (m_PressedAction.channel().isEmpty()) + return factoryPresetPressedAction(); + return m_PressedAction; +} + +/*! + This function returns the factory preset (default) action for when this button + is pressed and held. The return value is a legal QCop message. + */ +OQCopMessage ODeviceButton::factoryPresetHeldAction() const +{ + return m_FactoryPresetHeldAction; +} + +/*! + This function returns the user assigned action for when this button is pressed + and held. If no action is assigned, factoryPresetAction() is returned. + */ +OQCopMessage ODeviceButton::heldAction() const +{ + if (m_HeldAction.channel().isEmpty()) + return factoryPresetHeldAction(); + return m_HeldAction; +} + +void ODeviceButton::setKeycode(ushort keycode) +{ + m_Keycode = keycode; +} + +void ODeviceButton::setUserText(const QString& text) +{ + m_UserText = text; +} + +void ODeviceButton::setPixmap(const QPixmap& picture) +{ + m_Pixmap = picture; +} + +void ODeviceButton::setFactoryPresetPressedAction(const OQCopMessage& action) +{ + m_FactoryPresetPressedAction = action; +} + + +void ODeviceButton::setPressedAction(const OQCopMessage& action) +{ + m_PressedAction = action; +} + +void ODeviceButton::setFactoryPresetHeldAction(const OQCopMessage& action) +{ + m_FactoryPresetHeldAction = action; +} + +void ODeviceButton::setHeldAction(const OQCopMessage& action) +{ + m_HeldAction = action; +} diff --git a/noncore/unsupported/libopie/odevicebutton.h b/noncore/unsupported/libopie/odevicebutton.h new file mode 100644 index 0000000..1621526 --- a/dev/null +++ b/noncore/unsupported/libopie/odevicebutton.h @@ -0,0 +1,107 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef DEVICE_BUTTON_H +#define DEVICE_BUTTON_H + +#include <qpixmap.h> +#include <qstring.h> + +class OQCopMessageData; + +namespace Opie +{ + +class OQCopMessage { +public: + OQCopMessage ( ); + OQCopMessage ( const OQCopMessage © ); + OQCopMessage ( const QCString &m_channel, const QCString &message, const QByteArray &args = QByteArray ( )); + + OQCopMessage &operator = ( const OQCopMessage &assign ); + + void setChannel ( const QCString &channel ); + void setMessage ( const QCString &message ); + void setData ( const QByteArray &ba ); + + QCString channel ( ) const; + QCString message ( ) const; + QByteArray data ( ) const; + + bool isNull()const; + + bool send ( ); + +private: + void init ( const QCString &m_channel, const QCString &message, const QByteArray &args ); + + OQCopMessageData *d; + class Private; + Private* m_data; +}; + + +/** + * This class represents a physical button on a Qtopia device. A device may + * have n "user programmable" buttons, which are number 1..n. The location + * and number of buttons will vary from device to device. userText() and pixmap() + * may be used to describe this button to the user in help documentation. + * + * @version 1.0 + * @author Trolltech + * @short A representation of buttons + */ + +class ODeviceButton +{ +public: + ODeviceButton(); + virtual ~ODeviceButton(); + + ushort keycode ( ) const; + QString userText ( ) const; + QPixmap pixmap ( ) const; + OQCopMessage factoryPresetPressedAction ( ) const; + OQCopMessage pressedAction ( ) const; + OQCopMessage factoryPresetHeldAction ( ) const; + OQCopMessage heldAction ( ) const; + + void setKeycode ( ushort keycode ); + void setUserText ( const QString& text ); + void setPixmap ( const QPixmap& picture ); + void setFactoryPresetPressedAction ( const OQCopMessage& qcopMessage ); + void setPressedAction ( const OQCopMessage& qcopMessage ); + void setFactoryPresetHeldAction ( const OQCopMessage& qcopMessage ); + void setHeldAction ( const OQCopMessage& qcopMessage ); + +private: + ushort m_Keycode; + QString m_UserText; + QPixmap m_Pixmap; + OQCopMessage m_FactoryPresetPressedAction; + OQCopMessage m_PressedAction; + OQCopMessage m_FactoryPresetHeldAction; + OQCopMessage m_HeldAction; + class Private; + Private *d; +}; + +} + +#endif diff --git a/noncore/unsupported/libopie/ofiledialog.cc b/noncore/unsupported/libopie/ofiledialog.cc new file mode 100644 index 0000000..47306b6 --- a/dev/null +++ b/noncore/unsupported/libopie/ofiledialog.cc @@ -0,0 +1,212 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002,2003 <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <qpe/config.h> +#include <qpe/qpeapplication.h> + +#include <qfileinfo.h> +#include <qlayout.h> + + +#include "ofiledialog.h" + + +namespace { + /* + * helper functions to load the start dir + * and to save it + * helper to extract the dir out of a file name + */ + /** + * This method will use Config( argv[0] ); + * @param key The group key used + */ + QString lastUsedDir( const QString& key ) { + if ( qApp->argc() < 1 ) + return QString::null; + + Config cfg( QFileInfo(qApp->argv()[0]).fileName() ); // appname + cfg.setGroup( key ); + return cfg.readEntry("LastDir", QPEApplication::documentDir() ); + } + + void saveLastDir( const QString& key, const QString& file ) { + if ( qApp->argc() < 1 ) + return; + + Config cfg( QFileInfo(qApp->argv()[0]).fileName() ); + cfg.setGroup( key ); + QFileInfo inf( file ); + cfg.writeEntry("LastDir", inf.dirPath( true ) ); + } +}; + +/** + * This constructs a modal dialog + * + * @param caption The caption of the dialog + * @param wid The parent widget + * @param mode The mode of the OFileSelector @see OFileSelector + * @param selector The selector of the OFileSelector + * @param dirName the dir or resource to start from + * @param fileName a proposed or existing filename + * @param mimetypes The mimeTypes + */ +OFileDialog::OFileDialog(const QString &caption, + QWidget *wid, int mode, int selector, + const QString &dirName, + const QString &fileName, + const QMap<QString,QStringList>& mimetypes ) + : QDialog( wid, "OFileDialog", true ) +{ + // QVBoxLayout *lay = new QVBoxLayout(this); + //showMaximized(); + QVBoxLayout *lay = new QVBoxLayout(this ); + file = new OFileSelector(this , mode, selector, + dirName, fileName, + mimetypes ); + lay->addWidget( file ); + + //lay->addWidget( file ); + //showFullScreen(); + setCaption( caption.isEmpty() ? tr("FileDialog") : caption ); + connect(file, SIGNAL(fileSelected(const QString&) ), + this, SLOT(slotFileSelected(const QString&) ) ); + connect(file, SIGNAL(ok() ), + this, SLOT(slotSelectorOk()) ) ; + + connect(file, SIGNAL(dirSelected(const QString&) ), this, SLOT(slotDirSelected(const QString&) ) ); + +#if 0 + connect(file, SIGNAL(dirSelected(const QString &) ), + this, SLOT(slotDirSelected(const QString &) ) ); +#endif +} +/** + * @returns the mimetype of the selected + * currently it return QString::null + */ +QString OFileDialog::mimetype()const +{ + return QString::null; +} + +/** + * @return the fileName + */ +QString OFileDialog::fileName()const +{ + return file->selectedName(); +} + +/** + * return a DocLnk to the current file + */ +DocLnk OFileDialog::selectedDocument()const +{ + return file->selectedDocument(); +} + +/** + * This opens up a filedialog in Open mode + * + * @param selector the Selector Mode + * @param startDir Where to start from + * @param file A proposed filename + * @param mimes A list of MimeTypes + * @param wid the parent + * @param caption of the dialog if QString::null tr("Open") will be used + * @return the fileName or QString::null + */ +QString OFileDialog::getOpenFileName(int selector, + const QString &_startDir, + const QString &file, + const MimeTypes &mimes, + QWidget *wid, + const QString &caption ) +{ + QString ret; + QString startDir = _startDir; + if (startDir.isEmpty() ) + startDir = lastUsedDir( "FileDialog-OPEN" ); + + + OFileDialog dlg( caption.isEmpty() ? tr("Open") : caption, + wid, OFileSelector::Open, selector, startDir, file, mimes); + dlg.showMaximized(); + if( dlg.exec() ) { + ret = dlg.fileName(); + saveLastDir( "FileDialog-OPEN", ret ); + } + + return ret; +} + +/** + * This opens up a file dialog in save mode + * @see getOpenFileName + */ +QString OFileDialog::getSaveFileName(int selector, + const QString &_startDir, + const QString &file, + const MimeTypes &mimes, + QWidget *wid, + const QString &caption ) +{ + QString ret; + QString startDir = _startDir; + if (startDir.isEmpty() ) + startDir = lastUsedDir( "FileDialog-SAVE" ); + + OFileDialog dlg( caption.isEmpty() ? tr("Save") : caption, + wid, OFileSelector::Save, selector, startDir, file, mimes); + dlg.showMaximized(); + if( dlg.exec() ) { + ret = dlg.fileName(); + saveLastDir( "FileDialog-SAVE", ret ); + } + + return ret; +} + +void OFileDialog::slotFileSelected(const QString & ) +{ + accept(); +} + +void OFileDialog::slotSelectorOk( ) +{ + accept(); +} + +void OFileDialog::slotDirSelected(const QString &dir ) +{ + setCaption( dir ); + // if mode + //accept(); +} diff --git a/noncore/unsupported/libopie/ofiledialog.h b/noncore/unsupported/libopie/ofiledialog.h new file mode 100644 index 0000000..3b905c0 --- a/dev/null +++ b/noncore/unsupported/libopie/ofiledialog.h @@ -0,0 +1,101 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 zecke <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#ifndef OpieFileDialog_h +#define OpieFileDialog_h + +#include <qdialog.h> + +#include <opie/ofileselector.h> + +/** + * This class places a OFileSelector inside a QDialog. + * It provides static method for letting a user chose + * a file for either opening or saving. + * Most of the time the c'tor will not be used instead using + * the static member functions is prefered. + * + * <pre> + * QMap<QString, QStringList> mimeTypes; + * QStringList types; + * types << "text@slash* "; + * mimeTypes.insert( tr("Text"), types ); + * mimeTypes.insert( tr("All"), " *@slash* " ); // remove the spaces in the 2nd comment + * QString fileName= OFileDialog::getOpenFileName( OFileSelector::EXTENDED_ALL, + * "foo","bar", mimeTypes); + * </pre> + * + * @short A small QDialog swalloing a FileSelector + * @see QDialog + * @see OFileSelector + * @version 0.1-unfinished + * @author Holger Freyther ( zecke@handhelds.org ) + */ +class OFileDialog : public QDialog { + Q_OBJECT + public: + OFileDialog(const QString &caption, + QWidget *, int mode, int selector, + const QString &dirName, + const QString &fileName = QString::null, + const MimeTypes &mimetypes = MimeTypes() ); + QString mimetype() const; + QString fileName() const; + DocLnk selectedDocument()const; + + // static methods + static QString getOpenFileName(int selector, + const QString& startDir = QString::null, + const QString &fileName = QString::null, + const MimeTypes& mime = MimeTypes(), + QWidget *wid = 0, + const QString &caption = QString::null ); + + static QString getSaveFileName(int selector, + const QString& startDir = QString::null, + const QString& fileName = QString::null, + const MimeTypes& mimefilter = MimeTypes(), + QWidget *wid = 0, + const QString &caption = QString::null ); + + //let's OFileSelector catch up first + //static QString getExistingDirectory(const QString& startDir = QString::null, + // QWidget *parent = 0, + // const QString& caption = QString::null ); + private: + class OFileDialogPrivate; + OFileDialogPrivate *d; + OFileSelector *file; + + private slots: + void slotFileSelected( const QString & ); + void slotDirSelected(const QString & ); + void slotSelectorOk(); +}; +#endif diff --git a/noncore/unsupported/libopie/ofileselector.cpp b/noncore/unsupported/libopie/ofileselector.cpp new file mode 100644 index 0000000..2a6aed0 --- a/dev/null +++ b/noncore/unsupported/libopie/ofileselector.cpp @@ -0,0 +1,929 @@ +#include <qcombobox.h> +#include <qdir.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpopupmenu.h> +#include <qwidgetstack.h> + +/* hacky but we need to get FileSelector::filter */ +#define private public +#include <qpe/fileselector.h> +#undef private + +#include <qpe/qpeapplication.h> +#include <qpe/mimetype.h> +#include <qpe/resource.h> +#include <qpe/storage.h> + +#include "ofileselector_p.h" +#include "ofileselector.h" + + + +OFileViewInterface::OFileViewInterface( OFileSelector* selector ) + : m_selector( selector ) { +} +OFileViewInterface::~OFileViewInterface() { +} +QString OFileViewInterface::name()const{ + return m_name; +} +void OFileViewInterface::setName( const QString& name ) { + m_name = name; +} +OFileSelector* OFileViewInterface::selector()const { + return m_selector; +} +DocLnk OFileViewInterface::selectedDocument()const { + return DocLnk( selectedName() ); +} +bool OFileViewInterface::showNew()const { + return selector()->showNew(); +} +bool OFileViewInterface::showClose()const { + return selector()->showClose(); +} +MimeTypes OFileViewInterface::mimeTypes()const { + return selector()->mimeTypes(); +} +QStringList OFileViewInterface::currentMimeType()const { + return selector()->currentMimeType(); +} +void OFileViewInterface::activate( const QString& ) { + // not implemented here +} +void OFileViewInterface::ok() { + emit selector()->ok(); +} +void OFileViewInterface::cancel() { + emit selector()->cancel(); +} +void OFileViewInterface::closeMe() { + emit selector()->closeMe(); +} +void OFileViewInterface::fileSelected( const QString& str) { + emit selector()->fileSelected( str); +} +void OFileViewInterface::fileSelected( const DocLnk& lnk) { + emit selector()->fileSelected( lnk ); +} +void OFileViewInterface::setCurrentFileName( const QString& str ) { + selector()->m_lneEdit->setText( str ); +} +QString OFileViewInterface::currentFileName()const{ + return selector()->m_lneEdit->text(); +} +QString OFileViewInterface::startDirectory()const{ + return selector()->m_startDir; +} + + +ODocumentFileView::ODocumentFileView( OFileSelector* selector ) + : OFileViewInterface( selector ) { + m_selector = 0; + setName( QObject::tr("Documents") ); +} +ODocumentFileView::~ODocumentFileView() { + +} +QString ODocumentFileView::selectedName()const { + if (!m_selector) + return QString::null; + + return m_selector->selectedDocument().file(); +} +QString ODocumentFileView::selectedPath()const { + return QPEApplication::documentDir(); +} +QString ODocumentFileView::directory()const { + return selectedPath(); +} +void ODocumentFileView::reread() { + if (!m_selector) + return; + + m_selector->setNewVisible( showNew() ); + m_selector->setCloseVisible( showClose() ); + m_selector->filter = currentMimeType().join(";"); + m_selector->reread(); +} +int ODocumentFileView::fileCount()const { + if (!m_selector) + return -1; + + return m_selector->fileCount(); +} +DocLnk ODocumentFileView::selectedDocument()const { + if (!m_selector) + return DocLnk(); + + return m_selector->selectedDocument(); +} +QWidget* ODocumentFileView::widget( QWidget* parent ) { + if (!m_selector ) { + m_selector = new FileSelector(currentMimeType().join(";"), parent, "fileselector", showNew(), showClose() ); + QObject::connect(m_selector, SIGNAL(fileSelected(const DocLnk&) ), + selector(), SLOT(slotDocLnkBridge(const DocLnk&) ) ); + QObject::connect(m_selector, SIGNAL(closeMe() ), + selector(), SIGNAL(closeMe() ) ); + QObject::connect(m_selector, SIGNAL(newSelected(const DocLnk&) ), + selector(), SIGNAL(newSelected(const DocLnk&) ) ); + } + + return m_selector; +} + +/* + * This is the file system view used + * we use a QListView + QListViewItems for it + */ + +OFileSelectorItem::OFileSelectorItem( QListView* view, const QPixmap& pixmap, + const QString& path, const QString& date, + const QString& size, const QString& dir, + bool isLocked, bool isDir ) + : QListViewItem( view ) +{ + setPixmap(0, pixmap ); + setText(1, path ); + setText(2, size ); + setText(3, date ); + m_isDir = isDir; + m_dir = dir; + m_locked = isLocked; +} +OFileSelectorItem::~OFileSelectorItem() { + +} +bool OFileSelectorItem::isLocked()const { + return m_locked; +} +QString OFileSelectorItem::directory()const { + return m_dir; +} +bool OFileSelectorItem::isDir()const { + return m_isDir; +} +QString OFileSelectorItem::path()const { + return text( 1 ); +} +QString OFileSelectorItem::key( int id, bool )const { + QString ke; + if( id == 0 || id == 1 ){ // name + if( m_isDir ){ + ke.append("0" ); + ke.append( text(1) ); + }else{ + ke.append("1" ); + ke.append( text(1) ); + } + return ke; + }else + return text( id ); + +} + +OFileViewFileListView::OFileViewFileListView( QWidget* parent, const QString& startDir, + OFileSelector* sel) + : QWidget( parent ), m_sel( sel ) { + m_all = false; + QVBoxLayout* lay = new QVBoxLayout( this ); + m_currentDir = startDir; + + /* + * now we add a special bar + * One Button For Up + * Home + * Doc + * And a dropdown menu with FileSystems + * FUTURE: one to change dir with lineedit + * Bookmarks + * Create Dir + */ + QHBox* box = new QHBox(this ); + box->setBackgroundMode( PaletteButton ); + box->setSpacing( 0 ); + + QToolButton *btn = new QToolButton( box ); + btn->setIconSet( Resource::loadIconSet("up") ); + connect(btn, SIGNAL(clicked() ), + this, SLOT( cdUP() ) ); + + btn = new QToolButton( box ); + btn->setIconSet( Resource::loadIconSet("home") ); + connect(btn, SIGNAL(clicked() ), + this, SLOT( cdHome() ) ); + + btn = new QToolButton( box ); + btn->setIconSet( Resource::loadIconSet("DocsIcon") ); + connect(btn, SIGNAL(clicked() ), + this, SLOT(cdDoc() ) ); + + m_btnNew = new QToolButton( box ); + m_btnNew->setIconSet( Resource::loadIconSet("new") ); + connect(m_btnNew, SIGNAL(clicked() ), + this, SLOT(slotNew() ) ); + + + m_btnClose = new QToolButton( box ); + m_btnClose->setIconSet( Resource::loadIconSet("close") ); + connect(m_btnClose, SIGNAL(clicked() ), + selector(), SIGNAL(closeMe() ) ); + + btn = new QToolButton( box ); + btn->setIconSet( Resource::loadIconSet("cardmon/pcmcia") ); + + /* let's fill device parts */ + QPopupMenu* pop = new QPopupMenu(this); + connect(pop, SIGNAL( activated(int) ), + this, SLOT(slotFSActivated(int) ) ); + + StorageInfo storage; + const QList<FileSystem> &fs = storage.fileSystems(); + QListIterator<FileSystem> it(fs); + for ( ; it.current(); ++it ) { + const QString disk = (*it)->name(); + const QString path = (*it)->path(); + m_dev.insert( disk, path ); + pop->insertItem( disk ); + } + m_fsPop = pop; + + + btn->setPopup( pop ); + + lay->addWidget( box ); + + m_view = new QListView( this ); + + m_view->installEventFilter(this); + + QPEApplication::setStylusOperation( m_view->viewport(), + QPEApplication::RightOnHold); + m_view->addColumn(" " ); + m_view->addColumn(tr("Name"), 135 ); + m_view->addColumn(tr("Size"), -1 ); + m_view->addColumn(tr("Date"), 60 ); + m_view->addColumn(tr("Mime Type"), -1 ); + + + m_view->setSorting( 1 ); + m_view->setAllColumnsShowFocus( TRUE ); + + lay->addWidget( m_view, 1000 ); + connectSlots(); +} +OFileViewFileListView::~OFileViewFileListView() { +} +void OFileViewFileListView::slotNew() { + DocLnk lnk; + emit selector()->newSelected( lnk ); +} +OFileSelectorItem* OFileViewFileListView::currentItem()const{ + QListViewItem* item = m_view->currentItem(); + if (!item ) + return 0l; + + return static_cast<OFileSelectorItem*>(item); +} +void OFileViewFileListView::reread( bool all ) { + m_view->clear(); + + if (selector()->showClose() ) + m_btnClose->show(); + else + m_btnClose->hide(); + + if (selector()->showNew() ) + m_btnNew->show(); + else + m_btnNew->hide(); + + m_mimes = selector()->currentMimeType(); + m_all = all; + + QDir dir( m_currentDir ); + if (!dir.exists() ) + return; + + dir.setSorting( QDir::Name | QDir::DirsFirst | QDir::Reversed ); + int filter; + if (m_all ) + filter = QDir::Files | QDir::Dirs | QDir::Hidden | QDir::All; + else + filter = QDir::Files | QDir::Dirs | QDir::All; + dir.setFilter( filter ); + + // now go through all files + const QFileInfoList *list = dir.entryInfoList(); + if (!list) { + cdUP(); + return; + } + QFileInfoListIterator it( *list ); + QFileInfo *fi; + while( (fi=it.current() ) ){ + if( fi->fileName() == QString::fromLatin1("..") || fi->fileName() == QString::fromLatin1(".") ){ + ++it; + continue; + } + + /* + * It is a symlink we try to resolve it now but don't let us attack by DOS + * + */ + if( fi->isSymLink() ){ + QString file = fi->dirPath( true ) + "/" + fi->readLink(); + for( int i = 0; i<=4; i++) { // 5 tries to prevent dos + QFileInfo info( file ); + if( !info.exists() ){ + addSymlink( fi, TRUE ); + break; + }else if( info.isDir() ){ + addDir( fi, TRUE ); + break; + }else if( info.isFile() ){ + addFile( fi, TRUE ); + break; + }else if( info.isSymLink() ){ + file = info.dirPath(true ) + "/" + info.readLink() ; + break; + }else if( i == 4){ // couldn't resolve symlink add it as symlink + addSymlink( fi ); + } + } // off for loop for symlink resolving + }else if( fi->isDir() ) + addDir( fi ); + else if( fi->isFile() ) + addFile( fi ); + + ++it; + } // of while loop + m_view->sort(); + +} +int OFileViewFileListView::fileCount()const{ + return m_view->childCount(); +} +QString OFileViewFileListView::currentDir()const{ + return m_currentDir; +} +OFileSelector* OFileViewFileListView::selector() { + return m_sel; +} + +bool OFileViewFileListView::eventFilter (QObject *o, QEvent *e) { + if ( e->type() == QEvent::KeyPress ) { + QKeyEvent *k = (QKeyEvent *)e; + if ( (k->key()==Key_Enter) || (k->key()==Key_Return)) { + slotClicked( Qt::LeftButton,m_view->currentItem(),QPoint(0,0),0); + return true; + } + } + return false; +} + + +void OFileViewFileListView::connectSlots() { + connect(m_view, SIGNAL(clicked(QListViewItem*) ), + this, SLOT(slotCurrentChanged(QListViewItem*) ) ); + connect(m_view, SIGNAL(mouseButtonClicked(int,QListViewItem*,const QPoint&,int) ), + this, SLOT(slotClicked(int,QListViewItem*,const QPoint&,int) ) ); +} +void OFileViewFileListView::slotCurrentChanged( QListViewItem* item) { + if (!item) + return; +#if 0 + + OFileSelectorItem *sel = static_cast<OFileSelectorItem*>(item); + + if (!sel->isDir() ) { + selector()->m_lneEdit->setText( sel->text(1) ); + // if in fileselector mode we will emit selected + if ( selector()->mode() == OFileSelector::FileSelector ) { + qWarning("slot Current Changed"); + QStringList str = QStringList::split("->", sel->text(1) ); + QString path = sel->directory() + "/" + str[0].stripWhiteSpace(); + emit selector()->fileSelected( path ); + DocLnk lnk( path ); + emit selector()->fileSelected( lnk ); + } + } +#endif +} +void OFileViewFileListView::slotClicked(int button , QListViewItem* item, const QPoint&, int ) { + if (!item || ( button != Qt::LeftButton) ) + return; + + OFileSelectorItem *sel = static_cast<OFileSelectorItem*>(item); + if (!sel->isLocked() ) { + QStringList str = QStringList::split("->", sel->text(1) ); + if (sel->isDir() ) { + m_currentDir = sel->directory() + "/" + str[0].stripWhiteSpace(); + emit selector()->dirSelected( m_currentDir ); + reread( m_all ); + }else { // file + qWarning("slot Clicked"); + selector()->m_lneEdit->setText( str[0].stripWhiteSpace() ); + QString path = sel->directory() + "/" + str[0].stripWhiteSpace(); + emit selector()->fileSelected( path ); + DocLnk lnk( path ); + emit selector()->fileSelected( lnk ); + } + } // not locked +} +void OFileViewFileListView::addFile( QFileInfo* info, bool symlink ) { + MimeType type( info->absFilePath() ); + if (!compliesMime( type.id() ) ) + return; + + QPixmap pix = type.pixmap(); + QString dir, name; bool locked; + if ( pix.isNull() ) { + QWMatrix matrix; + QPixmap pixer(Resource::loadPixmap("UnknownDocument") ); + matrix.scale( .4, .4 ); + pix = pixer.xForm( matrix ); + } + dir = info->dirPath( true ); + locked = false; + if ( symlink ) + name = info->fileName() + " -> " + info->dirPath() + "/" + info->readLink(); + else{ + name = info->fileName(); + if ( ( (selector()->mode() == OFileSelector::Open)&& !info->isReadable() ) || + ( (selector()->mode() == OFileSelector::Save)&& !info->isWritable() ) ) { + locked = true; pix = Resource::loadPixmap("locked"); + } + } + (void)new OFileSelectorItem( m_view, pix, name, + info->lastModified().toString(), QString::number( info->size() ), + dir, locked ); +} +void OFileViewFileListView::addDir( QFileInfo* info, bool symlink ) { + bool locked = false; QString name; QPixmap pix; + + if ( ( ( selector()->mode() == OFileSelector::Open ) && !info->isReadable() ) || + ( ( selector()->mode() == OFileSelector::Save ) && !info->isWritable() ) ) { + locked = true; + if ( symlink ) + pix = Resource::loadPixmap( "opie/symlink" ); + else + pix = Resource::loadPixmap( "lockedfolder" ); + }else + pix = symlink ? Resource::loadPixmap( "opie/symlink") : Resource::loadPixmap("folder"); + + name = symlink ? info->fileName() + " -> " + info->dirPath(true) + "/" + info->readLink() : + info->fileName(); + + (void)new OFileSelectorItem( m_view, pix, name, + info->lastModified().toString(), + QString::number( info->size() ), + info->dirPath( true ), locked, true ); + + +} +void OFileViewFileListView::addSymlink( QFileInfo* , bool ) { + +} +void OFileViewFileListView::cdUP() { + QDir dir( m_currentDir ); + dir.cdUp(); + + if (!dir.exists() ) + m_currentDir = "/"; + else + m_currentDir = dir.absPath(); + + emit selector()->dirSelected( m_currentDir ); + reread( m_all ); +} +void OFileViewFileListView::cdHome() { + m_currentDir = QDir::homeDirPath(); + emit selector()->dirSelected( m_currentDir ); + reread( m_all ); +} +void OFileViewFileListView::cdDoc() { + m_currentDir = QPEApplication::documentDir(); + emit selector()->dirSelected( m_currentDir ); + reread( m_all ); +} +void OFileViewFileListView::changeDir( const QString& dir ) { + m_currentDir = dir; + emit selector()->dirSelected( m_currentDir ); + reread( m_all ); +} +void OFileViewFileListView::slotFSActivated( int id ) { + changeDir ( m_dev[m_fsPop->text(id)] ); +} + +/* check if the mimetype in mime + * complies with the one which is current + */ +/* + * We've the mimetype of the file + * We need to get the stringlist of the current mimetype + * + * mime = image@slashjpeg + * QStringList = 'image@slash*' + * or QStringList = image/jpeg;image/png;application/x-ogg + * or QStringList = application/x-ogg;image@slash*; + * with all these mime filters it should get acceptes + * to do so we need to look if mime is contained inside + * the stringlist + * if it's contained return true + * if not ( I'm no RegExp expert at all ) we'll look if a '@slash*' + * is contained in the mimefilter and then we will + * look if both are equal until the '/' + */ +bool OFileViewFileListView::compliesMime( const QString& str) { + if (str.isEmpty() || m_mimes.isEmpty() || str.stripWhiteSpace().isEmpty() ) + return true; + + for (QStringList::Iterator it = m_mimes.begin(); it != m_mimes.end(); ++it ) { + QRegExp reg( (*it) ); + reg.setWildcard( true ); + if ( str.find( reg ) != -1 ) + return true; + + } + return false; +} +/* + * The listView giving access to the file system! + */ +class OFileViewFileSystem : public OFileViewInterface { +public: + OFileViewFileSystem( OFileSelector* ); + ~OFileViewFileSystem(); + + QString selectedName() const; + QString selectedPath() const; + + QString directory()const; + void reread(); + int fileCount()const; + + QWidget* widget( QWidget* parent ); + void activate( const QString& ); +private: + OFileViewFileListView* m_view; + bool m_all : 1; +}; +OFileViewFileSystem::OFileViewFileSystem( OFileSelector* sel) + : OFileViewInterface( sel ) { + m_view = 0; + m_all = false; +} +OFileViewFileSystem::~OFileViewFileSystem() { +} +QString OFileViewFileSystem::selectedName()const{ + if (!m_view ) + return QString::null; + + QString cFN=currentFileName(); + if (cFN.startsWith("/")) return cFN; + return m_view->currentDir() + "/" + cFN; +} +QString OFileViewFileSystem::selectedPath()const{ + return QString::null; +} +QString OFileViewFileSystem::directory()const{ + if (!m_view) + return QString::null; + + OFileSelectorItem* item = m_view->currentItem(); + if (!item ) + return QString::null; + + return QDir(item->directory() ).absPath(); +} +void OFileViewFileSystem::reread() { + if (!m_view) + return; + + m_view->reread( m_all ); +} +int OFileViewFileSystem::fileCount()const{ + if (!m_view ) + return -1; + return m_view->fileCount(); +} +QWidget* OFileViewFileSystem::widget( QWidget* parent ) { + if (!m_view ) { + m_view = new OFileViewFileListView( parent, startDirectory(), selector() ); + } + return m_view; +} +void OFileViewFileSystem::activate( const QString& str) { + m_all = (str != QObject::tr("Files") ); + + +} + +/* Selector */ +/** + * @short new and complete c'tor + * + * Create a OFileSelector to let the user select a file. It can + * either be used to open a file, select a save name in a dir or + * as a dropin for the FileSelector. + * + * <pre> + * QMap<QString, QStringList> mimeTypes; + * QStringList types; + * types << "text@slash* "; + * types << "audio@slash*"; + * mimeTypes.insert( tr("Audio and Text"), types ); + * mimeTypes.insert( tr("All"), "*@slash*); + * + * now you could create your fileselector + * </pre> + * + * + * @param parent the parent of this widget + * @param mode The mode from the enum Mode (Open,Save,FILESELECTOR) + * @param sel The selector to be used + * @param dirName The name of the dir to start int + * @param fileName The fileName placed in the fileselector lineedit + * @param mimetypes The MimeType map of used mimetypes + * @param showNew Show a New Button. Most likely to be used in the FileSelector view. + * @param showClose Show a Close Button. Most likely to be used in FileSelector view. + * + */ +OFileSelector::OFileSelector( QWidget* parent, int mode, int sel, + const QString& dirName, const QString& fileName, + const MimeTypes& mimetypes, + bool showNew, bool showClose) + : QWidget( parent, "OFileSelector" ) +{ + m_current = 0; + m_shNew = showNew; + m_shClose = showClose; + m_mimeType = mimetypes; + m_startDir = dirName; + + m_mode = mode; + m_selector = sel; + + initUI(); + m_lneEdit->setText( fileName ); + initMime(); + initViews(); + + QString str; + switch ( m_selector ) { + default: + case Normal: + str = QObject::tr("Documents"); + m_cmbView->setCurrentItem( 0 ); + break; + case Extended: + str = QObject::tr("Files"); + m_cmbView->setCurrentItem( 1 ); + break; + case ExtendedAll: + str = QObject::tr("All Files"); + m_cmbView->setCurrentItem( 2 ); + break; + } + slotViewChange( str ); + +} + +/** + * This a convience c'tor to just substitute the use of FileSelector + */ +OFileSelector::OFileSelector( const QString& mimeFilter, QWidget* parent, const char* name, + bool showNew, bool showClose ) + : QWidget( parent, name ) +{ + m_current = 0; + m_shNew = showNew; + m_shClose = showClose; + m_startDir = QPEApplication::documentDir(); + + if (!mimeFilter.isEmpty() ) + m_mimeType.insert(mimeFilter, QStringList::split(";", mimeFilter ) ); + + m_mode = OFileSelector::FileSelector; + m_selector = OFileSelector::Normal; + + initUI(); + initMime(); + initViews(); + m_cmbView->setCurrentItem( 0 ); + slotViewChange( QObject::tr("Documents") ); +} +/* + * INIT UI will set up the basic GUI + * Layout: Simple VBoxLayout + * On top a WidgetStack containing the Views... + * - List View + * - Document View + * Below we will have a Label + LineEdit + * Below we will have two ComoBoxes one for choosing the view one for + * choosing the mimetype + */ +void OFileSelector::initUI() { + QVBoxLayout* lay = new QVBoxLayout( this ); + + m_stack = new QWidgetStack( this ); + lay->addWidget( m_stack, 1000 ); + + m_nameBox = new QHBox( this ); + (void)new QLabel( tr("Name:"), m_nameBox ); + m_lneEdit = new QLineEdit( m_nameBox ); + m_lneEdit ->installEventFilter(this); + lay->addWidget( m_nameBox ); + + m_cmbBox = new QHBox( this ); + m_cmbView = new QComboBox( m_cmbBox ); + m_cmbMime = new QComboBox( m_cmbBox ); + lay->addWidget( m_cmbBox ); +} + +/* + * This will make sure that the return key in the name edit causes dialogs to close + */ + +bool OFileSelector::eventFilter (QObject *o, QEvent *e) { + if ( e->type() == QEvent::KeyPress ) { + QKeyEvent *k = (QKeyEvent *)e; + if ( (k->key()==Key_Enter) || (k->key()==Key_Return)) { + emit ok(); + return true; + } + } + return false; +} + +/* + * This will insert the MimeTypes into the Combo Box + * And also connect the changed signal + * + * AutoMimeTyping is disabled for now. It used to reparse a dir and then set available mimetypes + */ +void OFileSelector::initMime() { + MimeTypes::Iterator it; + for ( it = m_mimeType.begin(); it != m_mimeType.end(); ++it ) { + m_cmbMime->insertItem( it.key() ); + } + m_cmbMime->setCurrentItem( 0 ); + + connect( m_cmbMime, SIGNAL(activated(int) ), + this, SLOT(slotMimeTypeChanged() ) ); + +} +void OFileSelector::initViews() { + m_cmbView->insertItem( QObject::tr("Documents") ); + m_cmbView->insertItem( QObject::tr("Files") ); + m_cmbView->insertItem( QObject::tr("All Files") ); + connect(m_cmbView, SIGNAL(activated(const QString&) ), + this, SLOT(slotViewChange(const QString&) ) ); + + + m_views.insert( QObject::tr("Documents"), new ODocumentFileView(this) ); + + /* see above why add both */ + OFileViewInterface* in = new OFileViewFileSystem( this ); + m_views.insert( QObject::tr("Files"), in ); + m_views.insert( QObject::tr("All Files"), in ); +} + +/** + * d'tor + */ +OFileSelector::~OFileSelector() { + +} + +/** + * Convience function for the fileselector + * make sure to delete the DocLnk + * + * @see DocLnk + * @todo remove in ODP + */ +const DocLnk* OFileSelector::selected() { + DocLnk* lnk = new DocLnk( currentView()->selectedDocument() ); + return lnk; +} + +/** + * + * @return the name of the selected file + */ +QString OFileSelector::selectedName()const{ + return currentView()->selectedName(); +} + +/** + * @return the selected path + */ +QString OFileSelector::selectedPath()const { + return currentView()->selectedPath(); +} + +/** + * @return the directory name + */ +QString OFileSelector::directory()const { + return currentView()->directory(); +} + +/** + * @return a DocLnk for the selected document + */ +DocLnk OFileSelector::selectedDocument()const { + return currentView()->selectedDocument(); +} + +/** + * @return the number of items for the current view + */ +int OFileSelector::fileCount()const { + return currentView()->fileCount(); +} + +/** + * @return reparse the file content + */ +void OFileSelector::reread() { + return currentView()->reread(); +} +OFileViewInterface* OFileSelector::currentView()const{ + return m_current; +} +bool OFileSelector::showNew()const { + return m_shNew; +} +bool OFileSelector::showClose()const { + return m_shClose; +} +MimeTypes OFileSelector::mimeTypes()const { + return m_mimeType; +} + +/** + * @return the Mode of the OFileSelector + */ +int OFileSelector::mode()const{ + return m_mode; +} + +/** + * @return the Selector of the OFileSelector + */ +int OFileSelector::selector()const{ + return m_selector; +} +QStringList OFileSelector::currentMimeType()const { + return m_mimeType[m_cmbMime->currentText()]; +} +void OFileSelector::slotMimeTypeChanged() { + reread(); +} +void OFileSelector::slotDocLnkBridge( const DocLnk& lnk) { + m_lneEdit->setText( lnk.name() ); + emit fileSelected( lnk ); + emit fileSelected( lnk.name() ); +} +void OFileSelector::slotFileBridge( const QString& str) { + DocLnk lnk( str ); + emit fileSelected( lnk ); +} +void OFileSelector::slotViewChange( const QString& view ) { + OFileViewInterface* interface = m_views[view]; + if (!interface) + return; + + interface->activate( view ); + if (m_current) + m_stack->removeWidget( m_current->widget( m_stack ) ); + + static int id = 1; + + m_stack->addWidget( interface->widget(m_stack), id ); + m_stack->raiseWidget( id ); + + interface->reread(); + m_current = interface; + + id++; +} +void OFileSelector::setNewVisible( bool b ) { + m_shNew = b; + currentView()->reread(); +} +void OFileSelector::setCloseVisible( bool b ) { + m_shClose = b; + currentView()->reread(); +} +void OFileSelector::setNameVisible( bool b ) { + if ( b ) + m_nameBox->show(); + else + m_nameBox->hide(); +} diff --git a/noncore/unsupported/libopie/ofileselector.h b/noncore/unsupported/libopie/ofileselector.h new file mode 100644 index 0000000..767455c --- a/dev/null +++ b/noncore/unsupported/libopie/ofileselector.h @@ -0,0 +1,210 @@ +/* + This is based on code and ideas of + L. J. Potter ljp@llornkcor.com + Thanks a lot + + + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002,2003 Holger Freyther <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#ifndef OPIE_OFILESELECTOR_FOO_H +#define OPIE_OFILESELECTOR_FOO_H + +#include <qlist.h> +#include <qwidget.h> +#include <qmap.h> +#include <qvaluelist.h> +#include <qstringlist.h> + +#include <qpe/applnk.h> + +typedef QMap<QString, QStringList> MimeTypes; + +class OFileViewInterface; +class OFileViewFileListView; +class QLineEdit; +class QComboBox; +class QWidgetStack; +class QHBox; + + +/** + * @short a dropin replacement for the FileSelector + * + * This class is first used insert the OFileDialog. + * It supports multiple view and mimetype filtering for now. + * + * @see OFileDialog + * @see FileSelector + * @author zecke + * @version 0.1 + */ +class OFileSelector : public QWidget { + Q_OBJECT + friend class OFileViewInterface; + friend class OFileViewFileListView; +public: + /** + * The Mode of the Fileselector + * Open = Open A File + * Save = Save a File + * FILESELECTOR = As A GUI in a screen to select a file + */ + enum Mode { Open=1, Save=2, FileSelector=4, OPEN=1, SAVE=2, FILESELECTOR=4 }; +// enum OldMode { OPEN=1, SAVE=2, FILESELECTOR = 4 }; + /** + * Normal = The old FileSelector + * Extended = Dir View + * ExtendedAll = Dir View with all hidden files + * Default = What the vendor considers best + */ + enum Selector { Normal = 0, Extended=1, ExtendedAll =2, Default=3, NORMAL=0,EXTENDED=1, EXTENDED_ALL =2, DEFAULT=3 }; +// enum OldSelector { NORMAL = 0, EXTENDED =1, EXTENDED_ALL = 2}; + + + OFileSelector(QWidget* parent, int mode, int selector, + const QString& dirName, + const QString& fileName, + const MimeTypes& mimetypes = MimeTypes(), + bool newVisible = FALSE, bool closeVisible = FALSE ); + + OFileSelector(const QString& mimeFilter, QWidget* parent, + const char* name = 0, bool newVisible = TRUE, bool closeVisible = FALSE ); + ~OFileSelector(); + + const DocLnk* selected(); + + QString selectedName()const; + QString selectedPath()const; + QString directory()const; + + DocLnk selectedDocument()const; + + int fileCount()const; + void reread(); + + int mode()const; + int selector()const; + + /** + * Set the Icon visible + * @param b Show or Hide the New Button + */ + void setNewVisible( bool b ); + + /** + * Set the Icon visible + */ + void setCloseVisible( bool b ); + + /** + * Set the Name Line visible + */ + void setNameVisible( bool b ); + +signals: + /** + * dirSelected is emitted whenever changed into a different dir + */ + void dirSelected( const QString& ); + + /** + * fileSelected is emitted when a file is selected + * it uses a DocLnk as parameter + */ + void fileSelected( const DocLnk& ); + + /** + * fileSelected is emitted when a file is selected + * the complete path is a parameter + */ + void fileSelected( const QString& ); + + /** + * Create a new File with a DocLnk + */ + void newSelected( const DocLnk& ); + + void closeMe(); + + /** + * Ok is emitted on a Qt::Key_Return or Q::Key_Enter + * in the line edit + */ + void ok(); + void cancel(); + +/* used by the ViewInterface */ +private: + bool showNew()const; + bool showClose()const; + MimeTypes mimeTypes()const; + QStringList currentMimeType()const; + +private: + /* inits the Widgets */ + void initUI(); + /* inits the MimeType ComboBox content + connects signals and slots */ + void initMime(); + /* init the Views :) */ + void initViews(); + +private: + QLineEdit* m_lneEdit; // the LineEdit for the Name + QComboBox *m_cmbView, *m_cmbMime; // two ComboBoxes to select the View and MimeType + QWidgetStack* m_stack; // our widget stack which will contain the views + OFileViewInterface* currentView()const; // returns the currentView + OFileViewInterface* m_current; // here is the view saved + bool m_shNew : 1; // should we show New? + bool m_shClose : 1; // should we show Close? + MimeTypes m_mimeType; // list of mimetypes + + QMap<QString, OFileViewInterface*> m_views; // QString translated view name + ViewInterface Ptr + QHBox* m_nameBox; // the LineEdit + Label is hold here + QHBox* m_cmbBox; // this holds the two combo boxes + + QString m_startDir; + int m_mode; + int m_selector; + + struct Data; // used for future versions + Data *d; + +private slots: + void slotMimeTypeChanged(); + + /* will set the text of the lineedit and emit a fileChanged signal */ + void slotDocLnkBridge( const DocLnk& ); + void slotFileBridge( const QString& ); + void slotViewChange( const QString& ); + + bool eventFilter (QObject *o, QEvent *e); + +}; + +#endif diff --git a/noncore/unsupported/libopie/ofileselector_p.h b/noncore/unsupported/libopie/ofileselector_p.h new file mode 100644 index 0000000..7fd0c50 --- a/dev/null +++ b/noncore/unsupported/libopie/ofileselector_p.h @@ -0,0 +1,151 @@ +#ifndef OPIE_OFILE_SELECTOR_PRIVATE_H +#define OPIE_OFILE_SELECTOR_PRIVATE_H + +#include <qmap.h> +#include <qstringlist.h> +#include <qwidget.h> +#include <qlistview.h> + +#include <qpe/applnk.h> +#include <qpe/fileselector.h> + + +/* + * How to avoid having really two different objects + * for Extended and ExtendedAll + * The only difference is the Lister... + * a) static object? + * b) leave some object inside the OFileSelector which can be used? + * c) when switching views tell which view we want o have.. internally we can switch then + * + * I'll take c) -zecke + */ + + +/* the View Interface */ +class OFileSelector; +typedef QMap<QString, QStringList> MimeTypes; +class QFileInfo; +class QToolButton; +class OFileViewInterface { +public: + OFileViewInterface( OFileSelector* selector ); + virtual ~OFileViewInterface(); + virtual QString selectedName()const = 0; + virtual QString selectedPath()const = 0; + virtual QString directory()const = 0; + virtual void reread() = 0; + virtual int fileCount()const = 0; + virtual DocLnk selectedDocument()const; + virtual QWidget* widget( QWidget* parent) = 0; + virtual void activate( const QString& ); + QString name()const; +protected: + OFileSelector* selector()const; + void setName( const QString& ); + bool showNew()const; + bool showClose()const; + MimeTypes mimeTypes()const; + QStringList currentMimeType()const; + QString startDirectory()const; +protected: + void ok(); + void cancel(); + void closeMe(); + void fileSelected( const QString& ); + void fileSelected( const DocLnk& ); + void setCurrentFileName( const QString& ); + QString currentFileName()const; + +private: + QString m_name; + OFileSelector* m_selector; +}; + + +/* THE Document View hosting a FileSelector*/ +class ODocumentFileView : public OFileViewInterface { +public: + ODocumentFileView( OFileSelector* selector ); + ~ODocumentFileView(); + + QString selectedName() const; + QString selectedPath() const; + + QString directory() const; + void reread(); + int fileCount()const; + DocLnk selectedDocument()const; + + QWidget* widget( QWidget* parent ); + +private: + mutable FileSelector* m_selector; + +}; + +class OFileSelectorItem : public QListViewItem { +public: + OFileSelectorItem( QListView* view, const QPixmap& pixmap, + const QString& path, const QString& date, + const QString& size, const QString& mDir, + bool isLocked = false, bool isDir = false ); + ~OFileSelectorItem(); + bool isLocked()const; + bool isDir()const; + QString directory()const; + QString path()const; + QString key(int id, bool )const; + +private: + bool m_locked : 1; + bool m_isDir : 1; + QString m_dir; +}; + +class OFileViewFileListView : public QWidget { + Q_OBJECT +public: + OFileViewFileListView( QWidget* parent, const QString& dir, OFileSelector* selector ); + ~OFileViewFileListView(); + + OFileSelectorItem* currentItem()const; + void reread( bool all = false ); + int fileCount()const; + QString currentDir()const; +protected: + bool eventFilter (QObject *o, QEvent *e); +private slots: + void slotNew(); // will emit newSelected + void cdUP(); + void cdHome(); + void cdDoc(); + void changeDir( const QString& ); + void slotCurrentChanged( QListViewItem* ); + void slotClicked(int, QListViewItem*, const QPoint&, int ); + void slotFSActivated(int); + +protected: + + OFileSelector* selector(); + +private: + QMap<QString, QString> m_dev; + bool m_all : 1; + OFileSelector* m_sel; + QPopupMenu* m_fsPop; + bool compliesMime( const QString& ); + QStringList m_mimes; // used in compy mime + QString m_currentDir; + QToolButton *m_btnNew, *m_btnClose; + void connectSlots(); + void addFile( QFileInfo* info, bool symlink = FALSE ); + void addDir ( QFileInfo* info, bool symlink = FALSE ); + void addSymlink( QFileInfo* info, bool = FALSE ); + + +private: + QListView* m_view; +}; + +#endif diff --git a/noncore/unsupported/libopie/ofileview.h b/noncore/unsupported/libopie/ofileview.h new file mode 100644 index 0000000..e072477 --- a/dev/null +++ b/noncore/unsupported/libopie/ofileview.h @@ -0,0 +1,87 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 zecke <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef ofileview_h +#define ofileview_h + +#include <qobject.h> +#include <qwidget.h> + +class QFileInfo; +class QDir; +class DocLnk; + +/** + * A OFileView is a specialised View for the + * OFileSelector + * With a View you can chage the user visible + * representation of a OFileLister + * OFileView is just a basic interface which helps you to + * write new views + */ +class OFileView { + Q_OBJECT + public: + OFileView(QWidget *widget, + const char *name ); + virtual OFileView(); + virtual ~OFileSelectorView() = 0; + + virtual void addFile(const QString &mine, + QFileInfo *info, + bool isSymlink = FALSE ) = 0; + + virtual void addDir (const QString &mine, + QFileInfo *info, + bool isSymlink = FALSE ) = 0; + + virtual void addSymlink(const QString &mime, + QFileInfo *info, + bool isSymlink = FALSE ) = 0; + + virtual void cd(const QString &path ) = 0; + signals: + void fileSelected(const QString &); + void fileSelected(const DocLnk & ); + void contextMenu(); + void changedDir(const QString &); + void changedDir(const QDir & ); +}; + +class OFileViewFactory { + // Q_OBJECT + public: + OFileViewFactory() {} ; + virtual ~OFileViewFactory() = 0; + + OFileSelectorView* newView(QWidget *parent, const char *name ); + QString name()const; +}; + + +#endif diff --git a/noncore/unsupported/libopie/ofontmenu.cc b/noncore/unsupported/libopie/ofontmenu.cc new file mode 100644 index 0000000..d16c5e5 --- a/dev/null +++ b/noncore/unsupported/libopie/ofontmenu.cc @@ -0,0 +1,156 @@ + + +#include <qpe/config.h> +#include "ofontmenu.h" + + +/** + * Constructs the FontMenu. + * + * @param parent The parent widget + * @param name A name for this widget + * @param list The list of widgets to be controlled + */ +OFontMenu::OFontMenu(QWidget *parent, const char *name, const QList<QWidget> &list ) + : QPopupMenu( parent, name ) +{ + m_list = list; + m_wids.setAutoDelete( TRUE ); + + insertItem(tr("Large"), this, SLOT(slotLarge() ), + 0, 10); + insertItem(tr("Medium"), this, SLOT(slotMedium() ), + 0, 11 ); + insertItem(tr("Small"), this, SLOT(slotSmall() ), + 0, 12 ); + setCheckable( true ); + m_size=10; +} + +/** + * This method saves the font size + * into a Config object + * OFontMenu will be used as group and size as key + * @param cfg The Config object to be used + */ +void OFontMenu::save(Config *cfg ) +{ + cfg->setGroup("OFontMenu" ); + cfg->writeEntry("size", m_size ); +} + +/** + * This method restores the font size from a Config object + * it'll apply the sizes to the widgets and will also set the + * menu appropriate + */ +void OFontMenu::restore(Config *cfg ) +{ + cfg->setGroup("OFontMeny" ); + m_size = cfg->readNumEntry("size" ); + setItemChecked(10, false ); + setItemChecked(11, false ); + setItemChecked(12, false ); + switch( m_size ){ + case 8: + setItemChecked(12, true ); + break; + case 14: + setItemChecked(10, true ); + break; + case 10:// fall through + default: + setItemChecked(11, true ); + m_size = 10; + break; + } + setFontSize( m_size ); +} + +/** + * set the list of widgets + * @param list the widget list + */ +void OFontMenu::setWidgets(const QList<QWidget> &list ) +{ + m_list = list; +} + +/** + * add a widget to the list + * @param wid The widget to be added + */ +void OFontMenu::addWidget( QWidget *wid ) +{ + m_list.append(wid ); +} + +/** + * removes the widget from the list of controlled objects + * @param wid the to be removed widget + */ +void OFontMenu::removeWidget( QWidget *wid ) +{ + m_list.remove( wid ); +} + +/** + * The list of controlled widgets + */ +const QList<QWidget> &OFontMenu::widgets()const +{ + return m_list; +} + +/** + * Forces a size on a widget + * @param wid The widget + * @param size The font size forced onto the widget + */ +void OFontMenu::forceSize(QWidget *wid, int size ) +{ + WidSize *widz = new WidSize; + widz->wid = wid; + widz->size = size; + m_wids.append( widz ); +} +void OFontMenu::slotSmall() +{ + setItemChecked(10, false ); + setItemChecked(11, false ); + setItemChecked(12, true ); + setFontSize( 8 ); +} +void OFontMenu::slotMedium() +{ + setItemChecked(10, false ); + setItemChecked(11, true ); + setItemChecked(12, false ); + setFontSize(10 ); +} +void OFontMenu::slotLarge() +{ + setItemChecked(10, true ); + setItemChecked(11, false ); + setItemChecked(12, false ); + setFontSize(14 ); +} +void OFontMenu::setFontSize(int size ) +{ + m_size = size; + QWidget *wid; + for(wid = m_list.first(); wid !=0; wid = m_list.next() ){ + QFont font = wid->font(); + font.setPointSize( size ); + wid->setFont( font ); + } + if(!m_wids.isEmpty() ){ + WidSize *wids; + for( wids = m_wids.first(); wids != 0; wids = m_wids.next() ){ + QFont font = wids->wid->font(); + font.setPointSize( wids->size ); + wids->wid->setFont( font ); + } + } + emit fontChanged(size ); +} diff --git a/noncore/unsupported/libopie/ofontmenu.h b/noncore/unsupported/libopie/ofontmenu.h new file mode 100644 index 0000000..6e143ca --- a/dev/null +++ b/noncore/unsupported/libopie/ofontmenu.h @@ -0,0 +1,113 @@ + +/* + + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 zecke <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + + + +#ifndef ofontmenu_h +#define ofontmenu_h + +#include <qpopupmenu.h> +#include <qlist.h> + +/* + * @internal + */ +namespace { + struct WidSize { + QWidget *wid; + int size; + }; + +}; + +// forward declarations +class Config; + +/** + * This class is a specialised QPopupMenu. It'll display three different + * font sizes. Small, Normal and large by adding widgets to the Menu + * you can control the font size of these widgets + * by using the save and restore method you can also apply font sizes + * over two different runtimes + * + * <pre> + * QTable* tbl = new QTable(); + * QList<QWidget> wid; + * wid.append( tbl ); + * OFontMenu* menu = new OFontMenu(this, "Popup Menu", wid ); + * Config cfg("mycfg"); + * menu->restore( cfg ); + * </pre> + * + * @author Holger Freyther ( zecke@handhelds.org ) + * @version 0.1 + * @short PopupMenu which can control the size of Widgets + * @see QPopupMenu + */ +class OFontMenu : public QPopupMenu { + Q_OBJECT + public: + OFontMenu(QWidget *parent, const char* name, const QList<QWidget> &list ); + void save(Config *cfg ); + void restore(Config *cfg ); + void setWidgets(const QList<QWidget> &list ); + void addWidget(QWidget *wid ); + void forceSize(QWidget *wid, int size ); + void removeWidget(QWidget *wid ); + const QList<QWidget> &widgets()const; + + signals: + /** + * this signal gets emitted when the font size gets changed + * @param size The new size of font + */ + void fontChanged(int size ); + + private: + QList<QWidget> m_list; + QList<WidSize> m_wids; + int m_size; + class OFontMenuPrivate; + OFontMenuPrivate *d; + + private slots: + virtual void slotSmall(); + virtual void slotMedium(); + virtual void slotLarge(); + void setFontSize(int size ); +}; + +#endif + + + + + diff --git a/noncore/unsupported/libopie/ofontselector.cpp b/noncore/unsupported/libopie/ofontselector.cpp new file mode 100644 index 0000000..87b7869 --- a/dev/null +++ b/noncore/unsupported/libopie/ofontselector.cpp @@ -0,0 +1,411 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Robert Griebl <sandman@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <qlayout.h> +#include <qlistbox.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qmultilineedit.h> + +#include <qpe/fontdatabase.h> + +#include "ofontselector.h" + +class OFontSelectorPrivate { +public: + QListBox * m_font_family_list; + QComboBox * m_font_style_list; + QComboBox * m_font_size_list; + QMultiLineEdit *m_preview; + + bool m_pointbug : 1; + + FontDatabase m_fdb; +}; + +namespace { + +class FontListItem : public QListBoxText { +public: + FontListItem ( const QString &t, const QStringList &styles, const QValueList<int> &sizes ) : QListBoxText ( ) + { + m_name = t; + m_styles = styles; + m_sizes = sizes; + + QString str = t; + str [0] = str [0]. upper ( ); + setText ( str ); + } + + QString family ( ) const + { + return m_name; + } + + const QStringList &styles ( ) const + { + return m_styles; + } + + const QValueList<int> &sizes ( ) const + { + return m_sizes; + } + +private: + QStringList m_styles; + QValueList<int> m_sizes; + QString m_name; +}; + + +static int findItemCB ( QComboBox *box, const QString &str ) +{ + for ( int i = 0; i < box-> count ( ); i++ ) { + if ( box-> text ( i ) == str ) + return i; + } + return -1; +} + +} +/* static same as anon. namespace */ +static int qt_version ( ) +{ + const char *qver = qVersion ( ); + + return ( qver [0] - '0' ) * 100 + ( qver [2] - '0' ) * 10 + ( qver [4] - '0' ); +} + +/** + * Constructs the Selector object + * @param withpreview If a font preview should be given + * @param parent The parent of the Font Selector + * @param name The name of the object + * @param fl WidgetFlags + */ +OFontSelector::OFontSelector ( bool withpreview, QWidget *parent, const char *name, WFlags fl ) : QWidget ( parent, name, fl ) +{ + d = new OFontSelectorPrivate ( ); + + QGridLayout *gridLayout = new QGridLayout ( this, 0, 0, 4, 4 ); + gridLayout->setRowStretch ( 4, 10 ); + + d-> m_font_family_list = new QListBox( this, "FontListBox" ); + gridLayout->addMultiCellWidget( d-> m_font_family_list, 0, 4, 0, 0 ); + connect( d-> m_font_family_list, SIGNAL( highlighted(int) ), this, SLOT( fontFamilyClicked(int) ) ); + + QLabel *label = new QLabel( tr( "Style" ), this ); + gridLayout->addWidget( label, 0, 1 ); + + d-> m_font_style_list = new QComboBox( this, "StyleListBox" ); + connect( d-> m_font_style_list, SIGNAL( activated(int) ), this, SLOT( fontStyleClicked(int) ) ); + gridLayout->addWidget( d-> m_font_style_list, 1, 1 ); + + label = new QLabel( tr( "Size" ), this ); + gridLayout->addWidget( label, 2, 1 ); + + d-> m_font_size_list = new QComboBox( this, "SizeListBox" ); + connect( d-> m_font_size_list, SIGNAL( activated(int) ), + this, SLOT( fontSizeClicked(int) ) ); + gridLayout->addWidget( d-> m_font_size_list, 3, 1 ); + + d-> m_pointbug = ( qt_version ( ) <= 233 ); + + if ( withpreview ) { + d-> m_preview = new QMultiLineEdit ( this, "Preview" ); + d-> m_preview-> setAlignment ( AlignCenter ); + d-> m_preview-> setWordWrap ( QMultiLineEdit::WidgetWidth ); + d-> m_preview-> setMargin ( 3 ); + d-> m_preview-> setText ( tr( "The Quick Brown Fox Jumps Over The Lazy Dog" )); + gridLayout-> addRowSpacing ( 5, 4 ); + gridLayout-> addMultiCellWidget ( d-> m_preview, 6, 6, 0, 1 ); + gridLayout-> setRowStretch ( 6, 5 ); + } + else + d-> m_preview = 0; + + loadFonts ( d-> m_font_family_list ); +} + +OFontSelector::~OFontSelector ( ) +{ + delete d; +} + +/** + * This methods tries to set the font + * @param f The wishes font + * @return success or failure + */ +bool OFontSelector::setSelectedFont ( const QFont &f ) +{ + return setSelectedFont ( f. family ( ), d-> m_fdb. styleString ( f ), f. pointSize ( ), QFont::encodingName ( f. charSet ( ))); +} + + +/** + * This is an overloaded method @see setSelectedFont + * @param familyStr The family of the font + * @param styleStr The style of the font + * @param sizeVal The size of font + * @param charset The charset to be used. Will be deprecated by QT3 + */ +bool OFontSelector::setSelectedFont ( const QString &familyStr, const QString &styleStr, int sizeVal, const QString & charset ) +{ + QString sizeStr = QString::number ( sizeVal ); + + QListBoxItem *family = d-> m_font_family_list-> findItem ( familyStr ); + if ( !family ) + family = d-> m_font_family_list-> findItem ( "Helvetica" ); + if ( !family ) + family = d-> m_font_family_list-> firstItem ( ); + d-> m_font_family_list-> setCurrentItem ( family ); + fontFamilyClicked ( d-> m_font_family_list-> index ( family )); + + int style = findItemCB ( d-> m_font_style_list, styleStr ); + if ( style < 0 ) + style = findItemCB ( d-> m_font_style_list, "Regular" ); + if ( style < 0 && d-> m_font_style_list-> count ( ) > 0 ) + style = 0; + d-> m_font_style_list-> setCurrentItem ( style ); + fontStyleClicked ( style ); + + int size = findItemCB ( d-> m_font_size_list, sizeStr ); + if ( size < 0 ) + size = findItemCB ( d-> m_font_size_list, "10" ); + if ( size < 0 && d-> m_font_size_list-> count ( ) > 0 ) + size = 0; + d-> m_font_size_list-> setCurrentItem ( size ); + fontSizeClicked ( size ); + + return (( family ) && ( style >= 0 ) && ( size >= 0 )); +} + +/** + * This method returns the name, style and size of the currently selected + * font or false if no font is selected + * @param family The font family will be written there + * @param style The style will be written there + * @param size The size will be written there + * @return success or failure + */ +bool OFontSelector::selectedFont ( QString &family, QString &style, int &size ) +{ + QString dummy; + return selectedFont ( family, style, size, dummy ); +} + + +/** + * This method does return the font family or QString::null if there is + * no font item selected + * @return the font family + */ +QString OFontSelector::fontFamily ( ) const +{ + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( d-> m_font_family_list-> currentItem ( )); + + return fli ? fli-> family ( ) : QString::null; +} + +/** + * This method will return the style of the font or QString::null + * @return the style of the font + */ +QString OFontSelector::fontStyle ( ) const +{ + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( d-> m_font_family_list-> currentItem ( )); + int fst = d-> m_font_style_list-> currentItem ( ); + + return ( fli && fst >= 0 ) ? fli-> styles ( ) [fst] : QString::null; +} + +/** + * This method will return the font size or 10 if no font size is available + */ +int OFontSelector::fontSize ( ) const +{ + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( d-> m_font_family_list-> currentItem ( )); + int fsi = d-> m_font_size_list-> currentItem ( ); + + return ( fli && fsi >= 0 ) ? fli-> sizes ( ) [fsi] : 10; +} + +/** + * returns the charset of the font or QString::null + */ +QString OFontSelector::fontCharSet ( ) const +{ + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( d-> m_font_family_list-> currentItem ( )); + + return fli ? d-> m_fdb. charSets ( fli-> family ( )) [0] : QString::null; +} + +/** + * Overloaded member function see above + * @see selectedFont + */ +bool OFontSelector::selectedFont ( QString &family, QString &style, int &size, QString &charset ) +{ + int ffa = d-> m_font_family_list-> currentItem ( ); + int fst = d-> m_font_style_list-> currentItem ( ); + int fsi = d-> m_font_size_list-> currentItem ( ); + + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( ffa ); + + if ( fli ) { + family = fli-> family ( ); + style = fst >= 0 ? fli-> styles ( ) [fst] : QString::null; + size = fsi >= 0 ? fli-> sizes ( ) [fsi] : 10; + charset = d-> m_fdb. charSets ( fli-> family ( )) [0]; + + return true; + } + else + return false; +} + + + + +void OFontSelector::loadFonts ( QListBox *list ) +{ + QStringList f = d-> m_fdb. families ( ); + + for ( QStringList::ConstIterator it = f. begin ( ); it != f. end ( ); ++it ) { + QValueList <int> ps = d-> m_fdb. pointSizes ( *it ); + + if ( d-> m_pointbug ) { + for ( QValueList <int>::Iterator it = ps. begin ( ); it != ps. end ( ); it++ ) + *it /= 10; + } + + list-> insertItem ( new FontListItem ( *it, d-> m_fdb. styles ( *it ), ps )); + } +} + +void OFontSelector::fontFamilyClicked ( int index ) +{ + QString oldstyle = d-> m_font_style_list-> currentText ( ); + QString oldsize = d-> m_font_size_list-> currentText ( ); + + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( index ); + + d-> m_font_style_list-> clear ( ); + d-> m_font_style_list-> insertStringList ( fli-> styles ( )); + d-> m_font_style_list-> setEnabled ( !fli-> styles ( ). isEmpty ( )); + + int i; + + i = findItemCB ( d-> m_font_style_list, oldstyle ); + if ( i < 0 ) + i = findItemCB ( d-> m_font_style_list, "Regular" ); + if (( i < 0 ) && ( d-> m_font_style_list-> count ( ) > 0 )) + i = 0; + + if ( i >= 0 ) { + d-> m_font_style_list-> setCurrentItem ( i ); + fontStyleClicked ( i ); + } + + d-> m_font_size_list-> clear ( ); + QValueList<int> sl = fli-> sizes ( ); + + for ( QValueList<int>::Iterator it = sl. begin ( ); it != sl. end ( ); ++it ) + d-> m_font_size_list-> insertItem ( QString::number ( *it )); + + i = findItemCB ( d-> m_font_size_list, oldsize ); + if ( i < 0 ) + i = findItemCB ( d-> m_font_size_list, "10" ); + if (( i < 0 ) && ( d-> m_font_size_list-> count ( ) > 0 )) + i = 0; + + if ( i >= 0 ) { + d-> m_font_size_list-> setCurrentItem ( i ); + fontSizeClicked ( i ); + } + changeFont ( ); +} + +void OFontSelector::fontStyleClicked ( int /*index*/ ) +{ + changeFont ( ); +} + +void OFontSelector::fontSizeClicked ( int /*index*/ ) +{ + changeFont ( ); +} + +void OFontSelector::changeFont ( ) +{ + QFont f = selectedFont ( ); + + if ( d-> m_preview ) + d-> m_preview-> setFont ( f ); + + emit fontSelected ( f ); +} + +/** + * Return the selected font + */ +QFont OFontSelector::selectedFont ( ) +{ + int ffa = d-> m_font_family_list-> currentItem ( ); + int fst = d-> m_font_style_list-> currentItem ( ); + int fsi = d-> m_font_size_list-> currentItem ( ); + + FontListItem *fli = (FontListItem *) d-> m_font_family_list-> item ( ffa ); + + if ( fli ) { + return d-> m_fdb. font ( fli-> family ( ), \ + fst >= 0 ? fli-> styles ( ) [fst] : QString::null, \ + fsi >= 0 ? fli-> sizes ( ) [fsi] : 10, \ + d-> m_fdb. charSets ( fli-> family ( )) [0] ); + } + else + return QFont ( ); +} + + +void OFontSelector::resizeEvent ( QResizeEvent *re ) +{ + if ( d-> m_preview ) { + d-> m_preview-> setMinimumHeight ( 1 ); + d-> m_preview-> setMaximumHeight ( 32767 ); + } + + QWidget::resizeEvent ( re ); + + if ( d-> m_preview ) + d-> m_preview-> setFixedHeight ( d-> m_preview-> height ( )); + +} diff --git a/noncore/unsupported/libopie/ofontselector.h b/noncore/unsupported/libopie/ofontselector.h new file mode 100644 index 0000000..b819c45 --- a/dev/null +++ b/noncore/unsupported/libopie/ofontselector.h @@ -0,0 +1,96 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Robert Griebl <sandman@handhelds.org> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This library is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OPIE_FONTSELECTOR_H__ +#define OPIE_FONTSELECTOR_H__ + +#include <qwidget.h> + +class QListBox; +class OFontSelectorPrivate; + +/** + * This class lets you chose a Font out of a list of Fonts. + * It can show a preview too. This selector will use all available + * fonts + * + * + * @short A widget to select a font + * @see QWidget + * @see QFont + * @author Rober Griebl + */ +class OFontSelector : public QWidget +{ + Q_OBJECT + +public: + OFontSelector ( bool withpreview, QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + virtual ~OFontSelector ( ); + + bool selectedFont ( QString &family, QString &style, int &size ); + bool selectedFont ( QString &family, QString &style, int &size, QString &charset ); + + QFont selectedFont ( ); + + bool setSelectedFont ( const QFont & ); + bool setSelectedFont ( const QString &family, const QString &style, int size, const QString &charset = 0 ); + + QString fontFamily ( ) const; + QString fontStyle ( ) const; + int fontSize ( ) const; + QString fontCharSet ( ) const; + +signals: + /** + * This signal gets emitted when a font got chosen + */ + void fontSelected ( const QFont & ); + +protected slots: + /** @internal */ + virtual void fontFamilyClicked ( int ); + /** @internal */ + virtual void fontStyleClicked ( int ); + /** @internal */ + virtual void fontSizeClicked ( int ); + +protected: + virtual void resizeEvent ( QResizeEvent *re ); + +private: + void loadFonts ( QListBox * ); + + void changeFont ( ); + +private: + OFontSelectorPrivate *d; +}; + +#endif + diff --git a/noncore/unsupported/libopie/oprocctrl.cpp b/noncore/unsupported/libopie/oprocctrl.cpp new file mode 100644 index 0000000..df8da1e --- a/dev/null +++ b/noncore/unsupported/libopie/oprocctrl.cpp @@ -0,0 +1,267 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESSCONTROLLER -- A helper class for KProcess +// +// version 0.3.1, Jan, 8th 1997 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther +// + +//#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <qsocketnotifier.h> +#include "oprocctrl.h" + +OProcessController *OProcessController::theOProcessController = 0; + +struct sigaction OProcessController::oldChildHandlerData; +bool OProcessController::handlerSet = false; + +OProcessController::OProcessController() +{ + assert( theOProcessController == 0 ); + + if (0 > pipe(fd)) + printf(strerror(errno)); + + notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read); + notifier->setEnabled(true); + QObject::connect(notifier, SIGNAL(activated(int)), + this, SLOT(slotDoHousekeeping(int))); + connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()), + SLOT( delayedChildrenCleanup())); + + theOProcessController = this; + + setupHandlers(); +} + + +void OProcessController::setupHandlers() +{ + if( handlerSet ) + return; + struct sigaction act; + act.sa_handler=theSigCHLDHandler; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGCHLD); + // Make sure we don't block this signal. gdb tends to do that :-( + sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0); + + act.sa_flags = SA_NOCLDSTOP; + + // CC: take care of SunOS which automatically restarts interrupted system + // calls (and thus does not have SA_RESTART) + +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; +#endif + + sigaction( SIGCHLD, &act, &oldChildHandlerData ); + + act.sa_handler=SIG_IGN; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGPIPE); + act.sa_flags = 0; + sigaction( SIGPIPE, &act, 0L); + handlerSet = true; +} + +void OProcessController::resetHandlers() +{ + if( !handlerSet ) + return; + sigaction( SIGCHLD, &oldChildHandlerData, 0 ); + // there should be no problem with SIGPIPE staying SIG_IGN + handlerSet = false; +} + +// block SIGCHLD handler, because it accesses processList +void OProcessController::addOProcess( OProcess* p ) +{ + sigset_t newset, oldset; + sigemptyset( &newset ); + sigaddset( &newset, SIGCHLD ); + sigprocmask( SIG_BLOCK, &newset, &oldset ); + processList.append( p ); + sigprocmask( SIG_SETMASK, &oldset, 0 ); +} + +void OProcessController::removeOProcess( OProcess* p ) +{ + sigset_t newset, oldset; + sigemptyset( &newset ); + sigaddset( &newset, SIGCHLD ); + sigprocmask( SIG_BLOCK, &newset, &oldset ); + processList.remove( p ); + sigprocmask( SIG_SETMASK, &oldset, 0 ); +} + +//using a struct which contains both the pid and the status makes it easier to write +//and read the data into the pipe +//especially this solves a problem which appeared on my box where slotDoHouseKeeping() received +//only 4 bytes (with some debug output around the write()'s it received all 8 bytes) +//don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX +struct waitdata +{ + pid_t pid; + int status; +}; + +void OProcessController::theSigCHLDHandler(int arg) +{ + struct waitdata wd; +// int status; +// pid_t this_pid; + int saved_errno; + + saved_errno = errno; + // since waitpid and write change errno, we have to save it and restore it + // (Richard Stevens, Advanced programming in the Unix Environment) + + bool found = false; + if( theOProcessController != 0 ) { + // iterating the list doesn't perform any system call + for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin(); + it != theOProcessController->processList.end(); + ++it ) + { + if( !(*it)->isRunning()) + continue; + wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG ); + if ( wd.pid > 0 ) { + ::write(theOProcessController->fd[1], &wd, sizeof(wd)); + found = true; + } + } + } + if( !found && oldChildHandlerData.sa_handler != SIG_IGN + && oldChildHandlerData.sa_handler != SIG_DFL ) + oldChildHandlerData.sa_handler( arg ); // call the old handler + // handle the rest + if( theOProcessController != 0 ) { + static const struct waitdata dwd = { 0, 0 }; // delayed waitpid() + ::write(theOProcessController->fd[1], &dwd, sizeof(dwd)); + } else { + int dummy; + while( waitpid( -1, &dummy, WNOHANG ) > 0 ) + ; + } + + errno = saved_errno; +} + + + +void OProcessController::slotDoHousekeeping(int ) +{ + unsigned int bytes_read = 0; + unsigned int errcnt=0; + // read pid and status from the pipe. + struct waitdata wd; + while ((bytes_read < sizeof(wd)) && (errcnt < 50)) { + int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read); + if (r > 0) bytes_read += r; + else if (r < 0) errcnt++; + } + if (errcnt >= 50) { + fprintf(stderr, + "Error: Max. error count for pipe read " + "exceeded in OProcessController::slotDoHousekeeping\n"); + return; // it makes no sense to continue here! + } + if (bytes_read != sizeof(wd)) { + fprintf(stderr, + "Error: Could not read info from signal handler %d <> %d!\n", + bytes_read, sizeof(wd)); + return; // it makes no sense to continue here! + } + if (wd.pid==0) { // special case, see delayedChildrenCleanup() + delayedChildrenCleanupTimer.start( 1000, true ); + return; + } + + for( QValueList<OProcess*>::ConstIterator it = processList.begin(); + it != processList.end(); + ++it ) { + OProcess* proc = *it; + if (proc->pid() == wd.pid) { + // process has exited, so do emit the respective events + if (proc->run_mode == OProcess::Block) { + // If the reads are done blocking then set the status in proc + // but do nothing else because OProcess will perform the other + // actions of processHasExited. + proc->status = wd.status; + proc->runs = false; + } else { + proc->processHasExited(wd.status); + } + return; + } + } +} + +// this is needed e.g. for popen(), which calls waitpid() checking +// for its forked child, if we did waitpid() directly in the SIGCHLD +// handler, popen()'s waitpid() call would fail +void OProcessController::delayedChildrenCleanup() +{ + struct waitdata wd; + while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) { + for( QValueList<OProcess*>::ConstIterator it = processList.begin(); + it != processList.end(); + ++it ) + { + if( !(*it)->isRunning() || (*it)->pid() != wd.pid ) + continue; + // it's OProcess, handle it + ::write(fd[1], &wd, sizeof(wd)); + break; + } + } +} + +OProcessController::~OProcessController() +{ + assert( theOProcessController == this ); + resetHandlers(); + + notifier->setEnabled(false); + + close(fd[0]); + close(fd[1]); + + delete notifier; + theOProcessController = 0; +} + +//#include "kprocctrl.moc" diff --git a/noncore/unsupported/libopie/oprocctrl.h b/noncore/unsupported/libopie/oprocctrl.h new file mode 100644 index 0000000..5b39490 --- a/dev/null +++ b/noncore/unsupported/libopie/oprocctrl.h @@ -0,0 +1,121 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESSCONTROLLER -- A helper class for KProcess +// +// version 0.3.1, Jan 8th 1997 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther +// + +#ifndef __KPROCCTRL_H__ +#define __KPROCCTRL_H__ + +#include <qvaluelist.h> +#include <qtimer.h> + +#include "oprocess.h" + +class OProcessControllerPrivate; +class QSocketNotifier; + +/** + * @short Used internally by @ref OProcess + * @internal + * @author Christian Czezakte <e9025461@student.tuwien.ac.at> + * + * A class for internal use by OProcess only. -- Exactly one instance + * of this class is generated by the first instance of OProcess that is + * created (a pointer to it gets stored in @ref theOProcessController ). + * + * This class takes care of the actual (UN*X) signal handling. +*/ +class OProcessController : public QObject +{ + Q_OBJECT + +public: + OProcessController(); + ~OProcessController(); + //CC: WARNING! Destructor Not virtual (but you don't derive classes from this anyhow...) + +public: + + /** + * Only a single instance of this class is allowed at a time, + * and this static variable is used to track the one instance. + */ + static OProcessController *theOProcessController; + + /** + * Automatically called upon SIGCHLD. + * + * Normally you do not need to do anything with this function but + * if your application needs to disable SIGCHLD for some time for + * reasons beyond your control, you should call this function afterwards + * to make sure that no SIGCHLDs where missed. + */ + static void theSigCHLDHandler(int signal); + // handler for sigchld + + /** + * @internal + */ + static void setupHandlers(); + /** + * @internal + */ + static void resetHandlers(); + /** + * @internal + */ + void addOProcess( OProcess* ); + /** + * @internal + */ + void removeOProcess( OProcess* ); + public slots: + /** + * @internal + */ + void slotDoHousekeeping(int socket); + + private slots: + void delayedChildrenCleanup(); +private: + int fd[2]; + QSocketNotifier *notifier; + static struct sigaction oldChildHandlerData; + static bool handlerSet; + QValueList<OProcess*> processList; + QTimer delayedChildrenCleanupTimer; + + // Disallow assignment and copy-construction + OProcessController( const OProcessController& ); + OProcessController& operator= ( const OProcessController& ); + + OProcessControllerPrivate *d; +}; + + + +#endif + diff --git a/noncore/unsupported/libopie/oprocess.cpp b/noncore/unsupported/libopie/oprocess.cpp new file mode 100644 index 0000000..c19881a --- a/dev/null +++ b/noncore/unsupported/libopie/oprocess.cpp @@ -0,0 +1,925 @@ +/* + + $Id$ + + This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +// +// KPROCESS -- A class for handling child processes in KDE without +// having to take care of Un*x specific implementation details +// +// version 0.3.1, Jan 8th 1998 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// +// Changes: +// +// March 2nd, 1998: Changed parameter list for KShellProcess: +// Arguments are now placed in a single string so that +// <shell> -c <commandstring> is passed to the shell +// to make the use of "operator<<" consistent with KProcess +// +// +// Ported by Holger Freyther +// <zekce> Harlekin: oprocess and say it was ported to Qt by the Opie developers an Qt 2 + + + +#include "oprocess.h" +#define _MAY_INCLUDE_KPROCESSCONTROLLER_ +#include "oprocctrl.h" + +//#include <config.h> + +#include <qfile.h> +#include <qsocketnotifier.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef HAVE_INITGROUPS +#include <grp.h> +#endif +#include <pwd.h> + +#include <qapplication.h> +#include <qmap.h> +//#include <kdebug.h> + +///////////////////////////// +// public member functions // +///////////////////////////// + +class OProcessPrivate { +public: + OProcessPrivate() : useShell(false) { } + + bool useShell; + QMap<QString,QString> env; + QString wd; + QCString shell; +}; + + +OProcess::OProcess(QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); +} + +OProcess::OProcess(const QString &arg0, QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); + *this << arg0; +} + +OProcess::OProcess(const QStringList &args, QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); + *this << args; +} + +void OProcess::init ( ) +{ + run_mode = NotifyOnExit; + runs = false; + pid_ = 0; + status = 0; + keepPrivs = false; + innot = 0; + outnot = 0; + errnot = 0; + communication = NoCommunication; + input_data = 0; + input_sent = 0; + input_total = 0; + d = 0; + + if (0 == OProcessController::theOProcessController) { + (void) new OProcessController(); + CHECK_PTR(OProcessController::theOProcessController); + } + + OProcessController::theOProcessController->addOProcess(this); + out[0] = out[1] = -1; + in[0] = in[1] = -1; + err[0] = err[1] = -1; +} + +void +OProcess::setEnvironment(const QString &name, const QString &value) +{ + if (!d) + d = new OProcessPrivate; + d->env.insert(name, value); +} + +void +OProcess::setWorkingDirectory(const QString &dir) +{ + if (!d) + d = new OProcessPrivate; + d->wd = dir; +} + +void +OProcess::setupEnvironment() +{ + if (d) + { + QMap<QString,QString>::Iterator it; + for(it = d->env.begin(); it != d->env.end(); ++it) + setenv(QFile::encodeName(it.key()).data(), + QFile::encodeName(it.data()).data(), 1); + if (!d->wd.isEmpty()) + chdir(QFile::encodeName(d->wd).data()); + } +} + +void +OProcess::setRunPrivileged(bool keepPrivileges) +{ + keepPrivs = keepPrivileges; +} + +bool +OProcess::runPrivileged() const +{ + return keepPrivs; +} + + +OProcess::~OProcess() +{ + // destroying the OProcess instance sends a SIGKILL to the + // child process (if it is running) after removing it from the + // list of valid processes (if the process is not started as + // "DontCare") + + OProcessController::theOProcessController->removeOProcess(this); + // this must happen before we kill the child + // TODO: block the signal while removing the current process from the process list + + if (runs && (run_mode != DontCare)) + kill(SIGKILL); + + // Clean up open fd's and socket notifiers. + closeStdin(); + closeStdout(); + closeStderr(); + + // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess + delete d; +} + +void OProcess::detach() +{ + OProcessController::theOProcessController->removeOProcess(this); + + runs = false; + pid_ = 0; + + // Clean up open fd's and socket notifiers. + closeStdin(); + closeStdout(); + closeStderr(); +} + +bool OProcess::setExecutable(const QString& proc) +{ + if (runs) return false; + + if (proc.isEmpty()) return false; + + if (!arguments.isEmpty()) + arguments.remove(arguments.begin()); + arguments.prepend(QFile::encodeName(proc)); + + return true; +} + +OProcess &OProcess::operator<<(const QStringList& args) +{ + QStringList::ConstIterator it = args.begin(); + for ( ; it != args.end() ; ++it ) + arguments.append(QFile::encodeName(*it)); + return *this; +} + +OProcess &OProcess::operator<<(const QCString& arg) +{ + return operator<< (arg.data()); +} + +OProcess &OProcess::operator<<(const char* arg) +{ + arguments.append(arg); + return *this; +} + +OProcess &OProcess::operator<<(const QString& arg) +{ + arguments.append(QFile::encodeName(arg)); + return *this; +} + +void OProcess::clearArguments() +{ + arguments.clear(); +} + +bool OProcess::start(RunMode runmode, Communication comm) +{ + uint i; + uint n = arguments.count(); + char **arglist; + + if (runs || (0 == n)) { + return false; // cannot start a process that is already running + // or if no executable has been assigned + } + run_mode = runmode; + status = 0; + + QCString shellCmd; + if (d && d->useShell) + { + if (d->shell.isEmpty()) + { + qWarning( "Could not find a valid shell" ); + return false; + } + + arglist = static_cast<char **>(malloc( (4)*sizeof(char *))); + for (i=0; i < n; i++) { + shellCmd += arguments[i]; + shellCmd += " "; // CC: to separate the arguments + } + + arglist[0] = d->shell.data(); + arglist[1] = (char *) "-c"; + arglist[2] = shellCmd.data(); + arglist[3] = 0; + } + else + { + arglist = static_cast<char **>(malloc( (n+1)*sizeof(char *))); + for (i=0; i < n; i++) + arglist[i] = arguments[i].data(); + arglist[n]= 0; + } + + if (!setupCommunication(comm)) + qWarning( "Could not setup Communication!"); + + // We do this in the parent because if we do it in the child process + // gdb gets confused when the application runs from gdb. + uid_t uid = getuid(); + gid_t gid = getgid(); +#ifdef HAVE_INITGROUPS + struct passwd *pw = getpwuid(uid); +#endif + + int fd[2]; + if (0 > pipe(fd)) + { + fd[0] = fd[1] = 0; // Pipe failed.. continue + } + + runs = true; + + QApplication::flushX(); + + // WABA: Note that we use fork() and not vfork() because + // vfork() has unclear semantics and is not standardized. + pid_ = fork(); + + if (0 == pid_) { + if (fd[0]) + close(fd[0]); + if (!runPrivileged()) + { + setgid(gid); +#if defined( HAVE_INITGROUPS) + if(pw) + initgroups(pw->pw_name, pw->pw_gid); +#endif + setuid(uid); + } + // The child process + if(!commSetupDoneC()) + qWarning( "Could not finish comm setup in child!" ); + + setupEnvironment(); + + // Matthias + if (run_mode == DontCare) + setpgid(0,0); + // restore default SIGPIPE handler (Harri) + struct sigaction act; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGPIPE); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigaction(SIGPIPE, &act, 0L); + + // We set the close on exec flag. + // Closing of fd[1] indicates that the execvp succeeded! + if (fd[1]) + fcntl(fd[1], F_SETFD, FD_CLOEXEC); + execvp(arglist[0], arglist); + char resultByte = 1; + if (fd[1]) + write(fd[1], &resultByte, 1); + _exit(-1); + } else if (-1 == pid_) { + // forking failed + + runs = false; + free(arglist); + return false; + } else { + if (fd[1]) + close(fd[1]); + // the parent continues here + + // Discard any data for stdin that might still be there + input_data = 0; + + // Check whether client could be started. + if (fd[0]) for(;;) + { + char resultByte; + int n = ::read(fd[0], &resultByte, 1); + if (n == 1) + { + // Error + runs = false; + close(fd[0]); + free(arglist); + pid_ = 0; + return false; + } + if (n == -1) + { + if ((errno == ECHILD) || (errno == EINTR)) + continue; // Ignore + } + break; // success + } + if (fd[0]) + close(fd[0]); + + if (!commSetupDoneP()) // finish communication socket setup for the parent + qWarning( "Could not finish comm setup in parent!" ); + + if (run_mode == Block) { + commClose(); + + // The SIGCHLD handler of the process controller will catch + // the exit and set the status + while(runs) + { + OProcessController::theOProcessController-> + slotDoHousekeeping(0); + } + runs = FALSE; + emit processExited(this); + } + } + free(arglist); + return true; +} + + + +bool OProcess::kill(int signo) +{ + bool rv=false; + + if (0 != pid_) + rv= (-1 != ::kill(pid_, signo)); + // probably store errno somewhere... + return rv; +} + + + +bool OProcess::isRunning() const +{ + return runs; +} + + + +pid_t OProcess::pid() const +{ + return pid_; +} + + + +bool OProcess::normalExit() const +{ + int _status = status; + return (pid_ != 0) && (!runs) && (WIFEXITED((_status))); +} + + + +int OProcess::exitStatus() const +{ + int _status = status; + return WEXITSTATUS((_status)); +} + + + +bool OProcess::writeStdin(const char *buffer, int buflen) +{ + bool rv; + + // if there is still data pending, writing new data + // to stdout is not allowed (since it could also confuse + // kprocess... + if (0 != input_data) + return false; + + if (runs && (communication & Stdin)) { + input_data = buffer; + input_sent = 0; + input_total = buflen; + slotSendData(0); + innot->setEnabled(true); + rv = true; + } else + rv = false; + return rv; +} + +void OProcess::flushStdin ( ) +{ + if ( !input_data || ( input_sent == input_total )) + return; + + int d1, d2; + + do { + d1 = input_total - input_sent; + slotSendData ( 0 ); + d2 = input_total - input_sent; + } while ( d2 <= d1 ); +} + +void OProcess::suspend() +{ + if ((communication & Stdout) && outnot) + outnot->setEnabled(false); +} + +void OProcess::resume() +{ + if ((communication & Stdout) && outnot) + outnot->setEnabled(true); +} + +bool OProcess::closeStdin() +{ + bool rv; + + if (communication & Stdin) { + communication = (Communication) (communication & ~Stdin); + delete innot; + innot = 0; + close(in[1]); + rv = true; + } else + rv = false; + return rv; +} + +bool OProcess::closeStdout() +{ + bool rv; + + if (communication & Stdout) { + communication = (Communication) (communication & ~Stdout); + delete outnot; + outnot = 0; + close(out[0]); + rv = true; + } else + rv = false; + return rv; +} + +bool OProcess::closeStderr() +{ + bool rv; + + if (communication & Stderr) { + communication = static_cast<Communication>(communication & ~Stderr); + delete errnot; + errnot = 0; + close(err[0]); + rv = true; + } else + rv = false; + return rv; +} + + +///////////////////////////// +// protected slots // +///////////////////////////// + + + +void OProcess::slotChildOutput(int fdno) +{ + if (!childOutput(fdno)) + closeStdout(); +} + + +void OProcess::slotChildError(int fdno) +{ + if (!childError(fdno)) + closeStderr(); +} + + +void OProcess::slotSendData(int) +{ + if (input_sent == input_total) { + innot->setEnabled(false); + input_data = 0; + emit wroteStdin(this); + } else + input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent); +} + + + +////////////////////////////// +// private member functions // +////////////////////////////// + + + +void OProcess::processHasExited(int state) +{ + if (runs) + { + runs = false; + status = state; + + commClose(); // cleanup communication sockets + + // also emit a signal if the process was run Blocking + if (DontCare != run_mode) + { + emit processExited(this); + } + } +} + + + +int OProcess::childOutput(int fdno) +{ + if (communication & NoRead) { + int len = -1; + emit receivedStdout(fdno, len); + errno = 0; // Make sure errno doesn't read "EAGAIN" + return len; + } + else + { + char buffer[1024]; + int len; + + len = ::read(fdno, buffer, 1024); + + if ( 0 < len) { + emit receivedStdout(this, buffer, len); + } + return len; + } +} + + + +int OProcess::childError(int fdno) +{ + char buffer[1024]; + int len; + + len = ::read(fdno, buffer, 1024); + + if ( 0 < len) + emit receivedStderr(this, buffer, len); + return len; +} + + + +int OProcess::setupCommunication(Communication comm) +{ + int ok; + + communication = comm; + + ok = 1; + if (comm & Stdin) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0; + + if (comm & Stdout) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0; + + if (comm & Stderr) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0; + + return ok; +} + + + +int OProcess::commSetupDoneP() +{ + int ok = 1; + + if (communication != NoCommunication) { + if (communication & Stdin) + close(in[0]); + if (communication & Stdout) + close(out[1]); + if (communication & Stderr) + close(err[1]); + + // Don't create socket notifiers and set the sockets non-blocking if + // blocking is requested. + if (run_mode == Block) return ok; + + if (communication & Stdin) { +// ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); + innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this); + CHECK_PTR(innot); + innot->setEnabled(false); // will be enabled when data has to be sent + QObject::connect(innot, SIGNAL(activated(int)), + this, SLOT(slotSendData(int))); + } + + if (communication & Stdout) { +// ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); + outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this); + CHECK_PTR(outnot); + QObject::connect(outnot, SIGNAL(activated(int)), + this, SLOT(slotChildOutput(int))); + if (communication & NoRead) + suspend(); + } + + if (communication & Stderr) { +// ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); + errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this ); + CHECK_PTR(errnot); + QObject::connect(errnot, SIGNAL(activated(int)), + this, SLOT(slotChildError(int))); + } + } + return ok; +} + + + +int OProcess::commSetupDoneC() +{ + int ok = 1; + struct linger so; + memset(&so, 0, sizeof(so)); + + if (communication & Stdin) + close(in[1]); + if (communication & Stdout) + close(out[0]); + if (communication & Stderr) + close(err[0]); + + if (communication & Stdin) + ok &= dup2(in[0], STDIN_FILENO) != -1; + else { + int null_fd = open( "/dev/null", O_RDONLY ); + ok &= dup2( null_fd, STDIN_FILENO ) != -1; + close( null_fd ); + } + if (communication & Stdout) { + ok &= dup2(out[1], STDOUT_FILENO) != -1; + ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so)); + } + else { + int null_fd = open( "/dev/null", O_WRONLY ); + ok &= dup2( null_fd, STDOUT_FILENO ) != -1; + close( null_fd ); + } + if (communication & Stderr) { + ok &= dup2(err[1], STDERR_FILENO) != -1; + ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so)); + } + else { + int null_fd = open( "/dev/null", O_WRONLY ); + ok &= dup2( null_fd, STDERR_FILENO ) != -1; + close( null_fd ); + } + return ok; +} + + + +void OProcess::commClose() +{ + if (NoCommunication != communication) { + bool b_in = (communication & Stdin); + bool b_out = (communication & Stdout); + bool b_err = (communication & Stderr); + if (b_in) + delete innot; + + if (b_out || b_err) { + // If both channels are being read we need to make sure that one socket buffer + // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). + // Hence we need to use select. + + // Once one or other of the channels has reached EOF (or given an error) go back + // to the usual mechanism. + + int fds_ready = 1; + fd_set rfds; + + int max_fd = 0; + if (b_out) { + fcntl(out[0], F_SETFL, O_NONBLOCK); + if (out[0] > max_fd) + max_fd = out[0]; + delete outnot; + outnot = 0; + } + if (b_err) { + fcntl(err[0], F_SETFL, O_NONBLOCK); + if (err[0] > max_fd) + max_fd = err[0]; + delete errnot; + errnot = 0; + } + + + while (b_out || b_err) { + // * If the process is still running we block until we + // receive data. (p_timeout = 0, no timeout) + // * If the process has already exited, we only check + // the available data, we don't wait for more. + // (p_timeout = &timeout, timeout immediately) + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + struct timeval *p_timeout = runs ? 0 : &timeout; + + FD_ZERO(&rfds); + if (b_out) + FD_SET(out[0], &rfds); + + if (b_err) + FD_SET(err[0], &rfds); + + fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout); + if (fds_ready <= 0) break; + + if (b_out && FD_ISSET(out[0], &rfds)) { + int ret = 1; + while (ret > 0) ret = childOutput(out[0]); + if ((ret == -1 && errno != EAGAIN) || ret == 0) + b_out = false; + } + + if (b_err && FD_ISSET(err[0], &rfds)) { + int ret = 1; + while (ret > 0) ret = childError(err[0]); + if ((ret == -1 && errno != EAGAIN) || ret == 0) + b_err = false; + } + } + } + + if (b_in) { + communication = (Communication) (communication & ~Stdin); + close(in[1]); + } + if (b_out) { + communication = (Communication) (communication & ~Stdout); + close(out[0]); + } + if (b_err) { + communication = (Communication) (communication & ~Stderr); + close(err[0]); + } + } +} + +void OProcess::setUseShell(bool useShell, const char *shell) +{ + if (!d) + d = new OProcessPrivate; + d->useShell = useShell; + d->shell = shell; + if (d->shell.isEmpty()) + d->shell = searchShell(); +} + +QString OProcess::quote(const QString &arg) +{ + QString res = arg; + res.replace(QRegExp(QString::fromLatin1("\'")), + QString::fromLatin1("'\"'\"'")); + res.prepend('\''); + res.append('\''); + return res; +} + +QCString OProcess::searchShell() +{ + QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace(); + if (!isExecutable(tmpShell)) + { + tmpShell = "/bin/sh"; + } + + return tmpShell; +} + +bool OProcess::isExecutable(const QCString &filename) +{ + struct stat fileinfo; + + if (filename.isEmpty()) return false; + + // CC: we've got a valid filename, now let's see whether we can execute that file + + if (-1 == stat(filename.data(), &fileinfo)) return false; + // CC: return false if the file does not exist + + // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets + if ( (S_ISDIR(fileinfo.st_mode)) || + (S_ISCHR(fileinfo.st_mode)) || + (S_ISBLK(fileinfo.st_mode)) || +#ifdef S_ISSOCK + // CC: SYSVR4 systems don't have that macro + (S_ISSOCK(fileinfo.st_mode)) || +#endif + (S_ISFIFO(fileinfo.st_mode)) || + (S_ISDIR(fileinfo.st_mode)) ) { + return false; + } + + // CC: now check for permission to execute the file + if (access(filename.data(), X_OK) != 0) return false; + + // CC: we've passed all the tests... + return true; +} + + + diff --git a/noncore/unsupported/libopie/oprocess.h b/noncore/unsupported/libopie/oprocess.h new file mode 100644 index 0000000..af7cddb --- a/dev/null +++ b/noncore/unsupported/libopie/oprocess.h @@ -0,0 +1,747 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESS -- A class for handling child processes in KDE without +// having to take care of Un*x specific implementation details +// +// version 0.3.1, Jan 8th 1998 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther to the Open Palmtop Integrated Environment +// + +#ifndef __kprocess_h__ +#define __kprocess_h__ + +#include <sys/types.h> // for pid_t +#include <sys/wait.h> +#include <signal.h> +#include <unistd.h> +#include <qvaluelist.h> +#include <qcstring.h> +#include <qobject.h> + +class QSocketNotifier; +class OProcessPrivate; + +/** + * Child process invocation, monitoring and control. + * + * @sect General usage and features + * + *This class allows a KDE and OPIE application to start child processes without having + *to worry about UN*X signal handling issues and zombie process reaping. + * + *@see KProcIO + * + *Basically, this class distinguishes three different ways of running + *child processes: + * + *@li OProcess::DontCare -- The child process is invoked and both the child + *process and the parent process continue concurrently. + * + *Starting a DontCare child process means that the application is + *not interested in any notification to determine whether the + *child process has already exited or not. + * + *@li OProcess::NotifyOnExit -- The child process is invoked and both the + *child and the parent process run concurrently. + * + *When the child process exits, the OProcess instance + *corresponding to it emits the Qt signal @ref processExited(). + * + *Since this signal is @em not emitted from within a UN*X + *signal handler, arbitrary function calls can be made. + * + *Be aware: When the OProcess objects gets destructed, the child + *process will be killed if it is still running! + *This means in particular, that you cannot use a OProcess on the stack + *with OProcess::NotifyOnExit. + * + *@li OProcess::Block -- The child process starts and the parent process + *is suspended until the child process exits. (@em Really not recommended + *for programs with a GUI.) + * + *OProcess also provides several functions for determining the exit status + *and the pid of the child process it represents. + * + *Furthermore it is possible to supply command-line arguments to the process + *in a clean fashion (no null -- terminated stringlists and such...) + * + *A small usage example: + *<pre> + *OProcess *proc = new OProcess; + * + **proc << "my_executable"; + **proc << "These" << "are" << "the" << "command" << "line" << "args"; + *QApplication::connect(proc, SIGNAL(processExited(OProcess *)), + * pointer_to_my_object, SLOT(my_objects_slot(OProcess *))); + *proc->start(); + *</pre> + * + *This will start "my_executable" with the commandline arguments "These"... + * + *When the child process exits, the respective Qt signal will be emitted. + * + *@sect Communication with the child process + * + *OProcess supports communication with the child process through + *stdin/stdout/stderr. + * + *The following functions are provided for getting data from the child + *process or sending data to the child's stdin (For more information, + *have a look at the documentation of each function): + * + *@li bool @ref writeStdin(char *buffer, int buflen); + *@li -- Transmit data to the child process's stdin. + * + *@li bool @ref closeStdin(); + *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)). + *Returns false if you try to close stdin for a process that has been started + *without a communication channel to stdin. + * + *@li bool @ref closeStdout(); + *@li -- Closes the child process's stdout. + *Returns false if you try to close stdout for a process that has been started + *without a communication channel to stdout. + * + *@li bool @ref closeStderr(); + *@li -- Closes the child process's stderr. + *Returns false if you try to close stderr for a process that has been started + *without a communication channel to stderr. + * + * + *@sect QT signals: + * + *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen); + *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen); + *@li -- Indicates that new data has arrived from either the + *child process's stdout or stderr. + * + *@li void @ref wroteStdin(OProcess *proc); + *@li -- Indicates that all data that has been sent to the child process + *by a prior call to @ref writeStdin() has actually been transmitted to the + *client . + * + *@author Christian Czezakte e9025461@student.tuwien.ac.at + * + * + **/ +class OProcess : public QObject +{ + Q_OBJECT + +public: + + /** + * Modes in which the communication channel can be opened. + * + * If communication for more than one channel is required, + * the values have to be or'ed together, for example to get + * communication with stdout as well as with stdin, you would + * specify @p Stdin @p | @p Stdout + * + * If @p NoRead is specified in conjunction with @p Stdout, + * no data is actually read from @p Stdout but only + * the signal @ref childOutput(int fd) is emitted. + */ + enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4, + AllOutput = 6, All = 7, + NoRead }; + + /** + * Run-modes for a child process. + */ + enum RunMode { + /** + * The application does not receive notifications from the subprocess when + * it is finished or aborted. + */ + DontCare, + /** + * The application is notified when the subprocess dies. + */ + NotifyOnExit, + /** + * The application is suspended until the started process is finished. + */ + Block }; + + /** + * Constructor + */ + OProcess(QObject *parent = 0, const char *name = 0); + /** + * Constructor + */ + OProcess(const QString &arg0, QObject *parent = 0, const char *name = 0); + /** + * Constructor + */ + OProcess(const QStringList &args, QObject *parent = 0, const char *name = 0); + + /** + *Destructor: + * + * If the process is running when the destructor for this class + * is called, the child process is killed with a SIGKILL, but + * only if the run mode is not of type @p DontCare. + * Processes started as @p DontCare keep running anyway. + */ + virtual ~OProcess(); + + /** + @deprecated + + The use of this function is now deprecated. -- Please use the + "operator<<" instead of "setExecutable". + + Sets the executable to be started with this OProcess object. + Returns false if the process is currently running (in that + case the executable remains unchanged.) + + @see operator<< + + */ + bool setExecutable(const QString& proc); + + + /** + * Sets the executable and the command line argument list for this process. + * + * For example, doing an "ls -l /usr/local/bin" can be achieved by: + * <pre> + * OProcess p; + * ... + * p << "ls" << "-l" << "/usr/local/bin" + * </pre> + * + **/ + OProcess &operator<<(const QString& arg); + /** + * Similar to previous method, takes a char *, supposed to be in locale 8 bit already. + */ + OProcess &operator<<(const char * arg); + /** + * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already. + */ + OProcess &operator<<(const QCString & arg); + + /** + * Sets the executable and the command line argument list for this process, + * in a single method call, or add a list of arguments. + **/ + OProcess &operator<<(const QStringList& args); + + /** + * Clear a command line argument list that has been set by using + * the "operator<<". + */ + void clearArguments(); + + /** + * Starts the process. + * For a detailed description of the + * various run modes and communication semantics, have a look at the + * general description of the OProcess class. + * + * The following problems could cause this function to + * return false: + * + * @li The process is already running. + * @li The command line argument list is empty. + * @li The starting of the process failed (could not fork). + * @li The executable was not found. + * + * @param comm Specifies which communication links should be + * established to the child process (stdin/stdout/stderr). By default, + * no communication takes place and the respective communication + * signals will never get emitted. + * + * @return true on success, false on error + * (see above for error conditions) + **/ + virtual bool start(RunMode runmode = NotifyOnExit, + Communication comm = NoCommunication); + + /** + * Stop the process (by sending it a signal). + * + * @param signo The signal to send. The default is SIGTERM. + * @return @p true if the signal was delivered successfully. + */ + virtual bool kill(int signo = SIGTERM); + + /** + @return @p true if the process is (still) considered to be running + */ + bool isRunning() const; + + /** Returns the process id of the process. + * + * If it is called after + * the process has exited, it returns the process id of the last + * child process that was created by this instance of OProcess. + * + * Calling it before any child process has been started by this + * OProcess instance causes pid() to return 0. + **/ + pid_t pid() const; + + /** + * Suspend processing of data from stdout of the child process. + */ + void suspend(); + + /** + * Resume processing of data from stdout of the child process. + */ + void resume(); + + /** + * @return @p true if the process has already finished and has exited + * "voluntarily", ie: it has not been killed by a signal. + * + * Note that you should check @ref OProcess::exitStatus() to determine + * whether the process completed its task successful or not. + */ + bool normalExit() const; + + /** + * Returns the exit status of the process. + * + * Please use + * @ref OProcess::normalExit() to check whether the process has exited + * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling + * this function because if the process did not exit normally, + * it does not have a valid exit status. + */ + int exitStatus() const; + + + /** + * Transmit data to the child process's stdin. + * + * OProcess::writeStdin may return false in the following cases: + * + * @li The process is not currently running. + * + * @li Communication to stdin has not been requested in the @ref start() call. + * + * @li Transmission of data to the child process by a previous call to + * @ref writeStdin() is still in progress. + * + * Please note that the data is sent to the client asynchronously, + * so when this function returns, the data might not have been + * processed by the child process. + * + * If all the data has been sent to the client, the signal + * @ref wroteStdin() will be emitted. + * + * Please note that you must not free "buffer" or call @ref writeStdin() + * again until either a @ref wroteStdin() signal indicates that the + * data has been sent or a @ref processHasExited() signal shows that + * the child process is no longer alive... + **/ + bool writeStdin(const char *buffer, int buflen); + + void flushStdin(); + + /** + * This causes the stdin file descriptor of the child process to be + * closed indicating an "EOF" to the child. + * + * @return @p false if no communication to the process's stdin + * had been specified in the call to @ref start(). + */ + bool closeStdin(); + + /** + * This causes the stdout file descriptor of the child process to be + * closed. + * + * @return @p false if no communication to the process's stdout + * had been specified in the call to @ref start(). + */ + bool closeStdout(); + + /** + * This causes the stderr file descriptor of the child process to be + * closed. + * + * @return @p false if no communication to the process's stderr + * had been specified in the call to @ref start(). + */ + bool closeStderr(); + + /** + * Lets you see what your arguments are for debugging. + */ + + const QValueList<QCString> &args() { return arguments; } + + /** + * Controls whether the started process should drop any + * setuid/segid privileges or whether it should keep them + * + * The default is @p false : drop privileges + */ + void setRunPrivileged(bool keepPrivileges); + + /** + * Returns whether the started process will drop any + * setuid/segid privileges or whether it will keep them + */ + bool runPrivileged() const; + + /** + * Modifies the environment of the process to be started. + * This function must be called before starting the process. + */ + void setEnvironment(const QString &name, const QString &value); + + /** + * Changes the current working directory (CWD) of the process + * to be started. + * This function must be called before starting the process. + */ + void setWorkingDirectory(const QString &dir); + + /** + * Specify whether to start the command via a shell or directly. + * The default is to start the command directly. + * If @p useShell is true @p shell will be used as shell, or + * if shell is empty, the standard shell is used. + * @p quote A flag indicating whether to quote the arguments. + * + * When using a shell, the caller should make sure that all filenames etc. + * are properly quoted when passed as argument. + * @see quote() + */ + void setUseShell(bool useShell, const char *shell = 0); + + /** + * This function can be used to quote an argument string such that + * the shell processes it properly. This is e. g. necessary for + * user-provided file names which may contain spaces or quotes. + * It also prevents expansion of wild cards and environment variables. + */ + static QString quote(const QString &arg); + + /** + * Detaches OProcess from child process. All communication is closed. + * No exit notification is emitted any more for the child process. + * Deleting the OProcess will no longer kill the child process. + * Note that the current process remains the parent process of the + * child process. + */ + void detach(); + + + +signals: + + /** + * Emitted after the process has terminated when + * the process was run in the @p NotifyOnExit (==default option to + * @ref start()) or the @ref Block mode. + **/ + void processExited(OProcess *proc); + + + /** + * Emitted, when output from the child process has + * been received on stdout. + * + * To actually get + * these signals, the respective communication link (stdout/stderr) + * has to be turned on in @ref start(). + * + * @param buffer The data received. + * @param buflen The number of bytes that are available. + * + * You should copy the information contained in @p buffer to your private + * data structures before returning from this slot. + **/ + void receivedStdout(OProcess *proc, char *buffer, int buflen); + + /** + * Emitted when output from the child process has + * been received on stdout. + * + * To actually get these signals, the respective communications link + * (stdout/stderr) has to be turned on in @ref start() and the + * @p NoRead flag should have been passed. + * + * You will need to explicitly call resume() after your call to start() + * to begin processing data from the child process's stdout. This is + * to ensure that this signal is not emitted when no one is connected + * to it, otherwise this signal will not be emitted. + * + * The data still has to be read from file descriptor @p fd. + **/ + void receivedStdout(int fd, int &len); + + + /** + * Emitted, when output from the child process has + * been received on stderr. + * To actually get + * these signals, the respective communication link (stdout/stderr) + * has to be turned on in @ref start(). + * + * @param buffer The data received. + * @param buflen The number of bytes that are available. + * + * You should copy the information contained in @p buffer to your private + * data structures before returning from this slot. + */ + void receivedStderr(OProcess *proc, char *buffer, int buflen); + + /** + * Emitted after all the data that has been + * specified by a prior call to @ref writeStdin() has actually been + * written to the child process. + **/ + void wroteStdin(OProcess *proc); + + +protected slots: + + /** + * This slot gets activated when data from the child's stdout arrives. + * It usually calls "childOutput" + */ + void slotChildOutput(int fdno); + + /** + * This slot gets activated when data from the child's stderr arrives. + * It usually calls "childError" + */ + void slotChildError(int fdno); + /* + Slot functions for capturing stdout and stderr of the child + */ + + /** + * Called when another bulk of data can be sent to the child's + * stdin. If there is no more data to be sent to stdin currently + * available, this function must disable the QSocketNotifier "innot". + */ + void slotSendData(int dummy); + +protected: + + /** + * Sets up the environment according to the data passed via + * setEnvironment(...) + */ + void setupEnvironment(); + + /** + * The list of the process' command line arguments. The first entry + * in this list is the executable itself. + */ + QValueList<QCString> arguments; + /** + * How to run the process (Block, NotifyOnExit, DontCare). You should + * not modify this data member directly from derived classes. + */ + RunMode run_mode; + /** + * true if the process is currently running. You should not + * modify this data member directly from derived classes. For + * reading the value of this data member, please use "isRunning()" + * since "runs" will probably be made private in later versions + * of OProcess. + */ + bool runs; + + /** + * The PID of the currently running process (see "getPid()"). + * You should not modify this data member in derived classes. + * Please use "getPid()" instead of directly accessing this + * member function since it will probably be made private in + * later versions of OProcess. + */ + pid_t pid_; + + /** + * The process' exit status as returned by "waitpid". You should not + * modify the value of this data member from derived classes. You should + * rather use @ref exitStatus than accessing this data member directly + * since it will probably be made private in further versions of + * OProcess. + */ + int status; + + + /** + * See setRunPrivileged() + */ + bool keepPrivs; + + /* + Functions for setting up the sockets for communication. + setupCommunication + -- is called from "start" before "fork"ing. + commSetupDoneP + -- completes communication socket setup in the parent + commSetupDoneC + -- completes communication setup in the child process + commClose + -- frees all allocated communication resources in the parent + after the process has exited + */ + + /** + * This function is called from "OProcess::start" right before a "fork" takes + * place. According to + * the "comm" parameter this function has to initialize the "in", "out" and + * "err" data member of OProcess. + * + * This function should return 0 if setting the needed communication channels + * was successful. + * + * The default implementation is to create UNIX STREAM sockets for the communication, + * but you could overload this function and establish a TCP/IP communication for + * network communication, for example. + */ + virtual int setupCommunication(Communication comm); + + /** + * Called right after a (successful) fork on the parent side. This function + * will usually do some communications cleanup, like closing the reading end + * of the "stdin" communication channel. + * + * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and + * "errnot" and connect their Qt slots to the respective OProcess member functions. + * + * For a more detailed explanation, it is best to have a look at the default + * implementation of "setupCommunication" in kprocess.cpp. + */ + virtual int commSetupDoneP(); + + /** + * Called right after a (successful) fork, but before an "exec" on the child + * process' side. It usually just closes the unused communication ends of + * "in", "out" and "err" (like the writing end of the "in" communication + * channel. + */ + virtual int commSetupDoneC(); + + + /** + * Immediately called after a process has exited. This function normally + * calls commClose to close all open communication channels to this + * process and emits the "processExited" signal (if the process was + * not running in the "DontCare" mode). + */ + virtual void processHasExited(int state); + + /** + * Should clean up the communication links to the child after it has + * exited. Should be called from "processHasExited". + */ + virtual void commClose(); + + + /** + * the socket descriptors for stdin/stdout/stderr. + */ + int out[2]; + int in[2]; + int err[2]; + + /** + * The socket notifiers for the above socket descriptors. + */ + QSocketNotifier *innot; + QSocketNotifier *outnot; + QSocketNotifier *errnot; + + /** + * Lists the communication links that are activated for the child + * process. Should not be modified from derived classes. + */ + Communication communication; + + /** + * Called by "slotChildOutput" this function copies data arriving from the + * child process's stdout to the respective buffer and emits the signal + * "@ref receivedStderr". + */ + int childOutput(int fdno); + + /** + * Called by "slotChildOutput" this function copies data arriving from the + * child process's stdout to the respective buffer and emits the signal + * "@ref receivedStderr" + */ + int childError(int fdno); + + // information about the data that has to be sent to the child: + + const char *input_data; // the buffer holding the data + int input_sent; // # of bytes already transmitted + int input_total; // total length of input_data + + /** + * @ref OProcessController is a friend of OProcess because it has to have + * access to various data members. + */ + friend class OProcessController; + + +private: + /** + * Searches for a valid shell. + * Here is the algorithm used for finding an executable shell: + * + * @li Try the executable pointed to by the "SHELL" environment + * variable with white spaces stripped off + * + * @li If your process runs with uid != euid or gid != egid, a shell + * not listed in /etc/shells will not used. + * + * @li If no valid shell could be found, "/bin/sh" is used as a last resort. + */ + QCString searchShell(); + + /** + * Used by @ref searchShell in order to find out whether the shell found + * is actually executable at all. + */ + bool isExecutable(const QCString &filename); + + // Disallow assignment and copy-construction + OProcess( const OProcess& ); + OProcess& operator= ( const OProcess& ); + +private: + void init ( ); + + OProcessPrivate *d; +}; + + + +#endif + diff --git a/noncore/unsupported/libopie/orecurrancebase.ui b/noncore/unsupported/libopie/orecurrancebase.ui new file mode 100644 index 0000000..baf79d3 --- a/dev/null +++ b/noncore/unsupported/libopie/orecurrancebase.ui @@ -0,0 +1,713 @@ +<!DOCTYPE UI><UI> +<class>ORecurranceBase</class> +<comment>********************************************************************* +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +** $Id$ +** +*********************************************************************</comment> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>ORecurranceBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>246</width> + <height>309</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Repeating Event </string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>1</number> + </property> + <widget> + <class>QButtonGroup</class> + <property stdset="1"> + <name>name</name> + <cstring>fraType</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>NoFrame</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Sunken</enum> + </property> + <property stdset="1"> + <name>title</name> + <string></string> + </property> + <property stdset="1"> + <name>exclusive</name> + <bool>true</bool> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>1</number> + </property> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdNone</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>None</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdDay</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Day</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdWeek</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Week</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdMonth</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Month</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdYear</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Year</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout4</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblEvery</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Every:</string> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>spinFreq</cstring> + </property> + <property stdset="1"> + <name>minValue</name> + <number>1</number> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblFreq</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Frequency</string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout8</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblEnd</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>End On:</string> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdEnd</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>No End Date</string> + </property> + </widget> + <widget> + <class>QCheckBox</class> + <property stdset="1"> + <name>name</name> + <cstring>chkNoEnd</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>No End Date</string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QButtonGroup</class> + <property stdset="1"> + <name>name</name> + <cstring>fraExtra</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>Box</enum> + </property> + <property stdset="1"> + <name>title</name> + <string>Repeat On</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>1</number> + </property> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Mon</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Tue</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra3</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Wed</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra4</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Thu</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra5</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Fri</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra6</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Sat</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>cmdExtra7</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Sun</string> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QFrame</class> + <property stdset="1"> + <name>name</name> + <cstring>Frame3</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>Box</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Sunken</enum> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>1</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout6</cstring> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>0</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblRepeat</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>3</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Every</string> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignTop|AlignLeft</set> + </property> + <property> + <name>hAlign</name> + </property> + <property> + <name>vAlign</name> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblVar1</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Var1</string> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignTop|AlignLeft</set> + </property> + <property> + <name>hAlign</name> + </property> + <property> + <name>vAlign</name> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblVar2</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Var 2</string> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignTop|AlignRight</set> + </property> + <property> + <name>hAlign</name> + </property> + <property> + <name>vAlign</name> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>lblWeekVar</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>7</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>WeekVar</string> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignTop|AlignHCenter</set> + </property> + <property> + <name>hAlign</name> + </property> + <property> + <name>vAlign</name> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>chkNoEnd</sender> + <signal>toggled(bool)</signal> + <receiver>cmdEnd</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>chkNoEnd</sender> + <signal>toggled(bool)</signal> + <receiver>ORecurranceBase</receiver> + <slot>slotNoEnd(bool)</slot> + </connection> + <connection> + <sender>spinFreq</sender> + <signal>valueChanged(int)</signal> + <receiver>lblVar1</receiver> + <slot>setNum(int)</slot> + </connection> + <connection> + <sender>spinFreq</sender> + <signal>valueChanged(int)</signal> + <receiver>ORecurranceBase</receiver> + <slot>setupRepeatLabel( int )</slot> + </connection> + <connection> + <sender>fraType</sender> + <signal>clicked(int)</signal> + <receiver>ORecurranceBase</receiver> + <slot>slotSetRType( int )</slot> + </connection> + <connection> + <sender>fraExtra</sender> + <signal>clicked(int)</signal> + <receiver>ORecurranceBase</receiver> + <slot>slotMonthLabel( int )</slot> + </connection> + <connection> + <sender>fraExtra</sender> + <signal>clicked(int)</signal> + <receiver>ORecurranceBase</receiver> + <slot>slotWeekLabel()</slot> + </connection> + <slot access="public">setupRepeatLabel( const QString & )</slot> + <slot access="public">setupRepeatLabel( int )</slot> + <slot access="public">slotMonthLabel( int )</slot> + <slot access="public">slotNoEnd(bool)</slot> + <slot access="public">slotSetRType( int )</slot> + <slot access="public">slotWeekLabel()</slot> +</connections> +</UI> diff --git a/noncore/unsupported/libopie/orecurrancewidget.cpp b/noncore/unsupported/libopie/orecurrancewidget.cpp new file mode 100644 index 0000000..33be269 --- a/dev/null +++ b/noncore/unsupported/libopie/orecurrancewidget.cpp @@ -0,0 +1,632 @@ +#include <qapplication.h> +#include <qlabel.h> +#include <qspinbox.h> + + +#include "orecurrancewidget.h" + +// Global Templates for use in setting up the repeat label... +// the problem is these strings get initialized before QPEApplication can install the translator -zecke +namespace { +QString strDayTemplate; +QString strYearTemplate; +QString strMonthDateTemplate; +QString strMonthDayTemplate; +QString strWeekTemplate; +QString dayLabel[7]; +} + +/* + * static linkage to not polute the symbol table... + * The problem is that const and static linkage are resolved prior to installing a translator + * leading to that the above strings are translted but to the original we delay the init of these strings... + * -zecke + */ +static void fillStrings() { + strDayTemplate = QObject::tr("Every"); + strYearTemplate = QObject::tr("%1 %2 every "); + strMonthDateTemplate = QObject::tr("The %1 every "); + strMonthDayTemplate = QObject::tr("The %1 %2 of every"); + strWeekTemplate = QObject::tr("Every "); + dayLabel[0] = QObject::tr("Monday"); + dayLabel[1] = QObject::tr("Tuesday"); + dayLabel[2] = QObject::tr("Wednesday"); + dayLabel[3] = QObject::tr("Thursday"); + dayLabel[4] = QObject::tr("Friday"); + dayLabel[5] = QObject::tr("Saturday"); + dayLabel[6] = QObject::tr("Sunday"); +} + +static QString numberPlacing( int x ); // return the proper word format for + // x (1st, 2nd, etc) +static int week( const QDate &dt ); // what week in the month is dt? + +/** + * Constructs the Widget + * @param startOnMonday Does the week start on monday + * @param newStart The start date of the recurrence + * @param parent The parent widget + * @param name the name of object + * @param modal if the dialog should be modal + * @param fl Additional window flags + */ +ORecurranceWidget::ORecurranceWidget( bool startOnMonday, + const QDate& newStart, + QWidget* parent, + const char* name, + bool modal, + WFlags fl ) + : ORecurranceBase( parent, name, modal, fl ), + start( newStart ), + currInterval( None ), + startWeekOnMonday( startOnMonday ) +{ + if (strDayTemplate.isEmpty() ) + fillStrings(); + + init(); + fraType->setButton( currInterval ); + chkNoEnd->setChecked( TRUE ); + setupNone(); +} + +/** + * Different constructor + * @param startOnMonday Does the week start on monday? + * @param rp Already set ORecur object + * @param startDate The start date + * @param parent The parent widget + * @param name The name of the object + * @param modal + * @param fl The flags for window + */ +ORecurranceWidget::ORecurranceWidget( bool startOnMonday, + const ORecur& rp, const QDate& startDate, + QWidget* parent, const char* name, + bool modal, WFlags fl) + : ORecurranceBase( parent, name, modal, fl ), + start( startDate ), + end( rp.endDate() ), + startWeekOnMonday( startOnMonday ) +{ + if (strDayTemplate.isEmpty() ) + fillStrings(); + // do some stuff with the repeat pattern + init(); + setRecurrence( rp ); +} + +ORecurranceWidget::~ORecurranceWidget() { +} + +/** + * set the start date + * @param date the new start date + */ +void ORecurranceWidget::setStartDate( const QDate& date ) { + setRecurrence( recurrence(), date ); +} +/** + * set the recurrence + * @param rp The ORecur object with the new recurrence rules + */ +void ORecurranceWidget::setRecurrence( const ORecur& rp ) { + setRecurrence( rp, start ); +} + +/** + * overloaded method taking ORecur and a new start date + * @param rp Recurrence rule + * @param date The new start date + */ +void ORecurranceWidget::setRecurrence( const ORecur& rp, const QDate& date ) { + start = date; + end = rp.endDate(); + switch ( rp.type() ) { + default: + case ORecur::NoRepeat: + currInterval = None; + setupNone(); + break; + case ORecur::Daily: + currInterval = Day; + setupDaily(); + break; + case ORecur::Weekly: + currInterval = Week; + setupWeekly(); + int day, buttons; + for ( day = 0x01, buttons = 0; buttons < 7; + day = day << 1, buttons++ ) { + if ( rp.days() & day ) { + if ( startWeekOnMonday ) + fraExtra->setButton( buttons ); + else { + if ( buttons == 7 ) + fraExtra->setButton( 0 ); + else + fraExtra->setButton( buttons + 1 ); + } + } + } + slotWeekLabel(); + break; + case ORecur::MonthlyDay: + currInterval = Month; + setupMonthly(); + fraExtra->setButton( 0 ); + slotMonthLabel( 0 ); + break; + case ORecur::MonthlyDate: + currInterval = Month; + setupMonthly(); + fraExtra->setButton( 1 ); + slotMonthLabel( 1 ); + break; + case ORecur::Yearly: + currInterval = Year; + setupYearly(); + break; + } + fraType->setButton( currInterval ); + spinFreq->setValue( rp.frequency() ); + if ( !rp.hasEndDate() ) { + cmdEnd->setText( tr("No End Date") ); + chkNoEnd->setChecked( TRUE ); + } else + cmdEnd->setText( TimeString::shortDate( end ) ); +} + +/** + * the user selected recurrence rule. + * @return The recurrence rule. + */ +ORecur ORecurranceWidget::recurrence()const { + QListIterator<QToolButton> it( listRTypeButtons ); + QListIterator<QToolButton> itExtra( listExtra ); + ORecur rpTmp; + int i; + for ( i = 0; *it; ++it, i++ ) { + if ( (*it)->isOn() ) { + switch ( i ) { + case None: + rpTmp.setType( ORecur::NoRepeat ); + break; + case Day: + rpTmp.setType( ORecur::Daily ); + break; + case Week:{ + rpTmp.setType( ORecur::Weekly ); + int day; + int day2 = 0; + for ( day = 1; *itExtra; ++itExtra, day = day << 1 ) { + if ( (*itExtra)->isOn() ) { + if ( startWeekOnMonday ) + day2 |= day; + else { + if ( day == 1 ) + day2 |= Event::SUN; + else + day2 |= day >> 1; + } + } + } + rpTmp.setDays( day2 ); + } + break; + case Month: + if ( cmdExtra1->isOn() ) + rpTmp.setType( ORecur::MonthlyDay ); + else if ( cmdExtra2->isOn() ) + rpTmp.setType( ORecur::MonthlyDate ); + // figure out the montly day... + rpTmp.setPosition( week( start ) ); + break; + case Year: + rpTmp.setType( ORecur::Yearly ); + break; + } + break; // no need to keep looking! + } + } + rpTmp.setFrequency(spinFreq->value() ); + rpTmp.setHasEndDate( !chkNoEnd->isChecked() ); + if ( rpTmp.hasEndDate() ) { + rpTmp.setEndDate( end ); + } + // timestamp it... +// rpTmp.setCreateTime( ); current DateTime is already set -zecke + return rpTmp; +} + +/** + * Return the end date of the recurrence. This is only + * valid if the recurrence rule does contain an enddate + */ +QDate ORecurranceWidget::endDate()const { + return end; +} +void ORecurranceWidget::slotSetRType(int rtype) { + // now call the right function based on the type... + currInterval = static_cast<repeatButtons>(rtype); + switch ( currInterval ) { + case None: + setupNone(); + break; + case Day: + setupDaily(); + break; + case Week: + setupWeekly(); + slotWeekLabel(); + break; + case Month: + setupMonthly(); + cmdExtra2->setOn( TRUE ); + slotMonthLabel( 1 ); + break; + case Year: + setupYearly(); + break; + } +} +void ORecurranceWidget::endDateChanged(int y, int m, int d) { + end.setYMD( y, m, d ); + if ( end < start ) + end = start; + cmdEnd->setText( TimeString::shortDate( end ) ); + repeatPicker->setDate( end.year(), end.month(), end.day() ); +} +void ORecurranceWidget::slotNoEnd( bool unused) { + // if the item was toggled, then go ahead and set it to the maximum date + if ( unused ) { + end.setYMD( 3000, 12, 31 ); + cmdEnd->setText( tr("No End Date") ); + } else { + end = start; + cmdEnd->setText( TimeString::shortDate(end) ); + } +} +void ORecurranceWidget::setupRepeatLabel( const QString& s) { + lblVar1->setText( s ); +} +void ORecurranceWidget::setupRepeatLabel( int x) { + // change the spelling based on the value of x + QString strVar2; + + if ( x > 1 ) + lblVar1->show(); + else + lblVar1->hide(); + + switch ( currInterval ) { + case None: + break; + case Day: + if ( x > 1 ) + strVar2 = tr( "days" ); + else + strVar2 = tr( "day" ); + break; + case Week: + if ( x > 1 ) + strVar2 = tr( "weeks" ); + else + strVar2 = tr( "week" ); + break; + case Month: + if ( x > 1 ) + strVar2 = tr( "months" ); + else + strVar2 = tr( "month" ); + break; + case Year: + if ( x > 1 ) + strVar2 = tr( "years" ); + else + strVar2 = tr( "year" ); + break; + } + if ( !strVar2.isNull() ) + lblVar2->setText( strVar2 ); +} +void ORecurranceWidget::slotWeekLabel() { + QString str; + QListIterator<QToolButton> it( listExtra ); + unsigned int i; + unsigned int keepMe; + bool bNeedCarriage = FALSE; + // don't do something we'll regret!!! + if ( currInterval != Week ) + return; + + if ( startWeekOnMonday ) + keepMe = start.dayOfWeek() - 1; + else + keepMe = start.dayOfWeek() % 7; + + QStringList list; + for ( i = 0; *it; ++it, i++ ) { + // a crazy check, if you are repeating weekly, the current day + // must be selected!!! + if ( i == keepMe && !( (*it)->isOn() ) ) + (*it)->setOn( TRUE ); + if ( (*it)->isOn() ) { + if ( startWeekOnMonday ) + list.append( dayLabel[i] ); + else { + if ( i == 0 ) + list.append( dayLabel[6] ); + else + list.append( dayLabel[i - 1] ); + } + } + } + QStringList::Iterator itStr; + for ( i = 0, itStr = list.begin(); itStr != list.end(); ++itStr, i++ ) { + if ( i == 3 ) + bNeedCarriage = TRUE; + else + bNeedCarriage = FALSE; + if ( str.isNull() ) + str = *itStr; + else if ( i == list.count() - 1 ) { + if ( i < 2 ) + str += tr(" and ") + *itStr; + else { + if ( bNeedCarriage ) + str += tr( ",\nand " ) + *itStr; + else + str += tr( ", and " ) + *itStr; + } + } else { + if ( bNeedCarriage ) + str += ",\n" + *itStr; + else + str += ", " + *itStr; + } + } + str = str.prepend( tr("on ") ); + + lblWeekVar->setText( str ); +} +void ORecurranceWidget::slotMonthLabel(int type) { + QString str; + if ( currInterval != Month || type > 1 ) + return; + if ( type == 1 ) + str = strMonthDateTemplate.arg( numberPlacing(start.day()) ); + else + str = strMonthDayTemplate.arg( numberPlacing(week(start))) + .arg( dayLabel[start.dayOfWeek() - 1] ); + lblRepeat->setText( str ); +} +void ORecurranceWidget::slotChangeStartOfWeek( bool onMonday ) { + startWeekOnMonday = onMonday; + // we need to make this unintrusive as possible... + int saveSpin = spinFreq->value(); + char days = 0; + int day; + QListIterator<QToolButton> itExtra( listExtra ); + for ( day = 1; *itExtra; ++itExtra, day = day << 1 ) { + if ( (*itExtra)->isOn() ) { + if ( !startWeekOnMonday ) + days |= day; + else { + if ( day == 1 ) + days |= ORecur::SUN; + else + days |= day >> 1; + } + } + } + setupWeekly(); + spinFreq->setValue( saveSpin ); + int buttons; + for ( day = 0x01, buttons = 0; buttons < 7; + day = day << 1, buttons++ ) { + if ( days & day ) { + if ( startWeekOnMonday ) + fraExtra->setButton( buttons ); + else { + if ( buttons == 7 ) + fraExtra->setButton( 0 ); + else + fraExtra->setButton( buttons + 1 ); + } + } + } + slotWeekLabel(); +} +void ORecurranceWidget::setupNone() { + lblRepeat->setText( tr("No Repeat") ); + lblVar1->hide(); + lblVar2->hide(); + hideExtras(); + cmdEnd->hide(); + lblFreq->hide(); + lblEvery->hide(); + lblFreq->hide(); + spinFreq->hide(); + lblEnd->hide(); + lblWeekVar->hide(); +} +void ORecurranceWidget::setupDaily() { + hideExtras(); + lblWeekVar->hide(); + spinFreq->setValue( 1 ); + lblFreq->setText( tr("day(s)") ); + lblVar2->show(); + showRepeatStuff(); + lblRepeat->setText( strDayTemplate ); + setupRepeatLabel( 1 ); +} +void ORecurranceWidget::setupWeekly() { +// reshow the buttons... + fraExtra->setTitle( tr("Repeat On") ); + fraExtra->setExclusive( FALSE ); + fraExtra->show(); + if ( startWeekOnMonday ) { + cmdExtra1->setText( tr("Mon") ); + cmdExtra2->setText( tr("Tue") ); + cmdExtra3->setText( tr("Wed") ); + cmdExtra4->setText( tr("Thu") ); + cmdExtra5->setText( tr("Fri") ); + cmdExtra6->setText( tr("Sat") ); + cmdExtra7->setText( tr("Sun") ); + } else { + cmdExtra1->setText( tr("Sun") ); + cmdExtra2->setText( tr("Mon") ); + cmdExtra3->setText( tr("Tue") ); + cmdExtra4->setText( tr("Wed") ); + cmdExtra5->setText( tr("Thu") ); + cmdExtra6->setText( tr("Fri") ); + cmdExtra7->setText( tr("Sat") ); + } + // I hope clustering these improve performance.... + cmdExtra1->setOn( FALSE ); + cmdExtra2->setOn( FALSE ); + cmdExtra3->setOn( FALSE ); + cmdExtra4->setOn( FALSE ); + cmdExtra5->setOn( FALSE ); + cmdExtra6->setOn( FALSE ); + cmdExtra7->setOn( FALSE ); + + cmdExtra1->show(); + cmdExtra2->show(); + cmdExtra3->show(); + cmdExtra4->show(); + cmdExtra5->show(); + cmdExtra6->show(); + cmdExtra7->show(); + + lblWeekVar->show(); + spinFreq->setValue( 1 ); + // might as well set the day too... + if ( startWeekOnMonday ) { + fraExtra->setButton( start.dayOfWeek() - 1 ); + } else { + fraExtra->setButton( start.dayOfWeek() % 7 ); + } + lblFreq->setText( tr("week(s)") ); + lblVar2->show(); + showRepeatStuff(); + setupRepeatLabel( 1 ); +} +void ORecurranceWidget::setupMonthly() { + hideExtras(); + lblWeekVar->hide(); + fraExtra->setTitle( tr("Repeat By") ); + fraExtra->setExclusive( TRUE ); + fraExtra->show(); + cmdExtra1->setText( tr("Day") ); + cmdExtra1->show(); + cmdExtra2->setText( tr("Date") ); + cmdExtra2->show(); + spinFreq->setValue( 1 ); + lblFreq->setText( tr("month(s)") ); + lblVar2->show(); + showRepeatStuff(); + setupRepeatLabel( 1 ); +} +void ORecurranceWidget::setupYearly() { +hideExtras(); + lblWeekVar->hide(); + spinFreq->setValue( 1 ); + lblFreq->setText( tr("year(s)") ); + lblFreq->show(); + lblFreq->show(); + showRepeatStuff(); + lblVar2->show(); + QString strEvery = strYearTemplate.arg( start.monthName(start.month()) ).arg( numberPlacing(start.day()) ); + lblRepeat->setText( strEvery ); + setupRepeatLabel( 1 ); + +} +void ORecurranceWidget::init() { + QPopupMenu *m1 = new QPopupMenu( this ); + repeatPicker = new DateBookMonth( m1, 0, TRUE ); + m1->insertItem( repeatPicker ); + cmdEnd->setPopup( m1 ); + cmdEnd->setPopupDelay( 0 ); + + QObject::connect( repeatPicker, SIGNAL(dateClicked(int,int,int)), + this, SLOT(endDateChanged(int,int,int)) ); + QObject::connect( qApp, SIGNAL(weekChanged(bool)), + this, SLOT(slotChangeStartOfWeek(bool)) ); + + listRTypeButtons.setAutoDelete( TRUE ); + listRTypeButtons.append( cmdNone ); + listRTypeButtons.append( cmdDay ); + listRTypeButtons.append( cmdWeek ); + listRTypeButtons.append( cmdMonth ); + listRTypeButtons.append( cmdYear ); + + listExtra.setAutoDelete( TRUE ); + listExtra.append( cmdExtra1 ); + listExtra.append( cmdExtra2 ); + listExtra.append( cmdExtra3 ); + listExtra.append( cmdExtra4 ); + listExtra.append( cmdExtra5 ); + listExtra.append( cmdExtra6 ); + listExtra.append( cmdExtra7 ); +} +void ORecurranceWidget::hideExtras() { + // hide the extra buttons... + fraExtra->hide(); + chkNoEnd->hide(); + QListIterator<QToolButton> it( listExtra ); + for ( ; *it; ++it ) { + (*it)->hide(); + (*it)->setOn( FALSE ); + } +} +void ORecurranceWidget::showRepeatStuff() { + cmdEnd->show(); + chkNoEnd->show(); + lblFreq->show(); + lblEvery->show(); + lblFreq->show(); + spinFreq->show(); + lblEnd->show(); + lblRepeat->setText( tr("Every") ); +} + + +static int week( const QDate &start ) +{ + // figure out the week... + int stop = start.day(), + sentinel = start.dayOfWeek(), + dayOfWeek = QDate( start.year(), start.month(), 1 ).dayOfWeek(), + week = 1, + i; + for ( i = 1; i < stop; i++ ) { + if ( dayOfWeek++ == sentinel ) + week++; + if ( dayOfWeek > 7 ) + dayOfWeek = 0; + } + return week; +} + +static QString numberPlacing( int x ) +{ + // I hope this works in other languages besides english... + QString str = QString::number( x ); + switch ( x % 10 ) { + case 1: + str += QWidget::tr( "st" ); + break; + case 2: + str += QWidget::tr( "nd" ); + break; + case 3: + str += QWidget::tr( "rd" ); + break; + default: + str += QWidget::tr( "th" ); + break; + } + return str; +} diff --git a/noncore/unsupported/libopie/orecurrancewidget.h b/noncore/unsupported/libopie/orecurrancewidget.h new file mode 100644 index 0000000..37a57f0 --- a/dev/null +++ b/noncore/unsupported/libopie/orecurrancewidget.h @@ -0,0 +1,93 @@ +/* + * GPL and based on the widget from TT + */ + +#ifndef OPIE_RECURRANCE_WIDGET_H +#define OPIE_RECURRANCE_WIDGET_H + +#include <qlist.h> +#include <qtoolbutton.h> +#include <qcheckbox.h> +#include <qdatetime.h> +#include <qbuttongroup.h> + +#include <qpe/datebookmonth.h> + +#include "orecurrancebase.h" +#include <opie/orecur.h> + +// FIXME spelling!!!! -zecke +// FIXME spelling filenames + +/** + * A widget to let the user select rules for recurrences. + * This widget can take care of weekly, monthly, daily and yearly recurrence + * It is used inside todolist and datebook. + * + * + * @short Widget of selecting Recurrance + * @author Trolltech, Holger Freyther + * @version 0.9 + */ +class ORecurranceWidget : public ORecurranceBase { + Q_OBJECT +public: + ORecurranceWidget( bool startOnMonday, + const QDate& start, QWidget* parent = 0, + const char* name = 0, bool modal = TRUE, + WFlags fl = 0 ); + ORecurranceWidget( bool startOnMonday, + const ORecur& rp, const QDate& start, + QWidget* parent = 0, const char* name =0, + bool modal = TRUE, WFlags = 0 ); + ~ORecurranceWidget(); + ORecur recurrence()const; + QDate endDate()const; + +public slots: + void slotSetRType( int ); + /** + * set the new end date + */ + void endDateChanged( int, int, int ); + /** + * enable/disable end date + */ + void slotNoEnd( bool unused ); + void setStartDate( const QDate& ); + void setRecurrence( const ORecur& recur, const QDate& start ); + void setRecurrence( const ORecur& recur ); + +private slots: + void setupRepeatLabel( const QString& ); + void setupRepeatLabel( int ); + void slotWeekLabel(); + void slotMonthLabel( int ); + void slotChangeStartOfWeek( bool onMonday ); + +private: + void setupNone(); + void setupDaily(); + void setupWeekly(); + void setupMonthly(); + void setupYearly(); + + enum repeatButtons { None, Day, Week, Month, Year }; + void init(); + void hideExtras(); + void showRepeatStuff(); + + QList<QToolButton> listRTypeButtons; + QList<QToolButton> listExtra; + QDate start; // only used in one spot... + QDate end; + repeatButtons currInterval; + bool startWeekOnMonday : 1; + DateBookMonth *repeatPicker; + + class Private; + Private *d; + +}; + +#endif diff --git a/noncore/unsupported/libopie/otabbar.cpp b/noncore/unsupported/libopie/otabbar.cpp new file mode 100644 index 0000000..52621ca --- a/dev/null +++ b/noncore/unsupported/libopie/otabbar.cpp @@ -0,0 +1,81 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "otabbar.h" + +OTabBar::OTabBar( QWidget *parent , const char *name ) + : QTabBar( parent, name ) +{ +} + +void OTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const +{ + + QRect r = br; + if ( t->iconset) + { + QIconSet::Mode mode = (t->enabled && isEnabled()) ? QIconSet::Normal : QIconSet::Disabled; + if ( mode == QIconSet::Normal && has_focus ) { + mode = QIconSet::Active; + } + QPixmap pixmap = t->iconset->pixmap( QIconSet::Small, mode ); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + r.setLeft( r.left() + pixw + 2 ); + p->drawPixmap( br.left()+2, br.center().y()-pixh/2, pixmap ); + } + + QRect tr = r; + if ( t->id == currentTab() ) + { + tr.setBottom( tr.bottom() - style().defaultFrameWidth() ); + } + + if ( t->enabled && isEnabled() ) + { + p->setPen( colorGroup().foreground() ); + p->drawText( tr, AlignCenter | ShowPrefix, t->label ); + } + else if ( style() == MotifStyle ) + { + p->setPen( palette().disabled().foreground() ); + p->drawText( tr, AlignCenter | ShowPrefix, t->label ); + } + else + { + p->setPen( colorGroup().light() ); + QRect wr = tr; + wr.moveBy( 1, 1 ); + p->drawText( wr, AlignCenter | ShowPrefix, t->label ); + p->setPen( palette().disabled().foreground() ); + p->drawText( tr, AlignCenter | ShowPrefix, t->label ); + } +} diff --git a/noncore/unsupported/libopie/otabbar.h b/noncore/unsupported/libopie/otabbar.h new file mode 100644 index 0000000..668187b --- a/dev/null +++ b/noncore/unsupported/libopie/otabbar.h @@ -0,0 +1,80 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OTABBAR_H +#define OTABBAR_H + +#include <qtabbar.h> + +/** + * @class OTabBar + * @brief The OTabBar class is a derivative of QTabBar. + * + * OTabBar is a derivation of TrollTech's QTabBar which provides + * a row of tabs for selection. The only difference between this + * class and QTabBar is that there is no dotted line box around + * the label of the tab with the current focus. + */ +class OTabBar : public QTabBar +{ + Q_OBJECT + +public: +/** + * @fn OTabBar( QWidget *parent = 0, const char *name = 0 ) + * @brief Object constructor. + * + * @param parent Pointer to parent of this control. + * @param name Name of control. + * + * Constructs a new OTabBar control with parent and name. + */ + // FIXME Allow WFlags? -zecke + OTabBar( QWidget * = 0, const char * = 0 ); + +protected: +/** + * @fn paintLabel( QPainter* p, const QRect& br , QTab* t, bool has_focus)const + * @brief Internal function to draw a tab's label. + * + * @param p Pointer to QPainter used for drawing. + * @param br QRect providing region to draw label in. + * @param t Tab to draw label for. + * @param has_focus Boolean value not used, retained for compatibility reasons. + */ + void paintLabel( QPainter *, const QRect &, QTab *, bool ) const; + +private: + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/otabinfo.h b/noncore/unsupported/libopie/otabinfo.h new file mode 100644 index 0000000..00bb06d --- a/dev/null +++ b/noncore/unsupported/libopie/otabinfo.h @@ -0,0 +1,134 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OTABINFO_H +#define OTABINFO_H + +#include <qlist.h> +#include <qstring.h> + +class QWidget; + +/** + * @class OTabInfo + * @brief The OTabInfo class is used internally by OTabWidget to keep track + * of widgets added to the control. + * + * OTabInfo provides the following information about a widget added to an + * OTabWidget control: + * + * ID - integer tab bar ID + * Control - QWidget pointer to child widget + * Label - QString text label for OTabWidget selection control + * Icon - QString name of icon file + */ +class OTabInfo +{ +public: +/** + * @fn OTabInfo() + * @brief Object constructor. + * + * @param parent Pointer to parent of this control. + * @param name Name of control. + * @param s Style of widget selection control. + * @param p Position of the widget selection control. + */ + OTabInfo() : i( -1 ), c( 0 ), p( 0 ), l( QString::null ) {} + +/** + * @fn OTabInfo( int id, QWidget *control, const QString &icon, const QString &label ) + * @brief Object constructor. + * + * @param id TabBar identifier for widget. + * @param control QWidget pointer to widget. + * @param icon QString name of icon file. + * @param label QString text label for OTabWidget selection control. + */ + OTabInfo( int id, QWidget *control, const QString &icon, const QString &label ) + : i( id ), c( control ), p( icon ), l( label ) {} + +/** + * @fn id()const + * @brief Returns TabBar ID. + */ + int id() const { return i; } + +/** + * @fn label()const + * @brief Returns text label for widget. + */ + const QString &label() const { return l; } + +/** + * @fn setLabel( const QString &label ) + * @brief Set label for tab. + * + * @param label QString text label for OTabWidget selection control. + */ + void setLabel( const QString &label ) { l = label; } + +/** + * @fn control()const + * @brief Returns pointer to widget. + */ + QWidget *control() const { return c; } + +/** + * @fn icon()const + * @brief Returns name of icon file. + */ + const QString &icon() const { return p; } + +/** + * @fn setIcon( const QString &icon ) + * @brief Set icon for tab. + * + * @param icon QString name of icon file. + */ + void setIcon( const QString &icon ) { p = icon; } + +private: + int i; + QWidget *c; + QString p; + QString l; + class Private; + Private *d; +}; + +/** + * @class OTabInfoList + * @brief A list of OTabInfo objects used by OTabWidget. + */ +typedef QList<OTabInfo> OTabInfoList; + +#endif diff --git a/noncore/unsupported/libopie/otabwidget.cpp b/noncore/unsupported/libopie/otabwidget.cpp new file mode 100644 index 0000000..52190b2 --- a/dev/null +++ b/noncore/unsupported/libopie/otabwidget.cpp @@ -0,0 +1,419 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "otabwidget.h" + +#include <qpe/applnk.h> +#include <qpe/config.h> +#include <qpe/resource.h> +#include <opie/otabbar.h> + +#include <qcombobox.h> +#include <qwidgetstack.h> + +OTabWidget::OTabWidget( QWidget *parent, const char *name, TabStyle s, TabPosition p ) + : QWidget( parent, name ) +{ + if ( s == Global ) + { + Config config( "qpe" ); + config.setGroup( "Appearance" ); + s = ( TabStyle ) config.readNumEntry( "TabStyle", (int) IconTab ); + if ( s <= Global || s > IconList) + { + s = IconTab; + } + QString pos = config.readEntry( "TabPosition", "Top"); + if ( pos == "Bottom" ) + { + p = Bottom; + } + else + { + p = Top; + } + } + + widgetStack = new QWidgetStack( this, "widgetstack" ); + widgetStack->setFrameStyle( QFrame::NoFrame ); + widgetStack->setLineWidth( style().defaultFrameWidth() ); + + tabBarStack = new QWidgetStack( this, "tabbarstack" ); + + tabBar = new OTabBar( tabBarStack, "tabbar" ); + tabBarStack->addWidget( tabBar, 0 ); + connect( tabBar, SIGNAL( selected(int) ), this, SLOT( slotTabBarSelected(int) ) ); + + tabList = new QComboBox( false, tabBarStack, "tablist" ); + tabBarStack->addWidget( tabList, 1 ); + connect( tabList, SIGNAL( activated(int) ), this, SLOT( slotTabListSelected(int) ) ); + + tabBarPosition = p; + setTabStyle( s ); + setTabPosition( p ); + + currTab= 0x0; +} + +OTabWidget::~OTabWidget() +{ +} + +void OTabWidget::addTab( QWidget *child, const QString &icon, const QString &label ) +{ + QPixmap iconset = loadSmooth( icon ); + + QTab *tab = new QTab(); + if ( tabBarStyle == IconTab ) + { + tab->label = QString::null; + } + else + { + tab->label = label; + } + if ( tabBarStyle == IconTab || tabBarStyle == IconList ) + { + tab->iconset = new QIconSet( iconset ); + } + int tabid = tabBar->addTab( tab ); + + if ( tabBarStyle == IconTab || tabBarStyle == IconList ) + { + tabList->insertItem( iconset, label, -1 ); + } + else + { + tabList->insertItem( label ); + } + + widgetStack->addWidget( child, tabid ); + widgetStack->raiseWidget( child ); + widgetStack->setFrameStyle( QFrame::StyledPanel | QFrame::Raised ); + + OTabInfo *tabinfo = new OTabInfo( tabid, child, icon, label ); + tabs.append( tabinfo ); + selectTab( tabinfo ); +} + +void OTabWidget::removePage( QWidget *childwidget ) +{ + if ( childwidget ) + { + OTabInfo *tab = tabs.first(); + while ( tab && tab->control() != childwidget ) + { + tab = tabs.next(); + } + if ( tab && tab->control() == childwidget ) + { + tabBar->setTabEnabled( tab->id(), FALSE ); + tabBar->removeTab( tabBar->tab( tab->id() ) ); + int i = 0; + while ( i < tabList->count() && tabList->text( i ) != tab->label() ) + { + i++; + } + if ( tabList->text( i ) == tab->label() ) + { + tabList->removeItem( i ); + } + widgetStack->removeWidget( childwidget ); + tabs.remove( tab ); + delete tab; + currTab = tabs.current(); + if ( !currTab ) + { + widgetStack->setFrameStyle( QFrame::NoFrame ); + } + + setUpLayout(); + } + } +} + +void OTabWidget::changeTab( QWidget *widget, const QString &iconset, const QString &label) +{ + OTabInfo *currtab = tabs.first(); + while ( currtab && currtab->control() != widget ) + { + currtab = tabs.next(); + } + if ( currtab && currtab->control() == widget ) + { + QTab *tab = tabBar->tab( currtab->id() ); + QPixmap icon( loadSmooth( iconset ) ); + tab->setText( label ); + if ( tabBarStyle == IconTab ) + tab->setIconSet( icon ); + int i = 0; + while ( i < tabList->count() && tabList->text( i ) != currtab->label() ) + { + i++; + } + if ( i < tabList->count() && tabList->text( i ) == currtab->label() ) + { + if ( tabBarStyle == IconTab || tabBarStyle == IconList ) + { + tabList->changeItem( icon, label, i ); + } + else + { + tabList->changeItem( label, i ); + } + } + currtab->setLabel( label ); + currtab->setIcon( iconset ); + } + setUpLayout(); +} + +void OTabWidget::setCurrentTab( QWidget *childwidget ) +{ + OTabInfo *currtab = tabs.first(); + while ( currtab && currtab->control() != childwidget ) + { + currtab = tabs.next(); + } + if ( currtab && currtab->control() == childwidget ) + { + selectTab( currtab ); + } +} + +void OTabWidget::setCurrentTab( const QString &tabname ) +{ + OTabInfo *newtab = tabs.first(); + while ( newtab && newtab->label() != tabname ) + { + newtab = tabs.next(); + } + if ( newtab && newtab->label() == tabname ) + { + selectTab( newtab ); + } +} + +void OTabWidget::setCurrentTab(int tabindex) { + OTabInfo *newtab = tabs.first(); + while ( newtab && newtab->id() != tabindex ) + { + newtab = tabs.next(); + } + if ( newtab && newtab->id() == tabindex ) + { + selectTab( newtab ); + } +} + + +OTabWidget::TabStyle OTabWidget::tabStyle() const +{ + return tabBarStyle; +} + +void OTabWidget::setTabStyle( TabStyle s ) +{ + tabBarStyle = s; + if ( tabBarStyle == TextTab || tabBarStyle == IconTab ) + { + QTab *currtab; + for ( OTabInfo *tabinfo = tabs.first(); tabinfo; tabinfo = tabs.next() ) + { + currtab = tabBar->tab( tabinfo->id() ); + if ( tabBarStyle == IconTab ) + { + currtab->iconset = new QIconSet( loadSmooth( tabinfo->icon() ) ); + if ( tabinfo == currTab ) + currtab->setText( tabinfo->label() ); + else + currtab->setText( QString::null ); + } + else + { + currtab->iconset = 0x0; + currtab->setText( tabinfo->label() ); + } + } + tabBarStack->raiseWidget( tabBar ); + } + else if ( tabBarStyle == TextList || tabBarStyle == IconList ) + { + tabList->clear(); + for ( OTabInfo *tabinfo = tabs.first(); tabinfo; tabinfo = tabs.next() ) + { + if ( tabBarStyle == IconList ) + { + tabList->insertItem( loadSmooth( tabinfo->icon() ), tabinfo->label() ); + } + else + { + tabList->insertItem( tabinfo->label() ); + } + } + tabBarStack->raiseWidget( tabList ); + } + setUpLayout(); +} + +OTabWidget::TabPosition OTabWidget::tabPosition() const +{ + return tabBarPosition; +} + +void OTabWidget::setTabPosition( TabPosition p ) +{ + tabBarPosition = p; + if ( tabBarPosition == Top ) + { + tabBar->setShape( QTabBar::RoundedAbove ); + } + else + { + tabBar->setShape( QTabBar::RoundedBelow ); + } + setUpLayout(); +} + +void OTabWidget::slotTabBarSelected( int id ) +{ + OTabInfo *newtab = tabs.first(); + while ( newtab && newtab->id() != id ) + { + newtab = tabs.next(); + } + if ( newtab && newtab->id() == id ) + { + selectTab( newtab ); + } +} + +void OTabWidget::slotTabListSelected( int index ) +{ + OTabInfo *newtab = tabs.at( index ); + if ( newtab ) + { + selectTab( newtab ); + } +} + +QPixmap OTabWidget::loadSmooth( const QString &name ) +{ + QPixmap p; + p.convertFromImage( Resource::loadImage( name ).smoothScale( AppLnk::smallIconSize(), AppLnk::smallIconSize() ) ); + return p; +} + +void OTabWidget::selectTab( OTabInfo *tab ) +{ + if ( tabBarStyle == IconTab ) + { + if ( currTab ) + { + tabBar->tab( currTab->id() )->setText( QString::null ); + setUpLayout(); + } + tabBar->tab( tab->id() )->setText( tab->label() ); + tabBar->setCurrentTab( tab->id() ); + setUpLayout(); + tabBar->update(); + } + else + { + tabBar->setCurrentTab( tab->id() ); + } + + widgetStack->raiseWidget( tab->control() ); + + emit currentChanged( tab->control() ); + + currTab = tab; +} + +void OTabWidget::setUpLayout() +{ + tabBar->layoutTabs(); + QSize t( tabBarStack->sizeHint() ); + if ( tabBarStyle == IconTab ) + { + if ( t.width() > width() ) + t.setWidth( width() ); + } + else + { + t.setWidth( width() ); + } + int lw = widgetStack->lineWidth(); + if ( tabBarPosition == Bottom ) + { + tabBarStack->setGeometry( QMAX(0, lw-2), height() - t.height() - lw, t.width(), t.height() ); + widgetStack->setGeometry( 0, 0, width(), height()-t.height()+QMAX(0, lw-2) ); + } + else + { + tabBarStack->setGeometry( QMAX(0, lw-2), 0, t.width(), t.height() ); + widgetStack->setGeometry( 0, t.height()-lw, width(), height()-t.height()+QMAX( 0, lw-2 ) ); + } + + if ( autoMask() ) + updateMask(); +} + +QSize OTabWidget::sizeHint() const +{ + QSize s( widgetStack->sizeHint() ); + QSize t( tabBarStack->sizeHint() ); + return QSize( QMAX( s.width(), t.width() ), s.height() + t.height() ); +} + +void OTabWidget::resizeEvent( QResizeEvent * ) +{ + setUpLayout(); +} + +int OTabWidget::currentTab() +{ + if ( currTab ) + { + return currTab->id(); + } + return -1; +} + +QWidget* OTabWidget::currentWidget()const +{ + if ( currTab ) + { + return currTab->control(); + } + + return 0; +} diff --git a/noncore/unsupported/libopie/otabwidget.h b/noncore/unsupported/libopie/otabwidget.h new file mode 100644 index 0000000..047eaa1 --- a/dev/null +++ b/noncore/unsupported/libopie/otabwidget.h @@ -0,0 +1,285 @@ +/* + This file is part of the Opie Project + + Copyright (c) 2002 Dan Williams <williamsdr@acm.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OTABWIDGET_H +#define OTABWIDGET_H + +#include "otabinfo.h" + +#include <qwidget.h> +#include <qlist.h> + +class OTabBar; +class QComboBox; +class QPixmap; +class QTabBar; +class QWidgetStack; + +/** + * @class OTabWidget + * @brief The OTabWidget class provides a stack of widgets. + * + * OTabWidget is a derivation of TrollTech's QTabWidget which provides + * a stack of widgets. Widgets can be selected using either a tab bar or + * drop down list box. + * + * The normal way to use OTabWidget is to do the following in the + * constructor: + * - Create a OTabWidget. + * - Create a QWidget for each of the pages in the control, insert + * children into it, set up geometry management for it, and use addTab() + * to add the widget. + */ +class OTabWidget : public QWidget +{ + Q_OBJECT +public: + +/** + * @enum TabStyle + * @brief Defines how the widget selection control is displayed. + * + * Valid values: + * - Global: use globally selected options (qpe.conf - TabStyle & TabPosition) + * - TextTab: Tabbed widget selection with text labels + * - IconTab: Tabbed widget selection with icon labels, text label for active widget + * (similar to Opie launcher) + * - TextList: Drop down list widget selection with text labels + * - IconList: Drop down list widget selection with icon & text labels + */ + enum TabStyle { Global, TextTab, IconTab, TextList, IconList }; + +/** + * @enum TabPosition + * @brief Defines where the widget selection control is drawn. + * + * Valid values: + * - Top: Widget selection control is drawn above widgets + * - Bottom: Widget selection control is drawn below widgets + */ + enum TabPosition { Top, Bottom }; + +/** + * @fn OTabWidget( QWidget *parent = 0, const char *name = 0, TabStyle s = Global, TabPosition p = Top ) + * @brief Object constructor. + * + * @param parent Pointer to parent of this control. + * @param name Name of control. + * @param s Style of widget selection control. + * @param p Position of the widget selection control. + * + * Constructs a new OTabWidget control with parent and name. The style and position parameters + * determine how the widget selection control will be displayed. + */ + // FIXME WFlags? -zecke + OTabWidget( QWidget * = 0, const char * = 0, TabStyle = Global, TabPosition = Top ); + +/** + * @fn ~OTabWidget() + * @brief Object destructor. + */ + ~OTabWidget(); + +/** + * @fn addTab( QWidget *child, const QString &icon, const QString &label ) + * @brief Add new widget to control. + * + * @param child Widget control. + * @param icon Path to icon. + * @param label Text label. + */ + void addTab( QWidget *, const QString &, const QString & ); + +/** + * @fn removePage( QWidget *widget ) + * @brief Remove widget from control. Does not delete widget. + * + * @param widget Widget control to be removed. + */ + /* ### Page vs. Tab.. yes the widget is a Page but then is addTab wrong -zecke */ + void removePage( QWidget * ); + +/** + * @fn changeTab( QWidget *widget, const QString &icon, const QString &label ) + * @brief Change text and/or icon for existing tab + * + * @param child Widget control. + * @param icon Path to icon. + * @param label Text label. + */ + void changeTab( QWidget *, const QString &, const QString & ); + +/** + * @fn tabStyle()const + * @brief Returns current widget selection control style. + */ + TabStyle tabStyle() const; + +/** + * @fn setTabStyle( TabStyle s ) + * @brief Set the current widget selection control style. + * + * @param s New style to be used. + */ + void setTabStyle( TabStyle ); + +/** + * @fn tabPosition()const + * @brief Returns current widget selection control position. + */ + TabPosition tabPosition() const; + +/** + * @fn setTabPosition( TabPosition p ) + * @brief Set the current widget selection control position. + * + * @param p New position of widget selection control. + */ + void setTabPosition( TabPosition ); + +/** + * @fn setCurrentTab( QWidget *childwidget ) + * @brief Selects and brings to top the desired widget by using widget pointer. + * + * @param childwidget Widget to select. + */ + void setCurrentTab( QWidget * ); + +/** + * @fn setCurrentTab( const QString &tabname ) + * @brief Selects and brings to top the desired widget, by using label. + * + * @param tabname Text label for widget to select. + */ + void setCurrentTab( const QString & ); + +/** + * @fn setCurrentTab( int ) + * @brief Selects and brings to top the desired widget, by using id. + * + * @param tab id for widget to select. + */ + void setCurrentTab(int); + +/** + * @fn sizeHint()const + * @brief Reimplemented for internal purposes. + */ + QSize sizeHint() const; + +/** + * @fn currentTab( ) + * @brief returns current tab id. + */ + // ### make const + int currentTab()/* const */; +/** + * @brief returns the current page of the active tab + * + * @since 1.2 + */ + QWidget* currentWidget()const; + +protected: + +/** + * @fn resizeEvent( QResizeEvent * ) + * @brief Reimplemented for internal purposes. + */ + void resizeEvent( QResizeEvent * ); + +private: + OTabInfoList tabs; + OTabInfo *currTab; + + TabStyle tabBarStyle; + TabPosition tabBarPosition; + + QWidgetStack *tabBarStack; + OTabBar *tabBar; + QComboBox *tabList; + + QWidgetStack *widgetStack; + class Private; + Private* d; + +/** + * @fn loadSmooth( const QString &name ) + * @brief Loads icon for widget. + * + * @param name Name of icon image file. + */ + QPixmap loadSmooth( const QString & ); + +/** + * @fn selectTab( OTabInfo *tab ) + * @brief Internal function to select desired widget. + * + * @param tab Pointer to data for widget. + */ + void selectTab( OTabInfo * ); + +/** + * @fn setUpLayout() + * @brief Internal function to adjust layout. + */ + void setUpLayout(); + + +signals: +/** + * @fn currentChanged( QWidget *widget ) + * @brief This signal is emitted whenever the widget has changed. + * + * @param widget Pointer to new current widget. + */ + void currentChanged( QWidget * ); + +private slots: + +/** + * @fn slotTabBarSelected( int id ) + * @brief Slot which is called when a tab is selected. + * + * @param id ID of widget selected. + */ + void slotTabBarSelected( int ); + +/** + * @fn slotTabListSelected( int index ) + * @brief Slot which is called when a drop down selection is made. + * + * @param id Index of widget selected. + */ + void slotTabListSelected( int ); +}; + +#endif diff --git a/noncore/unsupported/libopie/oticker.cpp b/noncore/unsupported/libopie/oticker.cpp new file mode 100644 index 0000000..b41cab6 --- a/dev/null +++ b/noncore/unsupported/libopie/oticker.cpp @@ -0,0 +1,132 @@ +/* + This file is part of the Opie Project + Copyright (c) 2002 L. Potter <ljp@llornkcor.com> + Copyright (C) 2000-2002 Trolltech AS. All rights reserved. + + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = General Public License along with + -- :-=` this; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <qpe/config.h> + +#include <stdlib.h> +#include <stdio.h> + +#include "oticker.h" + +OTicker::OTicker( QWidget* parent ) + : QLabel( parent ) { + // : QFrame( parent ) { + setTextFormat(Qt::RichText); + Config cfg("qpe"); + cfg.setGroup("Appearance"); + backgroundcolor = QColor( cfg.readEntry( "Background", "#E5E1D5" ) ); + foregroundcolor= Qt::black; + updateTimerTime = 50; + scrollLength = 1; +} + +OTicker::~OTicker() { +} + +void OTicker::setBackgroundColor(const QColor& backcolor) { + backgroundcolor = backcolor; + update(); +} + +void OTicker::setForegroundColor(const QColor& backcolor) { + foregroundcolor = backcolor; + update(); +} + +void OTicker::setFrame(int frameStyle) { + setFrameStyle( frameStyle/*WinPanel | Sunken */); + update(); +} + +void OTicker::setText( const QString& text ) { + pos = 0; // reset it everytime the text is changed + scrollText = text; +qDebug(scrollText); + + int pixelLen = 0; + bool bigger = false; + int contWidth = contentsRect().width(); + int contHeight = contentsRect().height(); + int pixelTextLen = fontMetrics().width( text ); + printf("<<<<<<<height %d, width %d, text width %d %d\n", contHeight, contWidth, pixelTextLen, scrollText.length()); + if( pixelTextLen < contWidth) + { + pixelLen = contWidth; + } + else + { + bigger = true; + pixelLen = pixelTextLen; + } + QPixmap pm( pixelLen, contHeight); +// pm.fill( QColor( 167, 212, 167 )); + + pm.fill(backgroundcolor); + QPainter pmp( &pm ); + pmp.setPen(foregroundcolor ); + pmp.drawText( 0, 0, pixelTextLen, contHeight, AlignVCenter, scrollText ); + pmp.end(); + scrollTextPixmap = pm; + + killTimers(); + // qDebug("Scrollupdate %d", updateTimerTime); + if ( bigger /*pixelTextLen > contWidth*/ ) + startTimer( updateTimerTime); + update(); +} + + +void OTicker::timerEvent( QTimerEvent * ) { + pos = ( pos <= 0 ) ? scrollTextPixmap.width() : pos - scrollLength;//1; + repaint( FALSE ); +} + +void OTicker::drawContents( QPainter *p ) { + int pixelLen = scrollTextPixmap.width(); + p->drawPixmap( pos, contentsRect().y(), scrollTextPixmap ); + if ( pixelLen > contentsRect().width() ) // Scrolling + p->drawPixmap( pos - pixelLen, contentsRect().y(), scrollTextPixmap ); +} + +void OTicker::mouseReleaseEvent( QMouseEvent * ) { +// qDebug("<<<<<<<>>>>>>>>>"); + emit mousePressed(); +} + +void OTicker::setUpdateTime(int time) { + updateTimerTime=time; +} + +void OTicker::setScrollLength(int len) { +scrollLength=len; +} + diff --git a/noncore/unsupported/libopie/oticker.h b/noncore/unsupported/libopie/oticker.h new file mode 100644 index 0000000..45bf7ce --- a/dev/null +++ b/noncore/unsupported/libopie/oticker.h @@ -0,0 +1,148 @@ +/* + This file is part of the Opie Project + Copyright (c) 2002 L. Potter <ljp@llornkcor.com> + Copyright (C) 2000-2002 Trolltech AS. All rights reserved. + + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = General Public License along with + -- :-=` this; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OTICKER_H +#define OTICKER_H + +#include <qwidget.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qpixmap.h> +#include <qstring.h> +#include <qslider.h> +#include <qlabel.h> +#include <qframe.h> +#include <qcolor.h> + +/** + * @class OTicker + * @brief The OTicker class provides a QLabel widget that scroll its contents + * + */ +class OTicker : public QLabel { + Q_OBJECT + +public: + +/*! + * @fn OTicker( QWidget* parent = 0 ) + * @brief Object constructor. + * + * @param parent Pointer to parent of this control. + + * Constructs a new OTicker control with parent + */ + OTicker( QWidget* parent=0 ); +/*! + * @fn ~OTicker() + * @brief Object destructor. + */ + ~OTicker(); +/*! + * @fn setText(const QString& ) + * @brief sets text to be displayed + * @param text QString text to be displayed. + * + */ + void setText( const QString& text ) ; +/*! + * @fn setBackgroundColor(const QColor& color) + * @brief sets color of the ticker's background + * @param color QColor color to be set. + * + */ + void setBackgroundColor(const QColor& color); +/*! + * @fn setForegroundColor(const QColor& color) + * @brief sets color of text + * @param color QColor color of text + * + */ + void setForegroundColor(const QColor& color); +/*! + * @fn setFrame(int style) + * @brief sets frame style + * @param style int Frame style to be see. See Qt::WidgetFlags. + * + */ + void setFrame(int style); +/*! + * @fn setUpdateTime(int timeout) + * @brief sets time of update + * @param timeout int time in milliseconds between updates. + * + */ + void setUpdateTime(int timeout); +/*! + * @fn setScrollLength(int length) + * @brief sets amount of scrolling default is 1 + * @param length int scroll length. + * + */ + void setScrollLength(int length); +signals: +/*! + * @fn mousePressed() + * @brief signal mouse press event + * + */ + void mousePressed(); +protected: +/*! + * @fn timerEvent( QTimerEvent * e) + * @brief timer timeout event + * @param e QEvent see QEvent. + * + */ + void timerEvent( QTimerEvent * e); +/*! + * @fn drawContents( QPainter *p ) + * @brief draws widget contents + * @param p QPainter. see QPainter + * + */ + void drawContents( QPainter *p ); +/*! + * @fn mouseReleaseEvent( QMouseEvent *e) + * @brief mouse release event + * @param e QMouseEvent. see QMouseEvent. + * + */ + void mouseReleaseEvent( QMouseEvent *e); +private: + QColor backgroundcolor, foregroundcolor; + QString scrollText; + QPixmap scrollTextPixmap; + int pos, updateTimerTime, scrollLength; +}; + +#endif diff --git a/noncore/unsupported/libopie/otimepicker.cpp b/noncore/unsupported/libopie/otimepicker.cpp new file mode 100644 index 0000000..11b80ed --- a/dev/null +++ b/noncore/unsupported/libopie/otimepicker.cpp @@ -0,0 +1,242 @@ +#include "otimepicker.h" + +#include <qlayout.h> +#include <stdio.h> +#include <qlineedit.h> + + +/** + * Constructs the widget + * @param parent The parent of the OTimePicker + * @param name The name of the object + * @param fl Window Flags + */ +OTimePicker::OTimePicker(QWidget* parent, const char* name, + WFlags fl) : + QWidget(parent,name,fl) +{ + + QVBoxLayout *vbox=new QVBoxLayout(this); + + OClickableLabel *r; + QString s; + + // Hour Row + QWidget *row=new QWidget(this); + QHBoxLayout *l=new QHBoxLayout(row); + vbox->addWidget(row); + + + for (int i=0; i<24; i++) { + r=new OClickableLabel(row); + hourLst.append(r); + s.sprintf("%.2d",i); + r->setText(s); + r->setToggleButton(true); + r->setAlignment(AlignHCenter | AlignVCenter); + l->addWidget(r); + connect(r, SIGNAL(toggled(bool)), + this, SLOT(slotHour(bool))); + + if (i==11) { // Second row + row=new QWidget(this); + l=new QHBoxLayout(row); + vbox->addWidget(row); + } + } + + // Minute Row + row=new QWidget(this); + l=new QHBoxLayout(row); + vbox->addWidget(row); + + for (int i=0; i<60; i+=5) { + r=new OClickableLabel(row); + minuteLst.append(r); + s.sprintf("%.2d",i); + r->setText(s); + r->setToggleButton(true); + r->setAlignment(AlignHCenter | AlignVCenter); + l->addWidget(r); + connect(r, SIGNAL(toggled(bool)), + this, SLOT(slotMinute(bool))); + } +} + +/** + * This method return the current time + * @return the time + */ +QTime OTimePicker::time()const { + return tm; +} + +void OTimePicker::slotHour(bool b) { + + OClickableLabel *r = (OClickableLabel *) sender(); + + if (b) { + QValueListIterator<OClickableLabel *> it; + for (it=hourLst.begin(); it!=hourLst.end(); it++) { + if (*it != r) (*it)->setOn(false); + else tm.setHMS((*it)->text().toInt(), tm.minute(), 0); + } + emit timeChanged(tm); + } else { + r->setOn(true); + } + +} + +void OTimePicker::slotMinute(bool b) { + + OClickableLabel *r = (OClickableLabel *) sender(); + + if (b) { + QValueListIterator<OClickableLabel *> it; + for (it=minuteLst.begin(); it!=minuteLst.end(); it++) { + if (*it != r) (*it)->setOn(false); + else tm.setHMS(tm.hour(),(*it)->text().toInt(), 0); + } + emit timeChanged(tm); + } else { + r->setOn(true); + } + +} + +/** + * Method to set the time. No signal gets emitted during this method call + * Minutes must be within 5 minutes step starting at 0 ( 0,5,10,15,20... ) + * @param t The time to be set + */ +void OTimePicker::setTime( const QTime& t) { + setTime( t.hour(), t.minute() ); +} + +/** + * Method to set the time. No signal gets emitted during this method call + * @param h The hour + * @param m The minute. Minutes need to set by 5 minute steps + */ +void OTimePicker::setTime( int h, int m ) { + setHour(h); + setMinute(m); +} + +/* + * FIXME round minutes to the 5 minute arrangement -zecke + */ +/** + * Method to set the minutes + * @param m minutes + */ +void OTimePicker::setMinute(int m) { + + QString minute; + minute.sprintf("%.2d",m); + + QValueListIterator<OClickableLabel *> it; + for (it=minuteLst.begin(); it!=minuteLst.end(); it++) { + if ((*it)->text() == minute) (*it)->setOn(true); + else (*it)->setOn(false); + } + + tm.setHMS(tm.hour(),m,0); +} + +/** + * Method to set the hour + */ +void OTimePicker::setHour(int h) { + + QString hour; + hour.sprintf("%.2d",h); + + QValueListIterator<OClickableLabel *> it; + for (it=hourLst.begin(); it!=hourLst.end(); it++) { + if ((*it)->text() == hour) (*it)->setOn(true); + else (*it)->setOn(false); + } + tm.setHMS(h,tm.minute(),0); +} + + +/** + * This is a modal Dialog. + * + * @param parent The parent widget + * @param name The name of the object + * @param fl Possible window flags + */ +OTimePickerDialog::OTimePickerDialog ( QWidget* parent, const char* name, WFlags fl ) + : OTimePickerDialogBase (parent , name, true , fl) +{ + + connect ( m_timePicker, SIGNAL( timeChanged(const QTime&) ), + this, SLOT( setTime(const QTime&) ) ); + connect ( minuteField, SIGNAL( textChanged(const QString&) ), + this, SLOT ( setMinute(const QString&) ) ); + connect ( hourField, SIGNAL( textChanged(const QString&) ), + this, SLOT ( setHour(const QString&) ) ); + +} + +/** + * @return the time + */ +QTime OTimePickerDialog::time()const +{ + return m_time; +} + +/** + * Set the time to time + * @param time The time to be set + */ +void OTimePickerDialog::setTime( const QTime& time ) +{ + m_time = time; + + m_timePicker->setHour ( time.hour() ); + m_timePicker->setMinute( time.minute() ); + + // Set Textfields + if ( time.hour() < 10 ) + hourField->setText( "0" + QString::number( time.hour() ) ); + else + hourField->setText( QString::number( time.hour() ) ); + + if ( time.minute() < 10 ) + minuteField->setText( "0" + QString::number( time.minute() ) ); + else + minuteField->setText( QString::number( time.minute() ) ); + +} + +/** + * This method takes the current minute and tries to set hour + * to hour. This succeeds if the resulting date is valid + * @param hour The hour as a string + */ +void OTimePickerDialog::setHour ( const QString& hour ) +{ + if ( QTime::isValid ( hour.toInt(), m_time.minute() , 00 ) ){ + m_time.setHMS ( hour.toInt(), m_time.minute() , 00 ); + setTime ( m_time ); + } + +} + +/** + * Method to set a new minute. It tries to convert the string to int and + * if the resulting date is valid a new date is set. + * @see setHour + */ +void OTimePickerDialog::setMinute ( const QString& minute ) +{ + if ( QTime::isValid ( m_time.hour(), minute.toInt(), 00 ) ){ + m_time.setHMS ( m_time.hour(), minute.toInt(), 00 ); + setTime ( m_time ); + } +} diff --git a/noncore/unsupported/libopie/otimepicker.h b/noncore/unsupported/libopie/otimepicker.h new file mode 100644 index 0000000..8df7d10 --- a/dev/null +++ b/noncore/unsupported/libopie/otimepicker.h @@ -0,0 +1,86 @@ +#ifndef OTIMEPICKER_H +#define OTIMEPICKER_H + +#include <qwidget.h> +#include <qvaluelist.h> +#include <qdatetime.h> +#include <qdialog.h> + +#include <opie/oclickablelabel.h> +#include "otimepickerbase.h" + +/** + * A class to pick time. It uses clickable labels + * internally to allow a quick selection of a time. + * A time can be selected by two clicks of a user + * + * @short A widget to quickly pick a QTime + * @version 1.0 + * @see QWidget + * @see QTime + * @author Hakan Ardo, Stefan Eilers + */ +class OTimePicker: public QWidget { + Q_OBJECT + + public: + OTimePicker(QWidget* parent = 0, const char* name = 0, + WFlags fl = 0); + + public slots: + void setHour(int h); + void setMinute(int m); + void setTime( const QTime& ); + void setTime( int h, int m ); + + public: + QTime time()const; + + private: + QValueList<OClickableLabel *> hourLst; + QValueList<OClickableLabel *> minuteLst; + QTime tm; + struct Private; + Private *d; + + private slots: + void slotHour(bool b); + void slotMinute(bool b); + + signals: + /** + * gets emitted when the time got changed by the user + */ + void timeChanged(const QTime &); +}; + +/** + * + * @short A small dialog to pick a time + * @version 1.0 + * @author Stefan Eilers + */ + +class OTimePickerDialog: public OTimePickerDialogBase { + Q_OBJECT + + public: + OTimePickerDialog ( QWidget* parent = 0, const char* name = NULL, WFlags fl = 0 ); + /** + * @todo make it non line! See KDE guide for BC + */ + ~OTimePickerDialog() { }; + + QTime time()const; + + public slots: + void setTime( const QTime& time ); + void setHour( const QString& hour ); + void setMinute( const QString& minute ); + + private: + QTime m_time; + class Private; + Private* d; +}; +#endif diff --git a/noncore/unsupported/libopie/otimepickerbase.ui b/noncore/unsupported/libopie/otimepickerbase.ui new file mode 100644 index 0000000..3e7f2fb --- a/dev/null +++ b/noncore/unsupported/libopie/otimepickerbase.ui @@ -0,0 +1,292 @@ +<!DOCTYPE UI><UI> +<class>OTimePickerDialogBase</class> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>OTimePickerDialogBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>210</width> + <height>137</height> + </rect> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>caption</name> + <string>OTimePickerDialogBase</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>4</number> + </property> + <widget> + <class>QFrame</class> + <property stdset="1"> + <name>name</name> + <cstring>Frame10</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>7</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>NoFrame</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Raised</enum> + </property> + <property> + <name>layoutMargin</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>2</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <spacer> + <property> + <name>name</name> + <cstring>Spacer4</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>MinimumExpanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget> + <class>QFrame</class> + <property stdset="1"> + <name>name</name> + <cstring>Frame4</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>4</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>Box</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Sunken</enum> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Time:</string> + </property> + </widget> + <widget> + <class>QLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>hourField</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignHCenter</set> + </property> + <property> + <name>hAlign</name> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1_2</cstring> + </property> + <property stdset="1"> + <name>font</name> + <font> + <bold>1</bold> + </font> + </property> + <property stdset="1"> + <name>text</name> + <string>:</string> + </property> + </widget> + <widget> + <class>QLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>minuteField</cstring> + </property> + <property stdset="1"> + <name>alignment</name> + <set>AlignHCenter</set> + </property> + <property> + <name>hAlign</name> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property> + <name>name</name> + <cstring>Spacer5</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>MinimumExpanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>GroupBox1</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>title</name> + <string>Pick Time:</string> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>11</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget row="0" column="0" > + <class>OTimePicker</class> + <property stdset="1"> + <name>name</name> + <cstring>m_timePicker</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + </sizepolicy> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>OTimePicker</class> + <header location="local">otimepicker.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>1</verdata> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753</data> + </image> +</images> +</UI> diff --git a/noncore/unsupported/libopie/owait.cpp b/noncore/unsupported/libopie/owait.cpp new file mode 100644 index 0000000..a0f3834 --- a/dev/null +++ b/noncore/unsupported/libopie/owait.cpp @@ -0,0 +1,91 @@ +/* This file is part of the OPIE libraries + Copyright (C) 2003 Maximilian Reiss (harlekin@handhelds.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <qlayout.h> +#include <qpe/qpeapplication.h> +#include <qpainter.h> + +#include "owait.h" + +#include <qpe/resource.h> + +static int frame = 0; + +/** + * This will construct a modal dialog. + * + * The default timer length is 10. + * + * @param parent The parent of the widget + * @param msg The name of the object + * @param dispIcon Display Icon? + */ +OWait::OWait(QWidget *parent, const char* msg, bool dispIcon ) + :QDialog(parent, msg, TRUE,WStyle_Customize) { + + + QHBoxLayout *hbox = new QHBoxLayout( this ); + + m_lb = new QLabel( this ); + m_lb->setBackgroundMode ( NoBackground ); + + hbox->addWidget( m_lb ); + hbox->activate(); + + m_pix = Resource::loadPixmap( "BigBusy" ); + m_aniSize = m_pix.height(); + resize( m_aniSize, m_aniSize ); + + m_timerLength = 10; + + m_waitTimer = new QTimer( this ); + connect( m_waitTimer, SIGNAL( timeout() ), this, SLOT( hide() ) ); +} + +void OWait::timerEvent( QTimerEvent * ) { + frame = (++frame) % 4; + repaint(); +} + +void OWait::paintEvent( QPaintEvent * ) { + QPainter p( m_lb ); + p.drawPixmap( 0, 0, m_pix, m_aniSize * frame, 0, m_aniSize, m_aniSize ); +} + +void OWait::show() { + + move( ( ( qApp->desktop()->width() ) / 2 ) - ( m_aniSize / 2 ), ( ( qApp->desktop()->height() ) / 2 ) - ( m_aniSize / 2 ) ); + startTimer( 300 ); + m_waitTimer->start( m_timerLength * 1000, true ); + QDialog::show(); +} + +void OWait::hide() { + killTimers(); + m_waitTimer->stop(); + frame = 0; + QDialog::hide(); +} + +void OWait::setTimerLength( int length ) { + m_timerLength = length; +} + +OWait::~OWait() { +} diff --git a/noncore/unsupported/libopie/owait.h b/noncore/unsupported/libopie/owait.h new file mode 100644 index 0000000..cbfc8d6 --- a/dev/null +++ b/noncore/unsupported/libopie/owait.h @@ -0,0 +1,77 @@ +/* This file is part of the OPIE libraries + Copyright (C) 2003 Maximilian Reiss (harlekin@handhelds.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + + + +#ifndef WAITPOPUP_H +#define WAITPOPUP_H + +#include <qdialog.h> +#include <qpixmap.h> +#include <qlabel.h> +#include <qtimer.h> + +/** + * This class displays a animated waiting icon in the middle of the screen. + * + * @short modal hour glass dialog + * @see QDialog + * @author Maximilian Reiß + */ +class OWait : public QDialog { + + Q_OBJECT + +public: + // FIXME Wflags -zecke? + OWait(QWidget *parent=0,const char* name=0, bool dispIcon=TRUE); + ~OWait(); + + /** + * reimplemented for control reasons + */ + void show(); + + /** + * Set the time before the icon will be automaticly hidden + * The timer will be started once the widget will be shown. + * @param length - time in seconds + */ + void setTimerLength( int length ); + + public slots: + /** + * reimplemented for control reasons + */ + void hide(); + + private: + void timerEvent( QTimerEvent * ) ; + void paintEvent( QPaintEvent * ); + + QPixmap m_pix; + QLabel *m_lb; + QTimer *m_waitTimer; + int m_timerLength; + int m_aniSize; + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/.cvsignore b/noncore/unsupported/libopie/pim/.cvsignore new file mode 100644 index 0000000..aef62c4 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/.cvsignore @@ -0,0 +1,2 @@ +config.in +moc* diff --git a/noncore/unsupported/libopie/pim/config.in b/noncore/unsupported/libopie/pim/config.in new file mode 100644 index 0000000..95d3737 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/config.in @@ -0,0 +1,2 @@ +menu "Pim" +endmenu diff --git a/noncore/unsupported/libopie/pim/libopie.pro b/noncore/unsupported/libopie/pim/libopie.pro new file mode 100644 index 0000000..62f235d --- a/dev/null +++ b/noncore/unsupported/libopie/pim/libopie.pro @@ -0,0 +1,64 @@ +TEMPLATE = lib +CONFIG += qte warn_on release +HEADERS = ofontmenu.h \ + tododb.h \ + todoevent.h todoresource.h \ + todovcalresource.h xmltree.h \ + colordialog.h colorpopupmenu.h \ + oclickablelabel.h oprocctrl.h \ + oprocess.h odevice.h \ + otimepicker.h otabwidget.h \ + otabbar.h otabinfo.h \ + ofileselector/ofiledialog.h \ + ofileselector/ofilelistview.h \ + ofileselector/ofileselector.h \ + ofileselector/ofileselectoritem.h \ + ofileselector/ofileview.h \ + ofileselector/olister.h \ + ofileselector/olocallister.h \ + ofileselector/ofileselectormain.h \ + pim/opimrecord.h \ + pim/otodo.h \ + pim/orecordlist.h \ + pim/opimaccesstemplate.h \ + pim/opimaccessbackend.h \ + pim/otodoaccess.h \ + pim/otodacessbackend.h \ + pim/ocontact.h \ + pim/ocontactaccess.h \ + pim/ocontactaccessbackend.h \ + pim/ocontactaccessbackend_xml.h \ + pim/orecord.h + +SOURCES = ofontmenu.cc \ + xmltree.cc \ + tododb.cpp todoevent.cpp \ + todovcalresource.cpp colordialog.cpp \ + colorpopupmenu.cpp oclickablelabel.cpp \ + oprocctrl.cpp oprocess.cpp \ + odevice.cpp otimepicker.cpp \ + otabwidget.cpp otabbar.cpp \ + ofileselector/ofiledialog.cpp \ + ofileselector/ofilelistview.cpp \ + ofileselector/ofileselector.cpp \ + ofileselector/ofileselectoritem.cpp \ + ofileselector/ofileview.cpp \ + ofileselector/olister.cpp \ + ofileselector/olocallister.cpp \ + ofileselector/ofileselectormain.cpp \ + pim/otodo.cpp \ + pim/opimrecord.cpp \ + pim/otodoaccess.cpp \ + pim/otodoaccessbackend.cpp \ + pim/ocontact.cpp \ + pim/ocontactaccess.cpp \ + pim/orecord.cpp + +TARGET = opie +INCLUDEPATH += $(OPIEDIR)/include +DESTDIR = $(OPIEDIR)/lib$(PROJMAK) +#VERSION = 1.0.0 + +INTERFACES = otimepickerbase.ui + +include ( $(OPIEDIR)/include.pro ) diff --git a/noncore/unsupported/libopie/pim/obackendfactory.h b/noncore/unsupported/libopie/pim/obackendfactory.h new file mode 100644 index 0000000..4cdef8b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/obackendfactory.h @@ -0,0 +1,197 @@ +/* + * Class to manage Backends. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version. + * ===================================================================== + * ToDo: Use plugins + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.9 2003/12/22 10:19:26 eilers + * Finishing implementation of sql-backend for datebook. But I have to + * port the PIM datebook application to use it, before I could debug the + * whole stuff. + * Thus, PIM-Database backend is finished, but highly experimental. And some + * parts are still generic. For instance, the "queryByExample()" methods are + * not (or not fully) implemented. Todo: custom-entries not stored. + * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular + * expression search in the database, which is not supported by sqlite ! + * Therefore we need either an extended sqlite or a workaround which would + * be very slow and memory consuming.. + * + * Revision 1.8 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + * Revision 1.7 2003/08/01 12:30:16 eilers + * Merging changes from BRANCH_1_0 to HEAD + * + * Revision 1.6.4.1 2003/06/30 14:34:19 eilers + * Patches from Zecke: + * Fixing and cleaning up extraMap handling + * Adding d_ptr for binary compatibility in the future + * + * Revision 1.6 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.5 2003/02/21 23:31:52 zecke + * Add XML datebookresource + * -clean up todoaccessxml header + * -implement some more stuff in the oeven tester + * -extend DefaultFactory to not crash and to use datebook + * + * -reading of OEvents is working nicely.. saving will be added + * tomorrow + * -fix spelling in ODateBookAcces + * + * Revision 1.4 2002/10/14 15:55:18 eilers + * Redeactivate SQL.. ;) + * + * Revision 1.3 2002/10/10 17:08:58 zecke + * The Cache is finally in place + * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;) + * The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster.... + * I still have to fully implement read ahead + * This change is bic but sc + * + * Revision 1.2 2002/10/08 09:27:36 eilers + * Fixed libopie.pro to include the new pim-API. + * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to + * compile itself would need to install libsqlite, libopiesql... + * Therefore, the backend currently uses XML only.. + * + * Revision 1.1 2002/10/07 17:35:01 eilers + * added OBackendFactory for advanced backend access + * + * + * ===================================================================== + */ +#ifndef OPIE_BACKENDFACTORY_H_ +#define OPIE_BACKENDFACTORY_H_ + +#include <qstring.h> +#include <qasciidict.h> +#include <qpe/config.h> + +#include "otodoaccessxml.h" +#include "ocontactaccessbackend_xml.h" +#include "odatebookaccessbackend_xml.h" + +#ifdef __USE_SQL +#include "otodoaccesssql.h" +#include "ocontactaccessbackend_sql.h" +#include "odatebookaccessbackend_sql.h" +#endif + +class OBackendPrivate; + +/** + * This class is our factory. It will give us the default implementations + * of at least Todolist, Contacts and Datebook. In the future this class will + * allow users to switch the backend with ( XML->SQLite ) without the need + * to recompile.# + * This class as the whole PIM Api is making use of templates + * + * <pre> + * OTodoAccessBackend* backend = OBackEndFactory<OTodoAccessBackend>::Default("todo", QString::null ); + * backend->load(); + * </pre> + * + * @author Stefan Eilers + * @version 0.1 + */ +template<class T> +class OBackendFactory +{ + public: + OBackendFactory() {}; + + enum BACKENDS { + TODO, + CONTACT, + DATE + }; + + /** + * Returns a backend implementation for backendName + * @param backendName the type of the backend + * @param appName will be passed on to the backend + */ + static T* Default( const QString backendName, const QString& appName ){ + + // __asm__("int3"); + + Config config( "pimaccess" ); + config.setGroup ( backendName ); + QString backend = config.readEntry( "usebackend" ); + + qWarning("Selected backend for %s is: %s", backendName.latin1(), backend.latin1() ); + + QAsciiDict<int> dict ( 3 ); + dict.setAutoDelete ( TRUE ); + + dict.insert( "todo", new int (TODO) ); + dict.insert( "contact", new int (CONTACT) ); + dict.insert( "datebook", new int(DATE) ); + + int *find = dict[ backendName ]; + if (!find ) return 0; + + switch ( *find ){ + case TODO: +#ifdef __USE_SQL + if ( backend == "sql" ) + return (T*) new OTodoAccessBackendSQL(""); +#else + if ( backend == "sql" ) + qWarning ("OBackendFactory:: sql Backend for TODO not implemented! Using XML instead!"); +#endif + + return (T*) new OTodoAccessXML( appName ); + case CONTACT: +#ifdef __USE_SQL + if ( backend == "sql" ) + return (T*) new OContactAccessBackend_SQL(""); +#else + if ( backend == "sql" ) + qWarning ("OBackendFactory:: sql Backend for CONTACT not implemented! Using XML instead!"); +#endif + + return (T*) new OContactAccessBackend_XML( appName ); + case DATE: +#ifdef __USE_SQL + if ( backend == "sql" ) + return (T*) new ODateBookAccessBackend_SQL(""); +#else + if ( backend == "sql" ) + qWarning("OBackendFactory:: sql Backend for DATEBOOK not implemented! Using XML instead!"); +#endif + + return (T*) new ODateBookAccessBackend_XML( appName ); + default: + return NULL; + } + + + } + private: + OBackendPrivate* d; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/ocontact.cpp b/noncore/unsupported/libopie/pim/ocontact.cpp new file mode 100644 index 0000000..fcf3b26 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontact.cpp @@ -0,0 +1,1207 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QTOPIA_INTERNAL_CONTACT_MRE + +#include "ocontact.h" +#include "opimresolver.h" +#include "oconversion.h" + +#include <qpe/stringutil.h> +#include <qpe/timestring.h> +#include <qpe/config.h> + +#include <qobject.h> +#include <qregexp.h> +#include <qstylesheet.h> +#include <qfileinfo.h> +#include <qmap.h> + +#include <stdio.h> + +/*! + \class Contact contact.h + \brief The Contact class holds the data of an address book entry. + + This data includes information the name of the person, contact + information, and business information such as deparment and job title. + + \ingroup qtopiaemb + \ingroup qtopiadesktop +*/ + + +/*! + Creates a new, empty contact. +*/ +OContact::OContact() + : OPimRecord(), mMap(), d( 0 ) +{ +} + +/*! + \internal + Creates a new contact. The properties of the contact are + set from \a fromMap. +*/ +OContact::OContact( const QMap<int, QString> &fromMap ) : + OPimRecord(), mMap( fromMap ), d( 0 ) +{ + QString cats = mMap[ Qtopia::AddressCategory ]; + if ( !cats.isEmpty() ) + setCategories( idsFromString( cats ) ); + + QString uidStr = find( Qtopia::AddressUid ); + + if ( uidStr.isEmpty() || (uidStr.toInt() == 0) ){ + qWarning( "Invalid UID found. Generate new one.." ); + setUid( uidGen().generate() ); + }else + setUid( uidStr.toInt() ); + +// if ( !uidStr.isEmpty() ) +// setUid( uidStr.toInt() ); +} + +/*! + Destroys a contact. +*/ +OContact::~OContact() +{ +} + +/*! \fn void OContact::setTitle( const QString &str ) + Sets the title of the contact to \a str. +*/ + +/*! \fn void OContact::setFirstName( const QString &str ) + Sets the first name of the contact to \a str. +*/ + +/*! \fn void OContact::setMiddleName( const QString &str ) + Sets the middle name of the contact to \a str. +*/ + +/*! \fn void OContact::setLastName( const QString &str ) + Sets the last name of the contact to \a str. +*/ + +/*! \fn void OContact::setSuffix( const QString &str ) + Sets the suffix of the contact to \a str. +*/ + +/*! \fn void OContact::setFileAs( const QString &str ) + Sets the contact to filed as \a str. +*/ + +/*! \fn void OContact::setDefaultEmail( const QString &str ) + Sets the default email of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeStreet( const QString &str ) + Sets the home street address of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeCity( const QString &str ) + Sets the home city of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeState( const QString &str ) + Sets the home state of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeZip( const QString &str ) + Sets the home zip code of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeCountry( const QString &str ) + Sets the home country of the contact to \a str. +*/ + +/*! \fn void OContact::setHomePhone( const QString &str ) + Sets the home phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeFax( const QString &str ) + Sets the home fax number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeMobile( const QString &str ) + Sets the home mobile phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeWebpage( const QString &str ) + Sets the home webpage of the contact to \a str. +*/ + +/*! \fn void OContact::setCompany( const QString &str ) + Sets the company for contact to \a str. +*/ + +/*! \fn void OContact::setJobTitle( const QString &str ) + Sets the job title of the contact to \a str. +*/ + +/*! \fn void OContact::setDepartment( const QString &str ) + Sets the department for contact to \a str. +*/ + +/*! \fn void OContact::setOffice( const QString &str ) + Sets the office for contact to \a str. +*/ + +/*! \fn void OContact::setBusinessStreet( const QString &str ) + Sets the business street address of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessCity( const QString &str ) + Sets the business city of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessState( const QString &str ) + Sets the business state of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessZip( const QString &str ) + Sets the business zip code of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessCountry( const QString &str ) + Sets the business country of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessPhone( const QString &str ) + Sets the business phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessFax( const QString &str ) + Sets the business fax number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessMobile( const QString &str ) + Sets the business mobile phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessPager( const QString &str ) + Sets the business pager number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessWebpage( const QString &str ) + Sets the business webpage of the contact to \a str. +*/ + +/*! \fn void OContact::setProfession( const QString &str ) + Sets the profession of the contact to \a str. +*/ + +/*! \fn void OContact::setAssistant( const QString &str ) + Sets the assistant of the contact to \a str. +*/ + +/*! \fn void OContact::setManager( const QString &str ) + Sets the manager of the contact to \a str. +*/ + +/*! \fn void OContact::setSpouse( const QString &str ) + Sets the spouse of the contact to \a str. +*/ + +/*! \fn void OContact::setGender( const QString &str ) + Sets the gender of the contact to \a str. +*/ + +/*! \fn void OContact::setNickname( const QString &str ) + Sets the nickname of the contact to \a str. +*/ + +/*! \fn void OContact::setNotes( const QString &str ) + Sets the notes about the contact to \a str. +*/ + +/*! \fn QString OContact::title() const + Returns the title of the contact. +*/ + +/*! \fn QString OContact::firstName() const + Returns the first name of the contact. +*/ + +/*! \fn QString OContact::middleName() const + Returns the middle name of the contact. +*/ + +/*! \fn QString OContact::lastName() const + Returns the last name of the contact. +*/ + +/*! \fn QString OContact::suffix() const + Returns the suffix of the contact. +*/ + +/*! \fn QString OContact::fileAs() const + Returns the string the contact is filed as. +*/ + +/*! \fn QString OContact::defaultEmail() const + Returns the default email address of the contact. +*/ + +/*! \fn QString OContact::emails() const + Returns the list of email address for a contact separated by ';'s in a single + string. +*/ + +/*! \fn QString OContact::homeStreet() const + Returns the home street address of the contact. +*/ + +/*! \fn QString OContact::homeCity() const + Returns the home city of the contact. +*/ + +/*! \fn QString OContact::homeState() const + Returns the home state of the contact. +*/ + +/*! \fn QString OContact::homeZip() const + Returns the home zip of the contact. +*/ + +/*! \fn QString OContact::homeCountry() const + Returns the home country of the contact. +*/ + +/*! \fn QString OContact::homePhone() const + Returns the home phone number of the contact. +*/ + +/*! \fn QString OContact::homeFax() const + Returns the home fax number of the contact. +*/ + +/*! \fn QString OContact::homeMobile() const + Returns the home mobile number of the contact. +*/ + +/*! \fn QString OContact::homeWebpage() const + Returns the home webpage of the contact. +*/ + +/*! \fn QString OContact::company() const + Returns the company for the contact. +*/ + +/*! \fn QString OContact::department() const + Returns the department for the contact. +*/ + +/*! \fn QString OContact::office() const + Returns the office for the contact. +*/ + +/*! \fn QString OContact::jobTitle() const + Returns the job title of the contact. +*/ + +/*! \fn QString OContact::profession() const + Returns the profession of the contact. +*/ + +/*! \fn QString OContact::assistant() const + Returns the assistant of the contact. +*/ + +/*! \fn QString OContact::manager() const + Returns the manager of the contact. +*/ + +/*! \fn QString OContact::businessStreet() const + Returns the business street address of the contact. +*/ + +/*! \fn QString OContact::businessCity() const + Returns the business city of the contact. +*/ + +/*! \fn QString OContact::businessState() const + Returns the business state of the contact. +*/ + +/*! \fn QString OContact::businessZip() const + Returns the business zip of the contact. +*/ + +/*! \fn QString OContact::businessCountry() const + Returns the business country of the contact. +*/ + +/*! \fn QString OContact::businessPhone() const + Returns the business phone number of the contact. +*/ + +/*! \fn QString OContact::businessFax() const + Returns the business fax number of the contact. +*/ + +/*! \fn QString OContact::businessMobile() const + Returns the business mobile number of the contact. +*/ + +/*! \fn QString OContact::businessPager() const + Returns the business pager number of the contact. +*/ + +/*! \fn QString OContact::businessWebpage() const + Returns the business webpage of the contact. +*/ + +/*! \fn QString OContact::spouse() const + Returns the spouse of the contact. +*/ + +/*! \fn QString OContact::gender() const + Returns the gender of the contact. +*/ + +/*! \fn QString OContact::nickname() const + Returns the nickname of the contact. +*/ + +/*! \fn QString OContact::children() const + Returns the children of the contact. +*/ + +/*! \fn QString OContact::notes() const + Returns the notes relating to the the contact. +*/ + +/*! \fn QString OContact::groups() const + \internal + Returns the groups for the contact. +*/ + +/*! \fn QStringList OContact::groupList() const + \internal +*/ + +/*! \fn QString OContact::field(int) const + \internal +*/ + +/*! \fn void OContact::saveJournal( journal_action, const QString & = QString::null ) + \internal +*/ + +/*! \fn void OContact::setUid( int id ) + \internal + Sets the uid for this record to \a id. +*/ + +/*! \enum OContact::journal_action + \internal +*/ + +/*! + \internal +*/ +QMap<int, QString> OContact::toMap() const +{ + QMap<int, QString> map = mMap; + QString cats = idsToString( categories() ); + if ( !cats.isEmpty() ) + map.insert( Qtopia::AddressCategory, cats ); + return map; +} + +/*! + Returns a rich text formatted QString representing the contents the contact. +*/ +QString OContact::toRichText() const +{ + QString text; + QString value, comp, state; + QString str; + bool marker = false; + + Config cfg("qpe"); + cfg.setGroup("Appearance"); + int addressformat = cfg.readNumEntry( "AddressFormat", Zip_City_State ); + + // name, jobtitle and company + if ( !(value = fullName()).isEmpty() ) + text += "<b><h3><img src=\"addressbook/AddressBook\"> " + Qtopia::escapeString(value) + "</h3></b>"; + + if ( !(value = jobTitle()).isEmpty() ) + text += Qtopia::escapeString(value) + " "; + + comp = company(); + if ( !(value = department()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( comp ) + text += ", " + Qtopia::escapeString(comp); + }else if ( comp ) + text += "<br>" + Qtopia::escapeString(comp); + text += "<br><hr>"; + + // defailt email + QString defEmail = defaultEmail(); + if ( !defEmail.isEmpty() ){ + text += "<b><img src=\"addressbook/email\"> " + QObject::tr("Default Email: ") + "</b>" + + Qtopia::escapeString(defEmail); + marker = true; + } + + // business address + if ( !businessStreet().isEmpty() || !businessCity().isEmpty() || + !businessZip().isEmpty() || !businessCountry().isEmpty() ) { + text += QObject::tr( "<br><b>Work Address:</b>" ); + marker = true; + } + + if ( !(value = businessStreet()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value); + marker = true; + } + + switch( addressformat ){ + case Zip_City_State:{ // Zip_Code City, State + state = businessState(); + if ( !(value = businessZip()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value) + " "; + marker = true; + + } + if ( !(value = businessCity()).isEmpty() ) { + marker = true; + if ( businessZip().isEmpty() && !businessStreet().isEmpty() ) + text += "<br>"; + text += Qtopia::escapeString(value); + if ( state ) + text += ", " + Qtopia::escapeString(state); + } else if ( !state.isEmpty() ){ + text += "<br>" + Qtopia::escapeString(state); + marker = true; + } + break; + } + case City_State_Zip:{ // City, State Zip_Code + state = businessState(); + if ( !(value = businessCity()).isEmpty() ) { + marker = true; + text += "<br>" + Qtopia::escapeString(value); + if ( state ) + text += ", " + Qtopia::escapeString(state); + } else if ( !state.isEmpty() ){ + text += "<br>" + Qtopia::escapeString(state); + marker = true; + } + if ( !(value = businessZip()).isEmpty() ){ + text += " " + Qtopia::escapeString(value); + marker = true; + } + break; + } + } + + if ( !(value = businessCountry()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value); + marker = true; + } + + // rest of Business data + str = office(); + if ( !str.isEmpty() ){ + text += "<br><b>" + QObject::tr("Office: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = businessWebpage(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/webpagework\"> " + QObject::tr("Business Web Page: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = businessPhone(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/phonework\"> " + QObject::tr("Business Phone: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = businessFax(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/faxwork\"> " + QObject::tr("Business Fax: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = businessMobile(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/mobilework\"> " + QObject::tr("Business Mobile: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = businessPager(); + if ( !str.isEmpty() ){ + text += "<br><b>" + QObject::tr("Business Pager: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + + // text += "<br>"; + + // home address + if ( !homeStreet().isEmpty() || !homeCity().isEmpty() || + !homeZip().isEmpty() || !homeCountry().isEmpty() ) { + text += QObject::tr( "<br><b>Home Address:</b>" ); + marker = true; + } + + if ( !(value = homeStreet()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value); + marker = true; + } + + switch( addressformat ){ + case Zip_City_State:{ // Zip_Code City, State + state = homeState(); + if ( !(value = homeZip()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value) + " "; + marker = true; + } + if ( !(value = homeCity()).isEmpty() ) { + marker = true; + if ( homeZip().isEmpty() && !homeStreet().isEmpty() ) + text += "<br>"; + text += Qtopia::escapeString(value); + if ( !state.isEmpty() ) + text += ", " + Qtopia::escapeString(state); + } else if (!state.isEmpty()) { + text += "<br>" + Qtopia::escapeString(state); + marker = true; + } + break; + } + case City_State_Zip:{ // City, State Zip_Code + state = homeState(); + if ( !(value = homeCity()).isEmpty() ) { + marker = true; + text += "<br>" + Qtopia::escapeString(value); + if ( state ) + text += ", " + Qtopia::escapeString(state); + } else if ( !state.isEmpty() ){ + text += "<br>" + Qtopia::escapeString(state); + marker = true; + } + if ( !(value = homeZip()).isEmpty() ){ + text += " " + Qtopia::escapeString(value); + marker = true; + } + break; + } + } + + if ( !(value = homeCountry()).isEmpty() ){ + text += "<br>" + Qtopia::escapeString(value); + marker = true; + } + + // rest of Home data + str = homeWebpage(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/webpagehome\"> " + QObject::tr("Home Web Page: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = homePhone(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/phonehome\"> " + QObject::tr("Home Phone: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = homeFax(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/faxhome\"> " + QObject::tr("Home Fax: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + str = homeMobile(); + if ( !str.isEmpty() ){ + text += "<br><b><img src=\"addressbook/mobilehome\"> " + QObject::tr("Home Mobile: ") + "</b>" + + Qtopia::escapeString(str); + marker = true; + } + + if ( marker ) + text += "<br><hr>"; + + // the rest... + str = emails(); + if ( !str.isEmpty() && ( str != defEmail ) ) + text += "<br><b>" + QObject::tr("All Emails: ") + "</b>" + + Qtopia::escapeString(str); + str = profession(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Profession: ") + "</b>" + + Qtopia::escapeString(str); + str = assistant(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Assistant: ") + "</b>" + + Qtopia::escapeString(str); + str = manager(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Manager: ") + "</b>" + + Qtopia::escapeString(str); + str = gender(); + if ( !str.isEmpty() && str.toInt() != 0 ) { + text += "<br>"; + if ( str.toInt() == 1 ) + str = QObject::tr( "Male" ); + else if ( str.toInt() == 2 ) + str = QObject::tr( "Female" ); + text += "<b>" + QObject::tr("Gender: ") + "</b>" + str; + } + str = spouse(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Spouse: ") + "</b>" + + Qtopia::escapeString(str); + if ( birthday().isValid() ){ + str = TimeString::numberDateString( birthday() ); + text += "<br><b>" + QObject::tr("Birthday: ") + "</b>" + + Qtopia::escapeString(str); + } + if ( anniversary().isValid() ){ + str = TimeString::numberDateString( anniversary() ); + text += "<br><b>" + QObject::tr("Anniversary: ") + "</b>" + + Qtopia::escapeString(str); + } + str = children(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Children: ") + "</b>" + + Qtopia::escapeString(str); + + str = nickname(); + if ( !str.isEmpty() ) + text += "<br><b>" + QObject::tr("Nickname: ") + "</b>" + + Qtopia::escapeString(str); + + // categories + if ( categoryNames("Contacts").count() ){ + text += "<br><b>" + QObject::tr( "Category:") + "</b> "; + text += categoryNames("Contacts").join(", "); + } + + // notes last + if ( !(value = notes()).isEmpty() ) { + text += "<br><hr><b>" + QObject::tr( "Notes:") + "</b> "; + QRegExp reg("\n"); + + //QString tmp = Qtopia::escapeString(value); + QString tmp = QStyleSheet::convertFromPlainText(value); + //tmp.replace( reg, "<br>" ); + text += "<br>" + tmp + "<br>"; + } + return text; +} + +/*! + \internal +*/ +void OContact::insert( int key, const QString &v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.insert( key, value ); +} + +/*! + \internal +*/ +void OContact::replace( int key, const QString & v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.replace( key, value ); +} + +/*! + \internal +*/ +QString OContact::find( int key ) const +{ + return mMap[key]; +} + +/*! + \internal +*/ +QString OContact::displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const +{ + QString s = street; + if ( !street.isEmpty() ) + s+= "\n"; + s += city; + if ( !city.isEmpty() && !state.isEmpty() ) + s += ", "; + s += state; + if ( !state.isEmpty() && !zip.isEmpty() ) + s += " "; + s += zip; + if ( !country.isEmpty() && !s.isEmpty() ) + s += "\n"; + s += country; + return s; +} + +/*! + \internal +*/ +QString OContact::displayBusinessAddress() const +{ + return displayAddress( businessStreet(), businessCity(), + businessState(), businessZip(), + businessCountry() ); +} + +/*! + \internal +*/ +QString OContact::displayHomeAddress() const +{ + return displayAddress( homeStreet(), homeCity(), + homeState(), homeZip(), + homeCountry() ); +} + +/*! + Returns the full name of the contact +*/ +QString OContact::fullName() const +{ + QString title = find( Qtopia::Title ); + QString firstName = find( Qtopia::FirstName ); + QString middleName = find( Qtopia::MiddleName ); + QString lastName = find( Qtopia::LastName ); + QString suffix = find( Qtopia::Suffix ); + + QString name = title; + if ( !firstName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += firstName; + } + if ( !middleName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += middleName; + } + if ( !lastName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += lastName; + } + if ( !suffix.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += suffix; + } + return name.simplifyWhiteSpace(); +} + +/*! + Returns a list of the names of the children of the contact. +*/ +QStringList OContact::childrenList() const +{ + return QStringList::split( " ", find( Qtopia::Children ) ); +} + +/*! \fn void OContact::insertEmail( const QString &email ) + + Insert \a email into the email list. Ensures \a email can only be added + once. If there is no default email address set, it sets it to the \a email. +*/ + +/*! \fn void OContact::removeEmail( const QString &email ) + + Removes the \a email from the email list. If the default email was \a email, + then the default email address is assigned to the first email in the + email list +*/ + +/*! \fn void OContact::clearEmails() + + Clears the email list. + */ + +/*! \fn void OContact::insertEmails( const QStringList &emailList ) + + Appends the \a emailList to the exiting email list + */ + +/*! + Returns a list of email addresses belonging to the contact, including + the default email address. +*/ +QStringList OContact::emailList() const +{ + QString emailStr = emails(); + + QStringList r; + if ( !emailStr.isEmpty() ) { + qDebug(" emailstr "); + QStringList l = QStringList::split( emailSeparator(), emailStr ); + for ( QStringList::ConstIterator it = l.begin();it != l.end();++it ) + r += (*it).simplifyWhiteSpace(); + } + + return r; +} + +/*! + \overload + + Generates the string for the contact to be filed as from the first, + middle and last name of the contact. +*/ +void OContact::setFileAs() +{ + QString lastName, firstName, middleName, fileas; + + lastName = find( Qtopia::LastName ); + firstName = find( Qtopia::FirstName ); + middleName = find( Qtopia::MiddleName ); + if ( !lastName.isEmpty() && !firstName.isEmpty() + && !middleName.isEmpty() ) + fileas = lastName + ", " + firstName + " " + middleName; + else if ( !lastName.isEmpty() && !firstName.isEmpty() ) + fileas = lastName + ", " + firstName; + else if ( !lastName.isEmpty() || !firstName.isEmpty() || + !middleName.isEmpty() ) + fileas = firstName + ( firstName.isEmpty() ? "" : " " ) + + middleName + ( middleName.isEmpty() ? "" : " " ) + + lastName; + + replace( Qtopia::FileAs, fileas ); +} + +/*! + \internal + Appends the contact information to \a buf. +*/ +void OContact::save( QString &buf ) const +{ + static const QStringList SLFIELDS = fields(); + // I'm expecting "<Contact " in front of this... + for ( QMap<int, QString>::ConstIterator it = mMap.begin(); + it != mMap.end(); ++it ) { + const QString &value = it.data(); + int key = it.key(); + if ( !value.isEmpty() ) { + if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) + continue; + + key -= Qtopia::AddressCategory+1; + buf += SLFIELDS[key]; + buf += "=\"" + Qtopia::escapeString(value) + "\" "; + } + } + buf += customToXml(); + if ( categories().count() > 0 ) + buf += "Categories=\"" + idsToString( categories() ) + "\" "; + buf += "Uid=\"" + QString::number( uid() ) + "\" "; + // You need to close this yourself +} + + +/*! + \internal + Returns the list of fields belonging to a contact + Never change order of this list ! It has to be regarding + enum AddressBookFields !! +*/ +QStringList OContact::fields() +{ + QStringList list; + + list.append( "Title" ); // Not Used! + list.append( "FirstName" ); + list.append( "MiddleName" ); + list.append( "LastName" ); + list.append( "Suffix" ); + list.append( "FileAs" ); + + list.append( "JobTitle" ); + list.append( "Department" ); + list.append( "Company" ); + list.append( "BusinessPhone" ); + list.append( "BusinessFax" ); + list.append( "BusinessMobile" ); + + list.append( "DefaultEmail" ); + list.append( "Emails" ); + + list.append( "HomePhone" ); + list.append( "HomeFax" ); + list.append( "HomeMobile" ); + + list.append( "BusinessStreet" ); + list.append( "BusinessCity" ); + list.append( "BusinessState" ); + list.append( "BusinessZip" ); + list.append( "BusinessCountry" ); + list.append( "BusinessPager" ); + list.append( "BusinessWebPage" ); + + list.append( "Office" ); + list.append( "Profession" ); + list.append( "Assistant" ); + list.append( "Manager" ); + + list.append( "HomeStreet" ); + list.append( "HomeCity" ); + list.append( "HomeState" ); + list.append( "HomeZip" ); + list.append( "HomeCountry" ); + list.append( "HomeWebPage" ); + + list.append( "Spouse" ); + list.append( "Gender" ); + list.append( "Birthday" ); + list.append( "Anniversary" ); + list.append( "Nickname" ); + list.append( "Children" ); + + list.append( "Notes" ); + list.append( "Groups" ); + + return list; +} + + +/*! + Sets the list of email address for contact to those contained in \a str. + Email address should be separated by ';'s. +*/ +void OContact::setEmails( const QString &str ) +{ + replace( Qtopia::Emails, str ); + if ( str.isEmpty() ) + setDefaultEmail( QString::null ); +} + +/*! + Sets the list of children for the contact to those contained in \a str. +*/ +void OContact::setChildren( const QString &str ) +{ + replace( Qtopia::Children, str ); +} + +/*! + \overload + Returns TRUE if the contact matches the regular expression \a regexp. + Otherwise returns FALSE. +*/ +bool OContact::match( const QRegExp &r ) const +{ + setLastHitField( -1 ); + bool match; + match = false; + QMap<int, QString>::ConstIterator it; + for ( it = mMap.begin(); it != mMap.end(); ++it ) { + if ( (*it).find( r ) > -1 ) { + setLastHitField( it.key() ); + match = true; + break; + } + } + return match; +} + + +QString OContact::toShortText() const +{ + return ( fullName() ); +} +QString OContact::type() const +{ + return QString::fromLatin1( "OContact" ); +} + + + +class QString OContact::recordField( int pos ) const +{ + QStringList SLFIELDS = fields(); // ?? why this ? (se) + return SLFIELDS[pos]; +} + +// In future releases, we should store birthday and anniversary +// internally as QDate instead of QString ! +// QString is always too complicate to interprete (DD.MM.YY, DD/MM/YY, MM/DD/YY, etc..)(se) + +/*! \fn void OContact::setBirthday( const QDate& date ) + Sets the birthday for the contact to \a date. If date is null + the current stored date will be removed. +*/ +void OContact::setBirthday( const QDate &v ) +{ + if ( v.isNull() ){ + qWarning( "Remove Birthday"); + replace( Qtopia::Birthday, QString::null ); + return; + } + + if ( v.isValid() ) + replace( Qtopia::Birthday, OConversion::dateToString( v ) ); + +} + + +/*! \fn void OContact::setAnniversary( const QDate &date ) + Sets the anniversary of the contact to \a date. If date is + null, the current stored date will be removed. +*/ +void OContact::setAnniversary( const QDate &v ) +{ + if ( v.isNull() ){ + qWarning( "Remove Anniversary"); + replace( Qtopia::Anniversary, QString::null ); + return; + } + + if ( v.isValid() ) + replace( Qtopia::Anniversary, OConversion::dateToString( v ) ); +} + +/*! \fn QDate OContact::birthday() const + Returns the birthday of the contact. +*/ +QDate OContact::birthday() const +{ + QString str = find( Qtopia::Birthday ); + // qWarning ("Birthday %s", str.latin1() ); + if ( !str.isEmpty() ) + return OConversion::dateFromString ( str ); + else + return QDate(); +} + + +/*! \fn QDate OContact::anniversary() const + Returns the anniversary of the contact. +*/ +QDate OContact::anniversary() const +{ + QDate empty; + QString str = find( Qtopia::Anniversary ); + // qWarning ("Anniversary %s", str.latin1() ); + if ( !str.isEmpty() ) + return OConversion::dateFromString ( str ); + else + return empty; +} + + +void OContact::insertEmail( const QString &v ) +{ + //qDebug("insertEmail %s", v.latin1()); + QString e = v.simplifyWhiteSpace(); + QString def = defaultEmail(); + + // if no default, set it as the default email and don't insert + if ( def.isEmpty() ) { + setDefaultEmail( e ); // will insert into the list for us + return; + } + + // otherwise, insert assuming doesn't already exist + QString emailsStr = find( Qtopia::Emails ); + if ( emailsStr.contains( e )) + return; + if ( !emailsStr.isEmpty() ) + emailsStr += emailSeparator(); + emailsStr += e; + replace( Qtopia::Emails, emailsStr ); +} + +void OContact::removeEmail( const QString &v ) +{ + QString e = v.simplifyWhiteSpace(); + QString def = defaultEmail(); + QString emailsStr = find( Qtopia::Emails ); + QStringList emails = emailList(); + + // otherwise, must first contain it + if ( !emailsStr.contains( e ) ) + return; + + // remove it + //qDebug(" removing email from list %s", e.latin1()); + emails.remove( e ); + // reset the string + emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator + replace( Qtopia::Emails, emailsStr ); + + // if default, then replace the default email with the first one + if ( def == e ) { + //qDebug("removeEmail is default; setting new default"); + if ( !emails.count() ) + clearEmails(); + else // setDefaultEmail will remove e from the list + setDefaultEmail( emails.first() ); + } +} +void OContact::clearEmails() +{ + mMap.remove( Qtopia::DefaultEmail ); + mMap.remove( Qtopia::Emails ); +} +void OContact::setDefaultEmail( const QString &v ) +{ + QString e = v.simplifyWhiteSpace(); + + //qDebug("OContact::setDefaultEmail %s", e.latin1()); + replace( Qtopia::DefaultEmail, e ); + + if ( !e.isEmpty() ) + insertEmail( e ); + +} + +void OContact::insertEmails( const QStringList &v ) +{ + for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it ) + insertEmail( *it ); +} +int OContact::rtti() { + return OPimResolver::AddressBook; +} +void OContact::setUid( int i ) +{ + OPimRecord::setUid(i); + replace( Qtopia::AddressUid , QString::number(i)); +} diff --git a/noncore/unsupported/libopie/pim/ocontact.h b/noncore/unsupported/libopie/pim/ocontact.h new file mode 100644 index 0000000..1d46b81 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontact.h @@ -0,0 +1,240 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef __OCONTACT_H__ +#define __OCONTACT_H__ + +#include <opie/opimrecord.h> +#include <qpe/recordfields.h> + +#include <qdatetime.h> +#include <qstringlist.h> + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>; +// MOC_SKIP_END +#endif + +class OContactPrivate; + +/** + * OContact class represents a specialised PIM Record for contacts. + * It does store all kind of persopn related information. + * + * @short Contact Container + * @author TT, Stefan Eiler, Holger Freyther + */ +class QPC_EXPORT OContact : public OPimRecord +{ + friend class DataSet; +public: + OContact(); + OContact( const QMap<int, QString> &fromMap ); + virtual ~OContact(); + + enum DateFormat{ + Zip_City_State = 0, + City_State_Zip + }; + + /* + * do we need to inline them + * if yes do we need to inline them this way? + * -zecke + */ + void setTitle( const QString &v ) { replace( Qtopia::Title, v ); } + void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); } + void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); } + void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); } + void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); } + void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); } + void setFileAs(); + + // default email address + void setDefaultEmail( const QString &v ); + // inserts email to list and ensure's doesn't already exist + void insertEmail( const QString &v ); + void removeEmail( const QString &v ); + void clearEmails(); + void insertEmails( const QStringList &v ); + + // home + void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); } + void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); } + void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); } + void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); } + void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); } + void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); } + void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); } + void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); } + void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); } + + // business + void setCompany( const QString &v ) { replace( Qtopia::Company, v ); } + void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); } + void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); } + void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); } + void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); } + void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); } + void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); } + void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); } + void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); } + void setOffice( const QString &v ) { replace( Qtopia::Office, v ); } + void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); } + void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); } + void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); } + void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); } + void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); } + void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); } + void setManager( const QString &v ) { replace( Qtopia::Manager, v ); } + + // personal + void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); } + void setGender( const QString &v ) { replace( Qtopia::Gender, v ); } + void setBirthday( const QDate &v ); + void setAnniversary( const QDate &v ); + void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); } + void setChildren( const QString &v ); + + // other + void setNotes( const QString &v ) { replace( Qtopia::Notes, v); } + + virtual bool match( const QRegExp ®exp ) const; + +// // custom +// void setCustomField( const QString &key, const QString &v ) +// { replace(Custom- + key, v ); } + + // name + QString fullName() const; + QString title() const { return find( Qtopia::Title ); } + QString firstName() const { return find( Qtopia::FirstName ); } + QString middleName() const { return find( Qtopia::MiddleName ); } + QString lastName() const { return find( Qtopia::LastName ); } + QString suffix() const { return find( Qtopia::Suffix ); } + QString fileAs() const { return find( Qtopia::FileAs ); } + + // email + QString defaultEmail() const { return find( Qtopia::DefaultEmail ); } + QStringList emailList() const; + + // home + /* + * OPimAddress address(enum Location)const; + * would be some how nicer... + * -zecke + */ + QString homeStreet() const { return find( Qtopia::HomeStreet ); } + QString homeCity() const { return find( Qtopia::HomeCity ); } + QString homeState() const { return find( Qtopia::HomeState ); } + QString homeZip() const { return find( Qtopia::HomeZip ); } + QString homeCountry() const { return find( Qtopia::HomeCountry ); } + QString homePhone() const { return find( Qtopia::HomePhone ); } + QString homeFax() const { return find( Qtopia::HomeFax ); } + QString homeMobile() const { return find( Qtopia::HomeMobile ); } + QString homeWebpage() const { return find( Qtopia::HomeWebPage ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayHomeAddress() const; + + // business + QString company() const { return find( Qtopia::Company ); } + QString businessStreet() const { return find( Qtopia::BusinessStreet ); } + QString businessCity() const { return find( Qtopia::BusinessCity ); } + QString businessState() const { return find( Qtopia::BusinessState ); } + QString businessZip() const { return find( Qtopia::BusinessZip ); } + QString businessCountry() const { return find( Qtopia::BusinessCountry ); } + QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); } + QString jobTitle() const { return find( Qtopia::JobTitle ); } + QString department() const { return find( Qtopia::Department ); } + QString office() const { return find( Qtopia::Office ); } + QString businessPhone() const { return find( Qtopia::BusinessPhone ); } + QString businessFax() const { return find( Qtopia::BusinessFax ); } + QString businessMobile() const { return find( Qtopia::BusinessMobile ); } + QString businessPager() const { return find( Qtopia::BusinessPager ); } + QString profession() const { return find( Qtopia::Profession ); } + QString assistant() const { return find( Qtopia::Assistant ); } + QString manager() const { return find( Qtopia::Manager ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayBusinessAddress() const; + + //personal + QString spouse() const { return find( Qtopia::Spouse ); } + QString gender() const { return find( Qtopia::Gender ); } + QDate birthday() const; + QDate anniversary() const; + QString nickname() const { return find( Qtopia::Nickname ); } + QString children() const { return find( Qtopia::Children ); } + QStringList childrenList() const; + + // other + QString notes() const { return find( Qtopia::Notes ); } + QString groups() const { return find( Qtopia::Groups ); } + QStringList groupList() const; + + QString toRichText() const; + QMap<int, QString> toMap() const; + QString field( int key ) const { return find( key ); } + + + void setUid( int i ); + + QString toShortText()const; + QString type()const; + class QString recordField(int) const; + + // Why private ? (eilers,se) + QString emailSeparator() const { return " "; } + + // the emails should be seperated by a comma + void setEmails( const QString &v ); + QString emails() const { return find( Qtopia::Emails ); } + static int rtti(); + +private: + // The XML Backend needs some access to the private functions + friend class OContactAccessBackend_XML; + + void insert( int key, const QString &value ); + void replace( int key, const QString &value ); + QString find( int key ) const; + static QStringList fields(); + + void save( QString &buf ) const; + + QString displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const; + + QMap<int, QString> mMap; + OContactPrivate *d; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactaccess.cpp b/noncore/unsupported/libopie/pim/ocontactaccess.cpp new file mode 100644 index 0000000..63b93ee --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccess.cpp @@ -0,0 +1,176 @@ +/* + * Class to manage the Contacts. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * Info: This class could just work with a change in the header-file + * of the Contact class ! Therefore our libopie only compiles + * with our version of libqpe + * ===================================================================== + * ToDo: XML-Backend: Automatic reload if something was changed... + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.9 2004/03/02 12:14:22 alwin + * run the optimize_connect script + * the whole cvs is tagged with "before_optimize_connect" if there are problems you + * can check the diff (but it had compiled and run here) + * + * Revision 1.8 2003/05/08 13:55:09 tille + * search stuff + * and match, toRichText & toShortText in oevent + * + * Revision 1.7 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.6 2002/11/01 15:10:42 eilers + * Added regExp-search in database for all fields in a contact. + * + * Revision 1.5 2002/10/16 10:52:40 eilers + * Added some docu to the interface and now using the cache infrastucture by zecke.. :) + * + * Revision 1.4 2002/10/14 16:21:54 eilers + * Some minor interface updates + * + * Revision 1.3 2002/10/07 17:34:24 eilers + * added OBackendFactory for advanced backend access + * + * Revision 1.2 2002/10/02 16:18:11 eilers + * debugged and seems to work almost perfectly .. + * + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * + */ + +#include "ocontactaccess.h" +#include "obackendfactory.h" + +#include <qasciidict.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qregexp.h> +#include <qlist.h> +#include <qcopchannel_qws.h> + +//#include <qpe/qcopenvelope_qws.h> +#include <qpe/global.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "ocontactaccessbackend_xml.h" + + +OContactAccess::OContactAccess ( const QString appname, const QString , + OContactAccessBackend* end, bool autosync ): + OPimAccessTemplate<OContact>( end ) +{ + /* take care of the backend. If there is no one defined, we + * will use the XML-Backend as default (until we have a cute SQL-Backend..). + */ + if( end == 0 ) { + qWarning ("Using BackendFactory !"); + end = OBackendFactory<OContactAccessBackend>::Default( "contact", appname ); + } + // Set backend locally and in template + m_backEnd = end; + OPimAccessTemplate<OContact>::setBackEnd (end); + + + /* Connect signal of external db change to function */ + QCopChannel *dbchannel = new QCopChannel( "QPE/PIM", this ); + connect( dbchannel, SIGNAL(received(const QCString&,const QByteArray&)), + this, SLOT(copMessage(const QCString&,const QByteArray&)) ); + if ( autosync ){ + QCopChannel *syncchannel = new QCopChannel( "QPE/Sync", this ); + connect( syncchannel, SIGNAL(received(const QCString&,const QByteArray&)), + this, SLOT(copMessage(const QCString&,const QByteArray&)) ); + } + + +} +OContactAccess::~OContactAccess () +{ + /* The user may forget to save the changed database, therefore try to + * do it for him.. + */ + save(); + // delete m_backEnd; is done by template.. +} + + +bool OContactAccess::save () +{ + /* If the database was changed externally, we could not save the + * Data. This will remove added items which is unacceptable ! + * Therefore: Reload database and merge the data... + */ + if ( OPimAccessTemplate<OContact>::wasChangedExternally() ) + reload(); + + bool status = OPimAccessTemplate<OContact>::save(); + if ( !status ) return false; + + /* Now tell everyone that new data is available. + */ + QCopEnvelope e( "QPE/PIM", "addressbookUpdated()" ); + + return true; +} + +const uint OContactAccess::querySettings() +{ + return ( m_backEnd->querySettings() ); +} + +bool OContactAccess::hasQuerySettings ( int querySettings ) const +{ + return ( m_backEnd->hasQuerySettings ( querySettings ) ); +} +ORecordList<OContact> OContactAccess::sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const +{ + QArray<int> matchingContacts = m_backEnd -> sorted( ascending, sortOrder, sortFilter, cat ); + return ( ORecordList<OContact>(matchingContacts, this) ); +} + + +bool OContactAccess::wasChangedExternally()const +{ + return ( m_backEnd->wasChangedExternally() ); +} + + +void OContactAccess::copMessage( const QCString &msg, const QByteArray & ) +{ + if ( msg == "addressbookUpdated()" ){ + qWarning ("OContactAccess: Received addressbokUpdated()"); + emit signalChanged ( this ); + } else if ( msg == "flush()" ) { + qWarning ("OContactAccess: Received flush()"); + save (); + } else if ( msg == "reload()" ) { + qWarning ("OContactAccess: Received reload()"); + reload (); + emit signalChanged ( this ); + } +} diff --git a/noncore/unsupported/libopie/pim/ocontactaccess.h b/noncore/unsupported/libopie/pim/ocontactaccess.h new file mode 100644 index 0000000..a7a099f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccess.h @@ -0,0 +1,196 @@ +/* + * Class to manage the Contacts. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version. + * ===================================================================== + * ToDo: Define enum for query settings + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.10 2003/12/22 10:19:26 eilers + * Finishing implementation of sql-backend for datebook. But I have to + * port the PIM datebook application to use it, before I could debug the + * whole stuff. + * Thus, PIM-Database backend is finished, but highly experimental. And some + * parts are still generic. For instance, the "queryByExample()" methods are + * not (or not fully) implemented. Todo: custom-entries not stored. + * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular + * expression search in the database, which is not supported by sqlite ! + * Therefore we need either an extended sqlite or a workaround which would + * be very slow and memory consuming.. + * + * Revision 1.9 2003/08/01 12:30:16 eilers + * Merging changes from BRANCH_1_0 to HEAD + * + * Revision 1.8.2.1 2003/06/30 14:34:19 eilers + * Patches from Zecke: + * Fixing and cleaning up extraMap handling + * Adding d_ptr for binary compatibility in the future + * + * Revision 1.8 2003/05/08 13:55:09 tille + * search stuff + * and match, toRichText & toShortText in oevent + * + * Revision 1.7 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.6 2003/01/02 14:27:12 eilers + * Improved query by example: Search by date is possible.. First step + * for a today plugin for birthdays.. + * + * Revision 1.5 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.4 2002/11/01 15:10:42 eilers + * Added regExp-search in database for all fields in a contact. + * + * Revision 1.3 2002/10/16 10:52:40 eilers + * Added some docu to the interface and now using the cache infrastucture by zecke.. :) + * + * Revision 1.2 2002/10/14 16:21:54 eilers + * Some minor interface updates + * + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * ===================================================================== + */ +#ifndef _OCONTACTACCESS_H +#define _OCONTACTACCESS_H + +#include <qobject.h> + +#include <qpe/qcopenvelope_qws.h> + +#include <qvaluelist.h> +#include <qfileinfo.h> + +#include "ocontact.h" +#include "ocontactaccessbackend.h" +#include "opimaccesstemplate.h" + +/** + * Class to access the contacts database. + * This is just a frontend for the real database handling which is + * done by the backend. + * This class is used to access the Contacts on a system. This class as any OPIE PIM + * class is backend independent. + * @author Stefan Eilers, Holger Freyther + * @see OPimAccessTemplate + */ +class OContactAccess: public QObject, public OPimAccessTemplate<OContact> +{ + Q_OBJECT + + public: + /** + * Create Database with contacts (addressbook). + * @param appname Name of application which wants access to the database + * (i.e. "todolist") + * @param filename The name of the database file. If not set, the default one + * is used. + * @param backend Pointer to an alternative Backend. If not set, we will use + * the default backend. + * @param handlesync If <b>true</b> the database stores the current state + * automatically if it receives the signals <i>flush()</i> and <i>reload()</i> + * which are used before and after synchronisation. If the application wants + * to react itself, it should be disabled by setting it to <b>false</b> + * @see OContactAccessBackend + */ + OContactAccess (const QString appname, const QString filename = 0l, + OContactAccessBackend* backend = 0l, bool handlesync = true); + ~OContactAccess (); + + /** Constants for query. + * Use this constants to set the query parameters. + * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes ! + * @see queryByExample() + */ + enum QuerySettings { + WildCards = 0x0001, + IgnoreCase = 0x0002, + RegExp = 0x0004, + ExactMatch = 0x0008, + MatchOne = 0x0010, // Only one Entry must match + DateDiff = 0x0020, // Find all entries from today until given date + DateYear = 0x0040, // The year matches + DateMonth = 0x0080, // The month matches + DateDay = 0x0100, // The day matches + }; + + + /** Return all Contacts in a sorted manner. + * @param ascending true: Sorted in acending order. + * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess + * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess + * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess + */ + List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const; + + /** Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + const uint querySettings(); + + /** Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + bool hasQuerySettings ( int querySettings ) const; + + /** + * if the resource was changed externally. + * You should use the signal instead of polling possible changes ! + */ + bool wasChangedExternally()const; + + + /** Save contacts database. + * Save is more a "commit". After calling this function, all changes are public available. + * @return true if successful + */ + bool save(); + + signals: + /* Signal is emitted if the database was changed. Therefore + * we may need to reload to stay consistent. + * @param which Pointer to the database who created this event. This pointer + * is useful if an application has to handle multiple databases at the same time. + * @see reload() + */ + void signalChanged ( const OContactAccess *which ); + + + private: + // class OContactAccessPrivate; + // OContactAccessPrivate* d; + OContactAccessBackend *m_backEnd; + bool m_loading:1; + + private slots: + void copMessage( const QCString &msg, const QByteArray &data ); + + private: + class Private; + Private *d; + +}; +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend.h new file mode 100644 index 0000000..cfeeff2 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend.h @@ -0,0 +1,131 @@ +/** + * The class responsible for managing a backend. + * The implementation of this abstract class contains + * the complete database handling. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version. + * ===================================================================== + * ToDo: Define enum for query settings + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.7 2004/02/19 02:05:37 zecke + * Add notes for API fixes and BC stuff + * + * Revision 1.6 2003/08/01 12:30:16 eilers + * Merging changes from BRANCH_1_0 to HEAD + * + * Revision 1.5.4.1 2003/06/30 14:34:19 eilers + * Patches from Zecke: + * Fixing and cleaning up extraMap handling + * Adding d_ptr for binary compatibility in the future + * + * Revision 1.5 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.4 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.3 2002/11/01 15:10:42 eilers + * Added regExp-search in database for all fields in a contact. + * + * Revision 1.2 2002/10/07 17:34:24 eilers + * added OBackendFactory for advanced backend access + * + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * ===================================================================== + * + */ + +#ifndef _OCONTACTACCESSBACKEND_H_ +#define _OCONTACTACCESSBACKEND_H_ + +#include "ocontact.h" +#include "opimaccessbackend.h" + +#include <qregexp.h> + +/** + * This class represents the interface of all Contact Backends. + * Derivates of this class will be used to access the contacts. + * As implementation currently XML and vCard exist. This class needs to be implemented + * if you want to provide your own storage. + * In all queries a list of uids is passed on instead of loading the actual record! + * + * @see OContactAccessBackend_VCard + * @see OContactAccessBackend_XML + */ +class OContactAccessBackend: public OPimAccessBackend<OContact> { + public: + /** + * @todo make non line in regard to BC guide of KDE + */ + OContactAccessBackend() {} + /** + * @todo make non inline in regard to the BC guide of KDE + */ + virtual ~OContactAccessBackend() {} + + + /** + * Return if database was changed externally. + * This may just make sense on file based databases like a XML-File. + * It is used to prevent to overwrite the current database content + * if the file was already changed by something else ! + * If this happens, we have to reload before save our data. + * If we use real databases, this should be handled by the database + * management system themselve, therefore this function should always return false in + * this case. It is not our problem to handle this conflict ... + * @return <i>true</i> if the database was changed and if save without reload will + * be dangerous. <i>false</i> if the database was not changed or it is save to write + * in this situation. + */ + virtual bool wasChangedExternally() = 0; + + virtual QArray<int> matchRegexp( const QRegExp &r ) const = 0; + + /** + * Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + virtual const uint querySettings() = 0; + + /** + * Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + virtual bool hasQuerySettings (uint querySettings) const = 0; + + /** + * FIXME!!! + * Returns a sorted list of records either ascendinf or descending for a giving criteria and category + */ + virtual QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ) = 0; + + +private: + class Private; + Private *d; +}; +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp new file mode 100644 index 0000000..669483d --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp @@ -0,0 +1,948 @@ +/* + * SQL Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.5 2004/03/14 13:50:35 alwin + * namespace correction + * + * Revision 1.4 2003/12/22 10:19:26 eilers + * Finishing implementation of sql-backend for datebook. But I have to + * port the PIM datebook application to use it, before I could debug the + * whole stuff. + * Thus, PIM-Database backend is finished, but highly experimental. And some + * parts are still generic. For instance, the "queryByExample()" methods are + * not (or not fully) implemented. Todo: custom-entries not stored. + * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular + * expression search in the database, which is not supported by sqlite ! + * Therefore we need either an extended sqlite or a workaround which would + * be very slow and memory consuming.. + * + * Revision 1.3 2003/12/08 15:18:10 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * + * Revision 1.2 2003/09/29 07:44:26 eilers + * Improvement of PIM-SQL Databases, but search queries are still limited. + * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space. + * Todo: Started to add new attributes. Some type conversions missing. + * + * Revision 1.1 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + */ + +#include "ocontactaccessbackend_sql.h" + +#include <qarray.h> +#include <qdatetime.h> +#include <qstringlist.h> + +#include <qpe/global.h> +#include <qpe/recordfields.h> + +#include <opie/ocontactfields.h> +#include <opie/oconversion.h> +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +using namespace Opie::DB; + + +// If defined, we use a horizontal table ( uid, attr1, attr2, attr3, ..., attrn ) instead +// vertical like "uid, type, value". +// DON'T DEACTIVATE THIS DEFINE IN PRODUCTIVE ENVIRONMENTS !! +#define __STORE_HORIZONTAL_ + +// Distinct loading is not very fast. If I expect that every person has just +// one (and always one) 'Last Name', I can request all uid's for existing lastnames, +// which is faster.. +// But this may not be true for all entries, like company contacts.. +// The current AddressBook application handles this problem, but other may not.. (eilers) +#define __USE_SUPERFAST_LOADQUERY + + +/* + * Implementation of used query types + * CREATE query + * LOAD query + * INSERT + * REMOVE + * CLEAR + */ +namespace { + /** + * CreateQuery for the Todolist Table + */ + class CreateQuery : public OSQLQuery { + public: + CreateQuery(); + ~CreateQuery(); + QString query()const; + }; + + /** + * Clears (delete) a Table + */ + class ClearQuery : public OSQLQuery { + public: + ClearQuery(); + ~ClearQuery(); + QString query()const; + + }; + + + /** + * LoadQuery + * this one queries for all uids + */ + class LoadQuery : public OSQLQuery { + public: + LoadQuery(); + ~LoadQuery(); + QString query()const; + }; + + /** + * inserts/adds a OContact to the table + */ + class InsertQuery : public OSQLQuery { + public: + InsertQuery(const OContact& ); + ~InsertQuery(); + QString query()const; + private: + OContact m_contact; + }; + + + /** + * removes one from the table + */ + class RemoveQuery : public OSQLQuery { + public: + RemoveQuery(int uid ); + ~RemoveQuery(); + QString query()const; + private: + int m_uid; + }; + + /** + * a find query for noncustom elements + */ + class FindQuery : public OSQLQuery { + public: + FindQuery(int uid); + FindQuery(const QArray<int>& ); + ~FindQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray<int> m_uids; + int m_uid; + }; + + /** + * a find query for custom elements + */ + class FindCustomQuery : public OSQLQuery { + public: + FindCustomQuery(int uid); + FindCustomQuery(const QArray<int>& ); + ~FindCustomQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray<int> m_uids; + int m_uid; + }; + + + + // We using three tables to store the information: + // 1. addressbook : It contains General information about the contact (non custom) + // 2. custom_data : Not official supported entries + // All tables are connected by the uid of the contact. + // Maybe I should add a table for meta-information ? + CreateQuery::CreateQuery() : OSQLQuery() {} + CreateQuery::~CreateQuery() {} + QString CreateQuery::query()const { + QString qu; +#ifdef __STORE_HORIZONTAL_ + + qu += "create table addressbook( uid PRIMARY KEY "; + + QStringList fieldList = OContactFields::untrfields( false ); + for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ + qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it ); + } + qu += " );"; + + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; + +#else + + qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));"; + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; +// qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );"; + +#endif // __STORE_HORIZONTAL_ + return qu; + } + + ClearQuery::ClearQuery() + : OSQLQuery() {} + ClearQuery::~ClearQuery() {} + QString ClearQuery::query()const { + QString qu = "drop table addressbook;"; + qu += "drop table custom_data;"; +// qu += "drop table dates;"; + return qu; + } + + + LoadQuery::LoadQuery() : OSQLQuery() {} + LoadQuery::~LoadQuery() {} + QString LoadQuery::query()const { + QString qu; +#ifdef __STORE_HORIZONTAL_ + qu += "select uid from addressbook"; +#else +# ifndef __USE_SUPERFAST_LOADQUERY + qu += "select distinct uid from addressbook"; +# else + qu += "select uid from addressbook where type = 'Last Name'"; +# endif // __USE_SUPERFAST_LOADQUERY +#endif // __STORE_HORIZONTAL_ + + return qu; + } + + + InsertQuery::InsertQuery( const OContact& contact ) + : OSQLQuery(), m_contact( contact ) { + } + + InsertQuery::~InsertQuery() { + } + + /* + * converts from a OContact to a query + */ + QString InsertQuery::query()const{ + +#ifdef __STORE_HORIZONTAL_ + QString qu; + qu += "insert into addressbook VALUES( " + + QString::number( m_contact.uid() ); + + // Get all information out of the contact-class + // Remember: The category is stored in contactMap, too ! + QMap<int, QString> contactMap = m_contact.toMap(); + + QStringList fieldList = OContactFields::untrfields( false ); + QMap<QString, int> translate = OContactFields::untrFieldsToId(); + for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ + // Convert Column-String to Id and get value for this id.. + // Hmmm.. Maybe not very cute solution.. + int id = translate[*it]; + switch ( id ){ + case Qtopia::Birthday:{ + // These entries should stored in a special format + // year-month-day + QDate day = m_contact.birthday(); + if ( day.isValid() ){ + qu += QString(",\"%1-%2-%3\"") + .arg( day.year() ) + .arg( day.month() ) + .arg( day.day() ); + } else { + qu += ",\"\""; + } + } + break; + case Qtopia::Anniversary:{ + // These entries should stored in a special format + // year-month-day + QDate day = m_contact.anniversary(); + if ( day.isValid() ){ + qu += QString(",\"%1-%2-%3\"") + .arg( day.year() ) + .arg( day.month() ) + .arg( day.day() ); + } else { + qu += ",\"\""; + } + } + break; + + default: + qu += QString( ",\"%1\"" ).arg( contactMap[id] ); + } + } + qu += " );"; + + +#else + // Get all information out of the contact-class + // Remember: The category is stored in contactMap, too ! + QMap<int, QString> contactMap = m_contact.toMap(); + + QMap<QString, QString> addressbook_db; + + // Get the translation from the ID to the String + QMap<int, QString> transMap = OContactFields::idToUntrFields(); + + for( QMap<int, QString>::Iterator it = contactMap.begin(); + it != contactMap.end(); ++it ){ + switch ( it.key() ){ + case Qtopia::Birthday:{ + // These entries should stored in a special format + // year-month-day + QDate day = m_contact.birthday(); + addressbook_db.insert( transMap[it.key()], + QString("%1-%2-%3") + .arg( day.year() ) + .arg( day.month() ) + .arg( day.day() ) ); + } + break; + case Qtopia::Anniversary:{ + // These entries should stored in a special format + // year-month-day + QDate day = m_contact.anniversary(); + addressbook_db.insert( transMap[it.key()], + QString("%1-%2-%3") + .arg( day.year() ) + .arg( day.month() ) + .arg( day.day() ) ); + } + break; + case Qtopia::AddressUid: // Ignore UID + break; + default: // Translate id to String + addressbook_db.insert( transMap[it.key()], it.data() ); + break; + } + + } + + // Now convert this whole stuff into a SQL String, beginning with + // the addressbook table.. + QString qu; + // qu += "begin transaction;"; + int id = 0; + for( QMap<QString, QString>::Iterator it = addressbook_db.begin(); + it != addressbook_db.end(); ++it ){ + qu += "insert into addressbook VALUES(" + + QString::number( m_contact.uid() ) + + "," + + QString::number( id++ ) + + ",'" + + it.key() //.latin1() + + "'," + + "0" // Priority for future enhancements + + ",'" + + it.data() //.latin1() + + "');"; + } + +#endif //__STORE_HORIZONTAL_ + // Now add custom data.. +#ifdef __STORE_HORIZONTAL_ + int id = 0; +#endif + id = 0; + QMap<QString, QString> customMap = m_contact.toExtraMap(); + for( QMap<QString, QString>::Iterator it = customMap.begin(); + it != customMap.end(); ++it ){ + qu += "insert into custom_data VALUES(" + + QString::number( m_contact.uid() ) + + "," + + QString::number( id++ ) + + ",'" + + it.key() //.latin1() + + "'," + + "0" // Priority for future enhancements + + ",'" + + it.data() //.latin1() + + "');"; + } + // qu += "commit;"; + qWarning("add %s", qu.latin1() ); + return qu; + } + + + RemoveQuery::RemoveQuery(int uid ) + : OSQLQuery(), m_uid( uid ) {} + RemoveQuery::~RemoveQuery() {} + QString RemoveQuery::query()const { + QString qu = "DELETE from addressbook where uid = " + + QString::number(m_uid) + ";"; + qu += "DELETE from custom_data where uid = " + + QString::number(m_uid) + ";"; + return qu; + } + + + + + FindQuery::FindQuery(int uid) + : OSQLQuery(), m_uid( uid ) { + } + FindQuery::FindQuery(const QArray<int>& ints) + : OSQLQuery(), m_uids( ints ){ + } + FindQuery::~FindQuery() { + } + QString FindQuery::query()const{ +// if ( m_uids.count() == 0 ) + return single(); + } + /* + else + return multi(); + } + QString FindQuery::multi()const { + QString qu = "select uid, type, value from addressbook where"; + for (uint i = 0; i < m_uids.count(); i++ ) { + qu += " UID = " + QString::number( m_uids[i] ) + " OR"; + } + qu.remove( qu.length()-2, 2 ); // Hmmmm.. + return qu; + } + */ +#ifdef __STORE_HORIZONTAL_ + QString FindQuery::single()const{ + QString qu = "select *"; + qu += " from addressbook where uid = " + QString::number(m_uid); + + // qWarning("find query: %s", qu.latin1() ); + return qu; + } +#else + QString FindQuery::single()const{ + QString qu = "select uid, type, value from addressbook where uid = "; + qu += QString::number(m_uid); + return qu; + } +#endif + + + FindCustomQuery::FindCustomQuery(int uid) + : OSQLQuery(), m_uid( uid ) { + } + FindCustomQuery::FindCustomQuery(const QArray<int>& ints) + : OSQLQuery(), m_uids( ints ){ + } + FindCustomQuery::~FindCustomQuery() { + } + QString FindCustomQuery::query()const{ +// if ( m_uids.count() == 0 ) + return single(); + } + QString FindCustomQuery::single()const{ + QString qu = "select uid, type, value from custom_data where uid = "; + qu += QString::number(m_uid); + return qu; + } + +}; + + +/* --------------------------------------------------------------------------- */ + +OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, + const QString& filename ): + OContactAccessBackend(), m_changed(false), m_driver( NULL ) +{ + qWarning("C'tor OContactAccessBackend_SQL starts"); + QTime t; + t.start(); + + /* Expecting to access the default filename if nothing else is set */ + if ( filename.isEmpty() ){ + m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); + } else + m_fileName = filename; + + // Get the standart sql-driver from the OSQLManager.. + OSQLManager man; + m_driver = man.standard(); + m_driver->setUrl( m_fileName ); + + load(); + + qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() ); +} + +OContactAccessBackend_SQL::~OContactAccessBackend_SQL () +{ + if( m_driver ) + delete m_driver; +} + +bool OContactAccessBackend_SQL::load () +{ + if (!m_driver->open() ) + return false; + + // Don't expect that the database exists. + // It is save here to create the table, even if it + // do exist. ( Is that correct for all databases ?? ) + CreateQuery creat; + OSQLResult res = m_driver->query( &creat ); + + update(); + + return true; + +} + +bool OContactAccessBackend_SQL::reload() +{ + return load(); +} + +bool OContactAccessBackend_SQL::save() +{ + return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) +} + + +void OContactAccessBackend_SQL::clear () +{ + ClearQuery cle; + OSQLResult res = m_driver->query( &cle ); + + reload(); +} + +bool OContactAccessBackend_SQL::wasChangedExternally() +{ + return false; +} + +QArray<int> OContactAccessBackend_SQL::allRecords() const +{ + + // FIXME: Think about cute handling of changed tables.. + // Thus, we don't have to call update here... + if ( m_changed ) + ((OContactAccessBackend_SQL*)this)->update(); + + return m_uids; +} + +bool OContactAccessBackend_SQL::add ( const OContact &newcontact ) +{ + InsertQuery ins( newcontact ); + OSQLResult res = m_driver->query( &ins ); + + if ( res.state() == OSQLResult::Failure ) + return false; + + int c = m_uids.count(); + m_uids.resize( c+1 ); + m_uids[c] = newcontact.uid(); + + return true; +} + + +bool OContactAccessBackend_SQL::remove ( int uid ) +{ + RemoveQuery rem( uid ); + OSQLResult res = m_driver->query(&rem ); + + if ( res.state() == OSQLResult::Failure ) + return false; + + m_changed = true; + + return true; +} + +bool OContactAccessBackend_SQL::replace ( const OContact &contact ) +{ + if ( !remove( contact.uid() ) ) + return false; + + return add( contact ); +} + + +OContact OContactAccessBackend_SQL::find ( int uid ) const +{ + qWarning("OContactAccessBackend_SQL::find()"); + QTime t; + t.start(); + + OContact retContact( requestNonCustom( uid ) ); + retContact.setExtraMap( requestCustom( uid ) ); + + qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() ); + return retContact; +} + + + +QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) +{ + QString qu = "SELECT uid FROM addressbook WHERE"; + + QMap<int, QString> queryFields = query.toMap(); + QStringList fieldList = OContactFields::untrfields( false ); + QMap<QString, int> translate = OContactFields::untrFieldsToId(); + + // Convert every filled field to a SQL-Query + bool isAnyFieldSelected = false; + for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ + int id = translate[*it]; + QString queryStr = queryFields[id]; + if ( !queryStr.isEmpty() ){ + isAnyFieldSelected = true; + switch( id ){ + default: + // Switching between case sensitive and insensitive... + // LIKE is not case sensitive, GLOB is case sensitive + // Do exist a better solution to switch this ? + if ( settings & OContactAccess::IgnoreCase ) + qu += "(\"" + *it + "\"" + " LIKE " + "'" + + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND "; + else + qu += "(\"" + *it + "\"" + " GLOB " + "'" + + queryStr + "'" + ") AND "; + + } + } + } + // Skip trailing "AND" + if ( isAnyFieldSelected ) + qu = qu.left( qu.length() - 4 ); + + qWarning( "queryByExample query: %s", qu.latin1() ); + + // Execute query and return the received uid's + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + QArray<int> empty; + return empty; + } + + QArray<int> list = extractUids( res ); + + return list; +} + +QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + QArray<int> nix(0); + return nix; +} + +const uint OContactAccessBackend_SQL::querySettings() +{ + return OContactAccess::IgnoreCase + || OContactAccess::WildCards; +} + +bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const +{ + /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay + * may be added with any of the other settings. IgnoreCase should never used alone. + * Wildcards, RegExp, ExactMatch should never used at the same time... + */ + + // Step 1: Check whether the given settings are supported by this backend + if ( ( querySettings & ( + OContactAccess::IgnoreCase + | OContactAccess::WildCards +// | OContactAccess::DateDiff +// | OContactAccess::DateYear +// | OContactAccess::DateMonth +// | OContactAccess::DateDay +// | OContactAccess::RegExp +// | OContactAccess::ExactMatch + ) ) != querySettings ) + return false; + + // Step 2: Check whether the given combinations are ok.. + + // IngoreCase alone is invalid + if ( querySettings == OContactAccess::IgnoreCase ) + return false; + + // WildCards, RegExp and ExactMatch should never used at the same time + switch ( querySettings & ~( OContactAccess::IgnoreCase + | OContactAccess::DateDiff + | OContactAccess::DateYear + | OContactAccess::DateMonth + | OContactAccess::DateDay + ) + ){ + case OContactAccess::RegExp: + return ( true ); + case OContactAccess::WildCards: + return ( true ); + case OContactAccess::ExactMatch: + return ( true ); + case 0: // one of the upper removed bits were set.. + return ( true ); + default: + return ( false ); + } + +} + +QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int ) +{ + QTime t; + t.start(); + +#ifdef __STORE_HORIZONTAL_ + QString query = "SELECT uid FROM addressbook "; + query += "ORDER BY \"Last Name\" "; +#else + QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' "; + query += "ORDER BY upper( value )"; +#endif + + if ( !asc ) + query += "DESC"; + + // qWarning("sorted query is: %s", query.latin1() ); + + OSQLRawQuery raw( query ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + QArray<int> empty; + return empty; + } + + QArray<int> list = extractUids( res ); + + qWarning("sorted needed %d ms!", t.elapsed() ); + return list; +} + + +void OContactAccessBackend_SQL::update() +{ + qWarning("Update starts"); + QTime t; + t.start(); + + // Now load the database set and extract the uid's + // which will be held locally + + LoadQuery lo; + OSQLResult res = m_driver->query(&lo); + if ( res.state() != OSQLResult::Success ) + return; + + m_uids = extractUids( res ); + + m_changed = false; + + qWarning("Update ends %d ms", t.elapsed() ); +} + +QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const +{ + qWarning("extractUids"); + QTime t; + t.start(); + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray<int> ints(list.count() ); + qWarning(" count = %d", list.count() ); + + int i = 0; + for (it = list.begin(); it != list.end(); ++it ) { + ints[i] = (*it).data("uid").toInt(); + i++; + } + qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); + + return ints; + +} + +#ifdef __STORE_HORIZONTAL_ +QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const +{ + QTime t; + t.start(); + + QMap<int, QString> nonCustomMap; + + int t2needed = 0; + int t3needed = 0; + QTime t2; + t2.start(); + FindQuery query( uid ); + OSQLResult res_noncustom = m_driver->query( &query ); + t2needed = t2.elapsed(); + + OSQLResultItem resItem = res_noncustom.first(); + + QTime t3; + t3.start(); + // Now loop through all columns + QStringList fieldList = OContactFields::untrfields( false ); + QMap<QString, int> translate = OContactFields::untrFieldsToId(); + for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ + // Get data for the selected column and store it with the + // corresponding id into the map.. + + int id = translate[*it]; + QString value = resItem.data( (*it) ); + + // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() ); + + switch( id ){ + case Qtopia::Birthday: + case Qtopia::Anniversary:{ + // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) + QStringList list = QStringList::split( '-', value ); + QStringList::Iterator lit = list.begin(); + int year = (*lit).toInt(); + int month = (*(++lit)).toInt(); + int day = (*(++lit)).toInt(); + if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){ + QDate date( year, month, day ); + nonCustomMap.insert( id, OConversion::dateToString( date ) ); + } + } + break; + case Qtopia::AddressCategory: + qWarning("Category is: %s", value.latin1() ); + default: + nonCustomMap.insert( id, value ); + } + } + + // First insert uid + nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) ); + t3needed = t3.elapsed(); + + // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() ); + qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", + t.elapsed(), t2needed, t3needed ); + + return nonCustomMap; +} +#else + +QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const +{ + QTime t; + t.start(); + + QMap<int, QString> nonCustomMap; + + int t2needed = 0; + QTime t2; + t2.start(); + FindQuery query( uid ); + OSQLResult res_noncustom = m_driver->query( &query ); + t2needed = t2.elapsed(); + + if ( res_noncustom.state() == OSQLResult::Failure ) { + qWarning("OSQLResult::Failure in find query !!"); + QMap<int, QString> empty; + return empty; + } + + int t3needed = 0; + QTime t3; + t3.start(); + QMap<QString, int> translateMap = OContactFields::untrFieldsToId(); + + OSQLResultItem::ValueList list = res_noncustom.results(); + OSQLResultItem::ValueList::Iterator it = list.begin(); + for ( ; it != list.end(); ++it ) { + if ( (*it).data("type") != "" ){ + int typeId = translateMap[(*it).data( "type" )]; + switch( typeId ){ + case Qtopia::Birthday: + case Qtopia::Anniversary:{ + // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) + QStringList list = QStringList::split( '-', (*it).data( "value" ) ); + QStringList::Iterator lit = list.begin(); + int year = (*lit).toInt(); + qWarning("1. %s", (*lit).latin1()); + int month = (*(++lit)).toInt(); + qWarning("2. %s", (*lit).latin1()); + int day = (*(++lit)).toInt(); + qWarning("3. %s", (*lit).latin1()); + qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day ); + QDate date( year, month, day ); + nonCustomMap.insert( typeId, OConversion::dateToString( date ) ); + } + break; + default: + nonCustomMap.insert( typeId, + (*it).data( "value" ) ); + } + } + } + // Add UID to Map.. + nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) ); + t3needed = t3.elapsed(); + + qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed ); + return nonCustomMap; +} + +#endif // __STORE_HORIZONTAL_ + +QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const +{ + QTime t; + t.start(); + + QMap<QString, QString> customMap; + + FindCustomQuery query( uid ); + OSQLResult res_custom = m_driver->query( &query ); + + if ( res_custom.state() == OSQLResult::Failure ) { + qWarning("OSQLResult::Failure in find query !!"); + QMap<QString, QString> empty; + return empty; + } + + OSQLResultItem::ValueList list = res_custom.results(); + OSQLResultItem::ValueList::Iterator it = list.begin(); + for ( ; it != list.end(); ++it ) { + customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); + } + + qWarning("RequestCustom needed: %d ms", t.elapsed() ); + return customMap; +} diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h new file mode 100644 index 0000000..8cd92e8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h @@ -0,0 +1,110 @@ +/* + * SQL Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.3 2004/03/14 13:50:35 alwin + * namespace correction + * + * Revision 1.2 2003/12/08 15:18:11 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * + * Revision 1.1 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + * + */ + +#ifndef _OContactAccessBackend_SQL_ +#define _OContactAccessBackend_SQL_ + +#include "ocontactaccessbackend.h" +#include "ocontactaccess.h" + +#include <qlist.h> +#include <qdict.h> + +namespace Opie { namespace DB { +class OSQLDriver; +class OSQLResult; +class OSQLResultItem; + +}} + +/* the default xml implementation */ +/** + * This class is the SQL implementation of a Contact backend + * it does implement everything available for OContact. + * @see OPimAccessBackend for more information of available methods + */ +class OContactAccessBackend_SQL : public OContactAccessBackend { + public: + OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); + + ~OContactAccessBackend_SQL (); + + bool save(); + + bool load (); + + void clear (); + + bool wasChangedExternally(); + + QArray<int> allRecords() const; + + OContact find ( int uid ) const; + // FIXME: Add lookahead-cache support ! + //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; + + QArray<int> queryByExample ( const OContact &query, int settings, + const QDateTime& d ); + + QArray<int> matchRegexp( const QRegExp &r ) const; + + const uint querySettings(); + + bool hasQuerySettings (uint querySettings) const; + + // Currently only asc implemented.. + QArray<int> sorted( bool asc, int , int , int ); + bool add ( const OContact &newcontact ); + + bool replace ( const OContact &contact ); + + bool remove ( int uid ); + bool reload(); + + private: + QArray<int> extractUids( Opie::DB::OSQLResult& res ) const; + QMap<int, QString> requestNonCustom( int uid ) const; + QMap<QString, QString> requestCustom( int uid ) const; + void update(); + + protected: + bool m_changed; + QString m_fileName; + QArray<int> m_uids; + + Opie::DB::OSQLDriver* m_driver; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp new file mode 100644 index 0000000..a795b56 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp @@ -0,0 +1,649 @@ +/* + * VCard Backend for the OPIE-Contact Database. + * + * Copyright (C) 2000 Trolltech AS. All rights reserved. + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ToDo: + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.11 2003/08/01 12:30:16 eilers + * Merging changes from BRANCH_1_0 to HEAD + * + * Revision 1.10.4.3 2003/07/23 08:54:37 eilers + * Default email was added to the list of all emails, which already contains + * the default email.. + * This closes bug #1045 + * + * Revision 1.10.4.2 2003/07/23 08:44:45 eilers + * Importing of Notes in vcard files wasn't implemented. + * Closes bug #1044 + * + * Revision 1.10.4.1 2003/06/02 13:37:49 eilers + * Fixing memory leak + * + * Revision 1.10 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.9 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.8 2003/02/21 16:52:49 zecke + * -Remove old Todo classes they're deprecated and today I already using the + * new API + * -Guard against self assignment in OTodo + * -Add test apps for OPIM + * -Opiefied Event classes + * -Added TimeZone handling and pinning of TimeZones to OEvent + * -Adjust ORecur and the widget to better timezone behaviour + * + * Revision 1.7 2003/02/16 22:25:46 zecke + * 0000276 Fix for that bug.. or better temp workaround + * A Preferred Number is HOME|VOICE + * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test + * triggers both + * and the cell phone number overrides the other entries.. + * + * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the + * number + * + * The right and final fix would be to reorder the if statement to make it + * if else based and the less common thing put to the bottom + * + * OTodoAccessVcal fix the date for beaming + * + * Revision 1.6 2003/01/13 15:49:31 eilers + * Fixing crash when businesscard.vcf is missing.. + * + * Revision 1.5 2002/12/07 13:26:22 eilers + * Fixing bug in storing anniversary.. + * + * Revision 1.4 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.3 2002/11/11 16:41:09 kergoth + * no default arguments in implementation + * + * Revision 1.2 2002/11/10 15:41:53 eilers + * Bugfixes.. + * + * Revision 1.1 2002/11/09 14:34:52 eilers + * Added VCard Backend. + * + */ +#include "ocontactaccessbackend_vcard.h" +#include "../../library/backend/vobject_p.h" +#include "../../library/backend/qfiledirect_p.h" + +#include <qpe/timeconversion.h> + +#include <qfile.h> + +OContactAccessBackend_VCard::OContactAccessBackend_VCard ( const QString& , const QString& filename ): + m_dirty( false ), + m_file( filename ) +{ + load(); +} + + +bool OContactAccessBackend_VCard::load () +{ + m_map.clear(); + m_dirty = false; + + VObject* obj = 0l; + + if ( QFile::exists(m_file) ){ + obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); + if ( !obj ) + return false; + }else{ + qWarning("File \"%s\" not found !", m_file.latin1() ); + return false; + } + + while ( obj ) { + OContact con = parseVObject( obj ); + /* + * if uid is 0 assign a new one + * this at least happens on + * Nokia6210 + */ + if ( con.uid() == 0 ){ + con.setUid( 1 ); + qWarning("assigned new uid %d",con.uid() ); + } + + m_map.insert( con.uid(), con ); + + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return true; + +} +bool OContactAccessBackend_VCard::reload() +{ + return load(); +} +bool OContactAccessBackend_VCard::save() +{ + if (!m_dirty ) + return true; + + QFileDirect file( m_file ); + if (!file.open(IO_WriteOnly ) ) + return false; + + VObject *obj; + obj = newVObject( VCCalProp ); + addPropValue( obj, VCVersionProp, "1.0" ); + + VObject *vo; + for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ + vo = createVObject( *it ); + writeVObject( file.directHandle() , vo ); + cleanVObject( vo ); + } + cleanStrTbl(); + deleteVObject( obj ); + + m_dirty = false; + return true; + + +} +void OContactAccessBackend_VCard::clear () +{ + m_map.clear(); + m_dirty = true; // ??? sure ? (se) +} + +bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) +{ + m_map.insert( newcontact.uid(), newcontact ); + m_dirty = true; + return true; +} + +bool OContactAccessBackend_VCard::remove ( int uid ) +{ + m_map.remove( uid ); + m_dirty = true; + return true; +} + +bool OContactAccessBackend_VCard::replace ( const OContact &contact ) +{ + m_map.replace( contact.uid(), contact ); + m_dirty = true; + return true; +} + +OContact OContactAccessBackend_VCard::find ( int uid ) const +{ + return m_map[uid]; +} + +QArray<int> OContactAccessBackend_VCard::allRecords() const +{ + QArray<int> ar( m_map.count() ); + QMap<int, OContact>::ConstIterator it; + int i = 0; + for ( it = m_map.begin(); it != m_map.end(); ++it ) { + ar[i] = it.key(); + i++; + } + return ar; +} + +// Not implemented +QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& ) +{ + QArray<int> ar(0); + return ar; +} + +// Not implemented +QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const +{ + QArray<int> ar(0); + return ar; +} + +const uint OContactAccessBackend_VCard::querySettings() +{ + return 0; // No search possible +} + +bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const +{ + return false; // No search possible, therefore all settings invalid ;) +} + +bool OContactAccessBackend_VCard::wasChangedExternally() +{ + return false; // Don't expect concurrent access +} + +// Not implemented +QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int ) +{ + QArray<int> ar(0); + return ar; +} + +// *** Private stuff *** + + +OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) +{ + OContact c; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCNameProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCNamePrefixesProp ) + c.setTitle( value ); + else if ( name == VCNameSuffixesProp ) + c.setSuffix( value ); + else if ( name == VCFamilyNameProp ) + c.setLastName( value ); + else if ( name == VCGivenNameProp ) + c.setFirstName( value ); + else if ( name == VCAdditionalNamesProp ) + c.setMiddleName( value ); + } + } + else if ( name == VCAdrProp ) { + bool work = TRUE; // default address is work address + QString street; + QString city; + QString region; + QString postal; + QString country; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCHomeProp ) + work = FALSE; + else if ( name == VCWorkProp ) + work = TRUE; + else if ( name == VCStreetAddressProp ) + street = value; + else if ( name == VCCityProp ) + city = value; + else if ( name == VCRegionProp ) + region = value; + else if ( name == VCPostalCodeProp ) + postal = value; + else if ( name == VCCountryNameProp ) + country = value; + } + if ( work ) { + c.setBusinessStreet( street ); + c.setBusinessCity( city ); + c.setBusinessCountry( country ); + c.setBusinessZip( postal ); + c.setBusinessState( region ); + } else { + c.setHomeStreet( street ); + c.setHomeCity( city ); + c.setHomeCountry( country ); + c.setHomeZip( postal ); + c.setHomeState( region ); + } + } + else if ( name == VCTelephoneProp ) { + enum { + HOME = 0x01, + WORK = 0x02, + VOICE = 0x04, + CELL = 0x08, + FAX = 0x10, + PAGER = 0x20, + UNKNOWN = 0x80 + }; + int type = 0; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + type |= HOME; + else if ( name == VCWorkProp ) + type |= WORK; + else if ( name == VCVoiceProp ) + type |= VOICE; + else if ( name == VCCellularProp ) + type |= CELL; + else if ( name == VCFaxProp ) + type |= FAX; + else if ( name == VCPagerProp ) + type |= PAGER; + else if ( name == VCPreferredProp ) + ; + else + type |= UNKNOWN; + } + if ( (type & UNKNOWN) != UNKNOWN ) { + if ( ( type & (HOME|WORK) ) == 0 ) // default + type |= HOME; + if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default + type |= VOICE; + + qWarning("value %s %d", value.data(), type ); + if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) + c.setHomePhone( value ); + if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) + c.setHomeFax( value ); + if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) + c.setHomeMobile( value ); + if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) + c.setBusinessPhone( value ); + if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) + c.setBusinessFax( value ); + if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) + c.setBusinessMobile( value ); + if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) + c.setBusinessPager( value ); + } + } + else if ( name == VCEmailAddressProp ) { + QString email = vObjectStringZValue( o ); + bool valid = TRUE; + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name != VCInternetProp && name != VCHomeProp && + name != VCWorkProp && + name != VCPreferredProp ) + // ### preffered should map to default email + valid = FALSE; + } + if ( valid ) { + c.insertEmail( email ); + } + } + else if ( name == VCURLProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + c.setHomeWebpage( value ); + else if ( name == VCWorkProp ) + c.setBusinessWebpage( value ); + } + } + else if ( name == VCOrgProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCOrgNameProp ) + c.setCompany( value ); + else if ( name == VCOrgUnitProp ) + c.setDepartment( value ); + else if ( name == VCOrgUnit2Prop ) + c.setOffice( value ); + } + } + else if ( name == VCTitleProp ) { + c.setJobTitle( value ); + } + else if ( name == "X-Qtopia-Profession" ) { + c.setProfession( value ); + } + else if ( name == "X-Qtopia-Manager" ) { + c.setManager( value ); + } + else if ( name == "X-Qtopia-Assistant" ) { + c.setAssistant( value ); + } + else if ( name == "X-Qtopia-Spouse" ) { + c.setSpouse( value ); + } + else if ( name == "X-Qtopia-Gender" ) { + c.setGender( value ); + } + else if ( name == "X-Qtopia-Anniversary" ) { + c.setAnniversary( convVCardDateToDate( value ) ); + } + else if ( name == "X-Qtopia-Nickname" ) { + c.setNickname( value ); + } + else if ( name == "X-Qtopia-Children" ) { + c.setChildren( value ); + } + else if ( name == VCBirthDateProp ) { + // Reading Birthdate regarding RFC 2425 (5.8.4) + c.setBirthday( convVCardDateToDate( value ) ); + + } + else if ( name == VCCommentProp ) { + c.setNotes( value ); + } +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + c.setFileAs(); + return c; +} + + +VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) +{ + VObject *vcard = newVObject( VCCardProp ); + safeAddPropValue( vcard, VCVersionProp, "2.1" ); + safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); + safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); + + // full name + safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); + + // name properties + VObject *name = safeAddProp( vcard, VCNameProp ); + safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); + safeAddPropValue( name, VCGivenNameProp, c.firstName() ); + safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); + safeAddPropValue( name, VCNamePrefixesProp, c.title() ); + safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); + + // home properties + VObject *home_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( home_adr, VCHomeProp ); + safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); + safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); + safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); + safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); + safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); + + VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); + safeAddProp( home_phone, VCHomeProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCCellularProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCFaxProp ); + + VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); + safeAddProp( url, VCHomeProp ); + + // work properties + VObject *work_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( work_adr, VCWorkProp ); + safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); + safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); + safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); + safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); + safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); + + VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); + safeAddProp( work_phone, VCWorkProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCCellularProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCFaxProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCPagerProp ); + + url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); + safeAddProp( url, VCWorkProp ); + + VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); + safeAddProp( title, VCWorkProp ); + + + QStringList emails = c.emailList(); + // emails.prepend( c.defaultEmail() ); Fix for bugreport #1045 + for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { + VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); + safeAddProp( email, VCInternetProp ); + } + + safeAddPropValue( vcard, VCNoteProp, c.notes() ); + + // Exporting Birthday regarding RFC 2425 (5.8.4) + if ( c.birthday().isValid() ){ + qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() ); + safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); + } + + if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { + VObject *org = safeAddProp( vcard, VCOrgProp ); + safeAddPropValue( org, VCOrgNameProp, c.company() ); + safeAddPropValue( org, VCOrgUnitProp, c.department() ); + safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); + } + + // some values we have to export as custom fields + safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); + safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); + safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); + + safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); + safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); + if ( c.anniversary().isValid() ){ + qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() ); + safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); + } + safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); + safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); + + return vcard; +} + +QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const +{ + QString str_rfc2425 = QString("%1-%2-%3") + .arg( d.year() ) + .arg( d.month(), 2 ) + .arg( d.day(), 2 ); + // Now replace spaces with "0"... + int pos = 0; + while ( ( pos = str_rfc2425.find (' ') ) > 0 ) + str_rfc2425.replace( pos, 1, "0" ); + + return str_rfc2425; +} + +QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) +{ + int monthPos = datestr.find('-'); + int dayPos = datestr.find('-', monthPos+1 ); + int sep_ignore = 1; + if ( monthPos == -1 || dayPos == -1 ) { + qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); + // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) + if ( datestr.length() == 8 ){ + monthPos = 4; + dayPos = 6; + sep_ignore = 0; + qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); + } else { + return QDate(); + } + } + int y = datestr.left( monthPos ).toInt(); + int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); + int d = datestr.mid( dayPos + sep_ignore ).toInt(); + qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); + QDate date ( y,m,d ); + return date; +} + +VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h new file mode 100644 index 0000000..6dbc718 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h @@ -0,0 +1,99 @@ +/* + * VCard Backend for the OPIE-Contact Database. + * + * Copyright (C) 2000 Trolltech AS. All rights reserved. + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ToDo: + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.6 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.5 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.4 2002/12/07 13:26:22 eilers + * Fixing bug in storing anniversary.. + * + * Revision 1.3 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.2 2002/11/10 15:41:53 eilers + * Bugfixes.. + * + * Revision 1.1 2002/11/09 14:34:52 eilers + * Added VCard Backend. + * + */ +#ifndef __OCONTACTACCESSBACKEND_VCARD_H_ +#define __OCONTACTACCESSBACKEND_VCARD_H_ + +#include <opie/ocontact.h> + +#include "ocontactaccessbackend.h" + +class VObject; + +/** + * This is the vCard 2.1 implementation of the Contact Storage + * @see OContactAccessBackend_XML + * @see OPimAccessBackend + */ +class OContactAccessBackend_VCard : public OContactAccessBackend { + public: + OContactAccessBackend_VCard ( const QString& appname, const QString& filename = QString::null ); + + bool load (); + bool reload(); + bool save(); + void clear (); + + bool add ( const OContact& newcontact ); + bool remove ( int uid ); + bool replace ( const OContact& contact ); + + OContact find ( int uid ) const; + QArray<int> allRecords() const; + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); + QArray<int> matchRegexp( const QRegExp &r ) const; + + const uint querySettings(); + bool hasQuerySettings (uint querySettings) const; + QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); + bool wasChangedExternally(); + +private: + OContact parseVObject( VObject* obj ); + VObject* createVObject( const OContact& c ); + QString convDateToVCardDate( const QDate& c ) const; + QDate convVCardDateToDate( const QString& datestr ); + VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); + VObject *safeAddProp( VObject* o, const char* prop); + + bool m_dirty : 1; + QString m_file; + QMap<int, OContact> m_map; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp new file mode 100644 index 0000000..7ceaf5b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp @@ -0,0 +1,824 @@ +/* + * XML Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.10 2004/03/01 15:44:36 chicken + * fix includes + * + * Revision 1.9 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + * Revision 1.8 2003/08/30 15:28:26 eilers + * Removed some unimportant debug output which causes slow down.. + * + * Revision 1.7 2003/08/01 12:30:16 eilers + * Merging changes from BRANCH_1_0 to HEAD + * + * Revision 1.6 2003/07/07 16:19:47 eilers + * Fixing serious bug in hasQuerySettings() + * + * Revision 1.5 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.4 2003/03/21 14:32:54 mickeyl + * g++ compliance fix: default arguments belong into the declaration, but not the definition + * + * Revision 1.3 2003/03/21 12:26:28 eilers + * Fixing small bug: If we search a birthday from today to today, it returned + * every contact .. + * + * Revision 1.2 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.1.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.1.2.1 2003/02/10 15:31:38 eilers + * Writing offsets to debug output.. + * + * Revision 1.1 2003/02/09 15:05:01 eilers + * Nothing happened.. Just some cleanup before I will start.. + * + * Revision 1.12 2003/01/03 16:58:03 eilers + * Reenable debug output + * + * Revision 1.11 2003/01/03 12:31:28 eilers + * Bugfix for calculating data diffs.. + * + * Revision 1.10 2003/01/02 14:27:12 eilers + * Improved query by example: Search by date is possible.. First step + * for a today plugin for birthdays.. + * + * Revision 1.9 2002/12/08 12:48:57 eilers + * Moved journal-enum from ocontact into i the xml-backend.. + * + * Revision 1.8 2002/11/14 17:04:24 eilers + * Sorting will now work if fullname is identical on some entries + * + * Revision 1.7 2002/11/13 15:02:46 eilers + * Small Bug in sorted fixed + * + * Revision 1.6 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.5 2002/11/01 15:10:42 eilers + * Added regExp-search in database for all fields in a contact. + * + * Revision 1.4 2002/10/16 10:52:40 eilers + * Added some docu to the interface and now using the cache infrastucture by zecke.. :) + * + * Revision 1.3 2002/10/14 16:21:54 eilers + * Some minor interface updates + * + * Revision 1.2 2002/10/07 17:34:24 eilers + * added OBackendFactory for advanced backend access + * + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * + */ + +#include "ocontactaccessbackend_xml.h" + +#include <qasciidict.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qarray.h> +#include <qmap.h> + +#include <qpe/global.h> + +#include <opie/xmltree.h> +#include "ocontactaccessbackend.h" +#include "ocontactaccess.h" + +#include <stdlib.h> +#include <errno.h> + +using namespace Opie; + + +OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ): + m_changed( false ) +{ + // Just m_contactlist should call delete if an entry + // is removed. + m_contactList.setAutoDelete( true ); + m_uidToContact.setAutoDelete( false ); + + m_appName = appname; + + /* Set journalfile name ... */ + m_journalName = getenv("HOME"); + m_journalName +="/.abjournal" + appname; + + /* Expecting to access the default filename if nothing else is set */ + if ( filename.isEmpty() ){ + m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); + } else + m_fileName = filename; + + /* Load Database now */ + load (); +} + +bool OContactAccessBackend_XML::save() +{ + + if ( !m_changed ) + return true; + + QString strNewFile = m_fileName + ".new"; + QFile f( strNewFile ); + if ( !f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + int total_written; + int idx_offset = 0; + QString out; + + // Write Header + out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" + " <Groups>\n" + " </Groups>\n" + " <Contacts>\n"; + QCString cstr = out.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + idx_offset += cstr.length(); + out = ""; + + // Write all contacts + QListIterator<OContact> it( m_contactList ); + for ( ; it.current(); ++it ) { + // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); + out += "<Contact "; + (*it)->save( out ); + out += "/>\n"; + cstr = out.utf8(); + total_written = f.writeBlock( cstr.data(), cstr.length() ); + idx_offset += cstr.length(); + if ( total_written != int(cstr.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + out = ""; + } + out += " </Contacts>\n</AddressBook>\n"; + + // Write Footer + cstr = out.utf8(); + total_written = f.writeBlock( cstr.data(), cstr.length() ); + if ( total_written != int( cstr.length() ) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + f.close(); + + // move the file over, I'm just going to use the system call + // because, I don't feel like using QDir. + if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { + qWarning( "problem renaming file %s to %s, errno: %d", + strNewFile.latin1(), m_journalName.latin1(), errno ); + // remove the tmp file... + QFile::remove( strNewFile ); + } + + /* The journalfile should be removed now... */ + removeJournal(); + + m_changed = false; + return true; +} + +bool OContactAccessBackend_XML::load () +{ + m_contactList.clear(); + m_uidToContact.clear(); + + /* Load XML-File and journal if it exists */ + if ( !load ( m_fileName, false ) ) + return false; + /* The returncode of the journalfile is ignored due to the + * fact that it does not exist when this class is instantiated ! + * But there may such a file exist, if the application crashed. + * Therefore we try to load it to get the changes before the # + * crash happened... + */ + load (m_journalName, true); + + return true; +} + +void OContactAccessBackend_XML::clear () +{ + m_contactList.clear(); + m_uidToContact.clear(); + + m_changed = false; +} + +bool OContactAccessBackend_XML::wasChangedExternally() +{ + QFileInfo fi( m_fileName ); + + QDateTime lastmod = fi.lastModified (); + + return (lastmod != m_readtime); +} + +QArray<int> OContactAccessBackend_XML::allRecords() const +{ + QArray<int> uid_list( m_contactList.count() ); + + uint counter = 0; + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + uid_list[counter++] = (*it)->uid(); + } + + return ( uid_list ); +} + +OContact OContactAccessBackend_XML::find ( int uid ) const +{ + OContact foundContact; //Create empty contact + + OContact* found = m_uidToContact.find( QString().setNum( uid ) ); + + if ( found ){ + foundContact = *found; + } + + return ( foundContact ); +} + +QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, + const QDateTime& d ) +{ + + QArray<int> m_currentQuery( m_contactList.count() ); + QListIterator<OContact> it( m_contactList ); + uint arraycounter = 0; + + for( ; it.current(); ++it ){ + /* Search all fields and compare them with query object. Store them into list + * if all fields matches. + */ + QDate* queryDate = 0l; + QDate* checkDate = 0l; + bool allcorrect = true; + for ( int i = 0; i < Qtopia::Groups; i++ ) { + // Birthday and anniversary are special nonstring fields and should + // be handled specially + switch ( i ){ + case Qtopia::Birthday: + queryDate = new QDate( query.birthday() ); + checkDate = new QDate( (*it)->birthday() ); + case Qtopia::Anniversary: + if ( queryDate == 0l ){ + queryDate = new QDate( query.anniversary() ); + checkDate = new QDate( (*it)->anniversary() ); + } + + if ( queryDate->isValid() ){ + if( checkDate->isValid() ){ + if ( settings & OContactAccess::DateYear ){ + if ( queryDate->year() != checkDate->year() ) + allcorrect = false; + } + if ( settings & OContactAccess::DateMonth ){ + if ( queryDate->month() != checkDate->month() ) + allcorrect = false; + } + if ( settings & OContactAccess::DateDay ){ + if ( queryDate->day() != checkDate->day() ) + allcorrect = false; + } + if ( settings & OContactAccess::DateDiff ) { + QDate current; + // If we get an additional date, we + // will take this date instead of + // the current one.. + if ( !d.date().isValid() ) + current = QDate::currentDate(); + else + current = d.date(); + + // We have to equalize the year, otherwise + // the search will fail.. + checkDate->setYMD( current.year(), + checkDate->month(), + checkDate->day() ); + if ( *checkDate < current ) + checkDate->setYMD( current.year()+1, + checkDate->month(), + checkDate->day() ); + + // Check whether the birthday/anniversary date is between + // the current/given date and the maximum date + // ( maximum time range ) ! + qWarning("Checking if %s is between %s and %s ! ", + checkDate->toString().latin1(), + current.toString().latin1(), + queryDate->toString().latin1() ); + if ( current.daysTo( *queryDate ) >= 0 ){ + if ( !( ( *checkDate >= current ) && + ( *checkDate <= *queryDate ) ) ){ + allcorrect = false; + qWarning (" Nope!.."); + } + } + } + } else{ + // checkDate is invalid. Therefore this entry is always rejected + allcorrect = false; + } + } + + delete queryDate; + queryDate = 0l; + delete checkDate; + checkDate = 0l; + break; + default: + /* Just compare fields which are not empty in the query object */ + if ( !query.field(i).isEmpty() ){ + switch ( settings & ~( OContactAccess::IgnoreCase + | OContactAccess::DateDiff + | OContactAccess::DateYear + | OContactAccess::DateMonth + | OContactAccess::DateDay + | OContactAccess::MatchOne + ) ){ + + case OContactAccess::RegExp:{ + QRegExp expr ( query.field(i), + !(settings & OContactAccess::IgnoreCase), + false ); + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) + allcorrect = false; + } + break; + case OContactAccess::WildCards:{ + QRegExp expr ( query.field(i), + !(settings & OContactAccess::IgnoreCase), + true ); + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) + allcorrect = false; + } + break; + case OContactAccess::ExactMatch:{ + if (settings & OContactAccess::IgnoreCase){ + if ( query.field(i).upper() != + (*it)->field(i).upper() ) + allcorrect = false; + }else{ + if ( query.field(i) != (*it)->field(i) ) + allcorrect = false; + } + } + break; + } + } + } + } + if ( allcorrect ){ + m_currentQuery[arraycounter++] = (*it)->uid(); + } + } + + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; +} + +QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const +{ + QArray<int> m_currentQuery( m_contactList.count() ); + QListIterator<OContact> it( m_contactList ); + uint arraycounter = 0; + + for( ; it.current(); ++it ){ + if ( (*it)->match( r ) ){ + m_currentQuery[arraycounter++] = (*it)->uid(); + } + + } + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; +} + +const uint OContactAccessBackend_XML::querySettings() +{ + return ( OContactAccess::WildCards + | OContactAccess::IgnoreCase + | OContactAccess::RegExp + | OContactAccess::ExactMatch + | OContactAccess::DateDiff + | OContactAccess::DateYear + | OContactAccess::DateMonth + | OContactAccess::DateDay + ); +} + +bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const +{ + /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay + * may be added with any of the other settings. IgnoreCase should never used alone. + * Wildcards, RegExp, ExactMatch should never used at the same time... + */ + + // Step 1: Check whether the given settings are supported by this backend + if ( ( querySettings & ( + OContactAccess::IgnoreCase + | OContactAccess::WildCards + | OContactAccess::DateDiff + | OContactAccess::DateYear + | OContactAccess::DateMonth + | OContactAccess::DateDay + | OContactAccess::RegExp + | OContactAccess::ExactMatch + ) ) != querySettings ) + return false; + + // Step 2: Check whether the given combinations are ok.. + + // IngoreCase alone is invalid + if ( querySettings == OContactAccess::IgnoreCase ) + return false; + + // WildCards, RegExp and ExactMatch should never used at the same time + switch ( querySettings & ~( OContactAccess::IgnoreCase + | OContactAccess::DateDiff + | OContactAccess::DateYear + | OContactAccess::DateMonth + | OContactAccess::DateDay + ) + ){ + case OContactAccess::RegExp: + return ( true ); + case OContactAccess::WildCards: + return ( true ); + case OContactAccess::ExactMatch: + return ( true ); + case 0: // one of the upper removed bits were set.. + return ( true ); + default: + return ( false ); + } +} + +// Currently only asc implemented.. +QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) +{ + QMap<QString, int> nameToUid; + QStringList names; + QArray<int> m_currentQuery( m_contactList.count() ); + + // First fill map and StringList with all Names + // Afterwards sort namelist and use map to fill array to return.. + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); + nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); + } + names.sort(); + + int i = 0; + if ( asc ){ + for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) + m_currentQuery[i++] = nameToUid[ (*it) ]; + }else{ + for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) + m_currentQuery[i++] = nameToUid[ (*it) ]; + } + + return m_currentQuery; + +} + +bool OContactAccessBackend_XML::add ( const OContact &newcontact ) +{ + //qWarning("odefaultbackend: ACTION::ADD"); + updateJournal (newcontact, ACTION_ADD); + addContact_p( newcontact ); + + m_changed = true; + + return true; +} + +bool OContactAccessBackend_XML::replace ( const OContact &contact ) +{ + m_changed = true; + + OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); + + if ( found ) { + OContact* newCont = new OContact( contact ); + + updateJournal ( *newCont, ACTION_REPLACE); + m_contactList.removeRef ( found ); + m_contactList.append ( newCont ); + m_uidToContact.remove( QString().setNum( contact.uid() ) ); + m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); + + qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); + + return true; + } else + return false; +} + +bool OContactAccessBackend_XML::remove ( int uid ) +{ + m_changed = true; + + OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); + + if ( found ) { + updateJournal ( *found, ACTION_REMOVE); + m_contactList.removeRef ( found ); + m_uidToContact.remove( QString().setNum( uid ) ); + + return true; + } else + return false; +} + +bool OContactAccessBackend_XML::reload(){ + /* Reload is the same as load in this implementation */ + return ( load() ); +} + +void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) +{ + OContact* contRef = new OContact( newcontact ); + + m_contactList.append ( contRef ); + m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); +} + +/* This function loads the xml-database and the journalfile */ +bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) +{ + + /* We use the time of the last read to check if the file was + * changed externally. + */ + if ( !isJournal ){ + QFileInfo fi( filename ); + m_readtime = fi.lastModified (); + } + + const int JOURNALACTION = Qtopia::Notes + 1; + const int JOURNALROW = JOURNALACTION + 1; + + bool foundAction = false; + journal_action action = ACTION_ADD; + int journalKey = 0; + QMap<int, QString> contactMap; + QMap<QString, QString> customMap; + QMap<QString, QString>::Iterator customIt; + QAsciiDict<int> dict( 47 ); + + dict.setAutoDelete( TRUE ); + dict.insert( "Uid", new int(Qtopia::AddressUid) ); + dict.insert( "Title", new int(Qtopia::Title) ); + dict.insert( "FirstName", new int(Qtopia::FirstName) ); + dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); + dict.insert( "LastName", new int(Qtopia::LastName) ); + dict.insert( "Suffix", new int(Qtopia::Suffix) ); + dict.insert( "FileAs", new int(Qtopia::FileAs) ); + dict.insert( "Categories", new int(Qtopia::AddressCategory) ); + dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); + dict.insert( "Emails", new int(Qtopia::Emails) ); + dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); + dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); + dict.insert( "HomeState", new int(Qtopia::HomeState) ); + dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); + dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); + dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); + dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); + dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); + dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); + dict.insert( "Company", new int(Qtopia::Company) ); + dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); + dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); + dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); + dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); + dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); + dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); + dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); + dict.insert( "Department", new int(Qtopia::Department) ); + dict.insert( "Office", new int(Qtopia::Office) ); + dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); + dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); + dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); + dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); + dict.insert( "Profession", new int(Qtopia::Profession) ); + dict.insert( "Assistant", new int(Qtopia::Assistant) ); + dict.insert( "Manager", new int(Qtopia::Manager) ); + dict.insert( "Spouse", new int(Qtopia::Spouse) ); + dict.insert( "Children", new int(Qtopia::Children) ); + dict.insert( "Gender", new int(Qtopia::Gender) ); + dict.insert( "Birthday", new int(Qtopia::Birthday) ); + dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); + dict.insert( "Nickname", new int(Qtopia::Nickname) ); + dict.insert( "Notes", new int(Qtopia::Notes) ); + dict.insert( "action", new int(JOURNALACTION) ); + dict.insert( "actionrow", new int(JOURNALROW) ); + + //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); + + XMLElement *root = XMLElement::load( filename ); + if(root != 0l ){ // start parsing + /* Parse all XML-Elements and put the data into the + * Contact-Class + */ + XMLElement *element = root->firstChild(); + //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); + element = element->firstChild(); + + /* Search Tag "Contacts" which is the parent of all Contacts */ + while( element && !isJournal ){ + if( element->tagName() != QString::fromLatin1("Contacts") ){ + //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", + // element->tagName().latin1()); + element = element->nextChild(); + } else { + element = element->firstChild(); + break; + } + } + /* Parse all Contacts and ignore unknown tags */ + while( element ){ + if( element->tagName() != QString::fromLatin1("Contact") ){ + //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", + // element->tagName().latin1()); + element = element->nextChild(); + continue; + } + /* Found alement with tagname "contact", now parse and store all + * attributes contained + */ + //qWarning("OContactDefBack::load element tagName() : %s", + // element->tagName().latin1() ); + QString dummy; + foundAction = false; + + XMLElement::AttributeMap aMap = element->attributes(); + XMLElement::AttributeMap::Iterator it; + contactMap.clear(); + customMap.clear(); + for( it = aMap.begin(); it != aMap.end(); ++it ){ + // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); + + int *find = dict[ it.key() ]; + /* Unknown attributes will be stored as "Custom" elements */ + if ( !find ) { + // qWarning("Attribute %s not known.", it.key().latin1()); + //contact.setCustomField(it.key(), it.data()); + customMap.insert( it.key(), it.data() ); + continue; + } + + /* Check if special conversion is needed and add attribute + * into Contact class + */ + switch( *find ) { + /* + case Qtopia::AddressUid: + contact.setUid( it.data().toInt() ); + break; + case Qtopia::AddressCategory: + contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); + break; + */ + case JOURNALACTION: + action = journal_action(it.data().toInt()); + foundAction = true; + qWarning ("ODefBack(journal)::ACTION found: %d", action); + break; + case JOURNALROW: + journalKey = it.data().toInt(); + break; + default: // no conversion needed add them to the map + contactMap.insert( *find, it.data() ); + break; + } + } + /* now generate the Contact contact */ + OContact contact( contactMap ); + + for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { + contact.setCustomField( customIt.key(), customIt.data() ); + } + + if (foundAction){ + foundAction = false; + switch ( action ) { + case ACTION_ADD: + addContact_p (contact); + break; + case ACTION_REMOVE: + if ( !remove (contact.uid()) ) + qWarning ("ODefBack(journal)::Unable to remove uid: %d", + contact.uid() ); + break; + case ACTION_REPLACE: + if ( !replace ( contact ) ) + qWarning ("ODefBack(journal)::Unable to replace uid: %d", + contact.uid() ); + break; + default: + qWarning ("Unknown action: ignored !"); + break; + } + }else{ + /* Add contact to list */ + addContact_p (contact); + } + + /* Move to next element */ + element = element->nextChild(); + } + }else { + qWarning("ODefBack::could not load"); + } + delete root; + qWarning("returning from loading" ); + return true; +} + + +void OContactAccessBackend_XML::updateJournal( const OContact& cnt, + journal_action action ) +{ + QFile f( m_journalName ); + bool created = !f.exists(); + if ( !f.open(IO_WriteOnly|IO_Append) ) + return; + + QString buf; + QCString str; + + // if the file was created, we have to set the Tag "<CONTACTS>" to + // get a XML-File which is readable by our parser. + // This is just a cheat, but better than rewrite the parser. + if ( created ){ + buf = "<Contacts>"; + QCString cstr = buf.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + } + + buf = "<Contact "; + cnt.save( buf ); + buf += " action=\"" + QString::number( (int)action ) + "\" "; + buf += "/>\n"; + QCString cstr = buf.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); +} + +void OContactAccessBackend_XML::removeJournal() +{ + QFile f ( m_journalName ); + if ( f.exists() ) + f.remove(); +} + diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h new file mode 100644 index 0000000..6857844 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h @@ -0,0 +1,163 @@ +/* + * XML Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ToDo: XML-Backend: Automatic reload if something was changed... + * File Locking to protect against concurrent access + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:07 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.15 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + * Revision 1.14 2003/04/13 18:07:10 zecke + * More API doc + * QString -> const QString& + * QString = 0l -> QString::null + * + * Revision 1.13 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.12.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.12.2.1 2003/02/09 15:05:01 eilers + * Nothing happened.. Just some cleanup before I will start.. + * + * Revision 1.12 2003/01/03 16:58:03 eilers + * Reenable debug output + * + * Revision 1.11 2003/01/03 12:31:28 eilers + * Bugfix for calculating data diffs.. + * + * Revision 1.10 2003/01/02 14:27:12 eilers + * Improved query by example: Search by date is possible.. First step + * for a today plugin for birthdays.. + * + * Revision 1.9 2002/12/08 12:48:57 eilers + * Moved journal-enum from ocontact into i the xml-backend.. + * + * Revision 1.8 2002/11/14 17:04:24 eilers + * Sorting will now work if fullname is identical on some entries + * + * Revision 1.7 2002/11/13 15:02:46 eilers + * Small Bug in sorted fixed + * + * Revision 1.6 2002/11/13 14:14:51 eilers + * Added sorted for Contacts.. + * + * Revision 1.5 2002/11/01 15:10:42 eilers + * Added regExp-search in database for all fields in a contact. + * + * Revision 1.4 2002/10/16 10:52:40 eilers + * Added some docu to the interface and now using the cache infrastucture by zecke.. :) + * + * Revision 1.3 2002/10/14 16:21:54 eilers + * Some minor interface updates + * + * Revision 1.2 2002/10/07 17:34:24 eilers + * added OBackendFactory for advanced backend access + * + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * + */ + +#ifndef _OContactAccessBackend_XML_ +#define _OContactAccessBackend_XML_ + +#include "ocontactaccessbackend.h" +#include "ocontactaccess.h" + +#include <qlist.h> +#include <qdict.h> + +/* the default xml implementation */ +/** + * This class is the XML implementation of a Contact backend + * it does implement everything available for OContact. + * @see OPimAccessBackend for more information of available methods + */ +class OContactAccessBackend_XML : public OContactAccessBackend { + public: + OContactAccessBackend_XML ( const QString& appname, const QString& filename = QString::null ); + + bool save(); + + bool load (); + + void clear (); + + bool wasChangedExternally(); + + QArray<int> allRecords() const; + + OContact find ( int uid ) const; + + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); + + QArray<int> matchRegexp( const QRegExp &r ) const; + + const uint querySettings(); + + bool hasQuerySettings (uint querySettings) const; + + // Currently only asc implemented.. + QArray<int> sorted( bool asc, int , int , int ); + bool add ( const OContact &newcontact ); + + bool replace ( const OContact &contact ); + + bool remove ( int uid ); + bool reload(); + + private: + + enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; + + void addContact_p( const OContact &newcontact ); + + /* This function loads the xml-database and the journalfile */ + bool load( const QString filename, bool isJournal ); + + + void updateJournal( const OContact& cnt, journal_action action ); + void removeJournal(); + + protected: + bool m_changed; + QString m_journalName; + QString m_fileName; + QString m_appName; + QList<OContact> m_contactList; + QDateTime m_readtime; + + QDict<OContact> m_uidToContact; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/ocontactfields.cpp b/noncore/unsupported/libopie/pim/ocontactfields.cpp new file mode 100644 index 0000000..0f08a5a --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactfields.cpp @@ -0,0 +1,477 @@ + +#include "ocontactfields.h" + +#include <qstringlist.h> +#include <qobject.h> + +// We should use our own enum in the future .. +#include <qpe/recordfields.h> +#include <qpe/config.h> +#include <opie/ocontact.h> + +/*! + \internal + Returns a list of personal field names for a contact. +*/ +QStringList OContactFields::personalfields( bool sorted, bool translated ) +{ + QStringList list; + QMap<int, QString> mapIdToStr; + if ( translated ) + mapIdToStr = idToTrFields(); + else + mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[ Qtopia::AddressUid ] ); + list.append( mapIdToStr[ Qtopia::AddressCategory ] ); + + list.append( mapIdToStr[ Qtopia::Title ] ); + list.append( mapIdToStr[ Qtopia::FirstName ] ); + list.append( mapIdToStr[ Qtopia::MiddleName ] ); + list.append( mapIdToStr[ Qtopia::LastName ] ); + list.append( mapIdToStr[ Qtopia::Suffix ] ); + list.append( mapIdToStr[ Qtopia::FileAs ] ); + + list.append( mapIdToStr[ Qtopia::JobTitle ] ); + list.append( mapIdToStr[ Qtopia::Department ] ); + list.append( mapIdToStr[ Qtopia::Company ] ); + + list.append( mapIdToStr[ Qtopia::Notes ] ); + list.append( mapIdToStr[ Qtopia::Groups ] ); + + if (sorted) list.sort(); + return list; +} + +/*! + \internal + Returns a list of details field names for a contact. +*/ +QStringList OContactFields::detailsfields( bool sorted, bool translated ) +{ + QStringList list; + QMap<int, QString> mapIdToStr; + if ( translated ) + mapIdToStr = idToTrFields(); + else + mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[ Qtopia::Office ] ); + list.append( mapIdToStr[ Qtopia::Profession ] ); + list.append( mapIdToStr[ Qtopia::Assistant ] ); + list.append( mapIdToStr[ Qtopia::Manager ] ); + + list.append( mapIdToStr[ Qtopia::Spouse ] ); + list.append( mapIdToStr[ Qtopia::Gender ] ); + list.append( mapIdToStr[ Qtopia::Birthday ] ); + list.append( mapIdToStr[ Qtopia::Anniversary ] ); + list.append( mapIdToStr[ Qtopia::Nickname ] ); + list.append( mapIdToStr[ Qtopia::Children ] ); + + if (sorted) list.sort(); + return list; +} + +/*! + \internal + Returns a list of phone field names for a contact. +*/ +QStringList OContactFields::phonefields( bool sorted, bool translated ) +{ + QStringList list; + QMap<int, QString> mapIdToStr; + if ( translated ) + mapIdToStr = idToTrFields(); + else + mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[Qtopia::BusinessPhone] ); + list.append( mapIdToStr[Qtopia::BusinessFax] ); + list.append( mapIdToStr[Qtopia::BusinessMobile] ); + list.append( mapIdToStr[Qtopia::BusinessPager] ); + list.append( mapIdToStr[Qtopia::BusinessWebPage] ); + + list.append( mapIdToStr[Qtopia::DefaultEmail] ); + list.append( mapIdToStr[Qtopia::Emails] ); + + list.append( mapIdToStr[Qtopia::HomePhone] ); + list.append( mapIdToStr[Qtopia::HomeFax] ); + list.append( mapIdToStr[Qtopia::HomeMobile] ); + // list.append( mapIdToStr[Qtopia::HomePager] ); + list.append( mapIdToStr[Qtopia::HomeWebPage] ); + + if (sorted) list.sort(); + + return list; +} + +/*! + \internal + Returns a list of field names for a contact. +*/ +QStringList OContactFields::fields( bool sorted, bool translated ) +{ + QStringList list; + QMap<int, QString> mapIdToStr; + if ( translated ) + mapIdToStr = idToTrFields(); + else + mapIdToStr = idToUntrFields(); + + list += personalfields( sorted, translated ); + + list += phonefields( sorted, translated ); + + list.append( mapIdToStr[Qtopia::BusinessStreet] ); + list.append( mapIdToStr[Qtopia::BusinessCity] ); + list.append( mapIdToStr[Qtopia::BusinessState] ); + list.append( mapIdToStr[Qtopia::BusinessZip] ); + list.append( mapIdToStr[Qtopia::BusinessCountry] ); + + list.append( mapIdToStr[Qtopia::HomeStreet] ); + list.append( mapIdToStr[Qtopia::HomeCity] ); + list.append( mapIdToStr[Qtopia::HomeState] ); + list.append( mapIdToStr[Qtopia::HomeZip] ); + list.append( mapIdToStr[Qtopia::HomeCountry] ); + + list += detailsfields( sorted, translated ); + + if (sorted) list.sort(); + + return list; +} + + +/*! + \internal + Returns an untranslated list of personal field names for a contact. +*/ +QStringList OContactFields::untrpersonalfields( bool sorted ) +{ + return personalfields( sorted, false ); +} + + +/*! + \internal + Returns a translated list of personal field names for a contact. +*/ +QStringList OContactFields::trpersonalfields( bool sorted ) +{ + return personalfields( sorted, true ); +} + + +/*! + \internal + Returns an untranslated list of details field names for a contact. +*/ +QStringList OContactFields::untrdetailsfields( bool sorted ) +{ + return detailsfields( sorted, false ); +} + + +/*! + \internal + Returns a translated list of details field names for a contact. +*/ +QStringList OContactFields::trdetailsfields( bool sorted ) +{ + return detailsfields( sorted, true ); +} + + +/*! + \internal + Returns a translated list of phone field names for a contact. +*/ +QStringList OContactFields::trphonefields( bool sorted ) +{ + return phonefields( sorted, true ); +} + +/*! + \internal + Returns an untranslated list of phone field names for a contact. +*/ +QStringList OContactFields::untrphonefields( bool sorted ) +{ + return phonefields( sorted, false ); +} + + +/*! + \internal + Returns a translated list of field names for a contact. +*/ +QStringList OContactFields::trfields( bool sorted ) +{ + return fields( sorted, true ); +} + +/*! + \internal + Returns an untranslated list of field names for a contact. +*/ +QStringList OContactFields::untrfields( bool sorted ) +{ + return fields( sorted, false ); +} + +QMap<int, QString> OContactFields::idToTrFields() +{ + QMap<int, QString> ret_map; + + ret_map.insert( Qtopia::AddressUid, QObject::tr( "User Id" ) ); + ret_map.insert( Qtopia::AddressCategory, QObject::tr( "Categories" ) ); + + ret_map.insert( Qtopia::Title, QObject::tr( "Name Title") ); + ret_map.insert( Qtopia::FirstName, QObject::tr( "First Name" ) ); + ret_map.insert( Qtopia::MiddleName, QObject::tr( "Middle Name" ) ); + ret_map.insert( Qtopia::LastName, QObject::tr( "Last Name" ) ); + ret_map.insert( Qtopia::Suffix, QObject::tr( "Suffix" )); + ret_map.insert( Qtopia::FileAs, QObject::tr( "File As" ) ); + + ret_map.insert( Qtopia::JobTitle, QObject::tr( "Job Title" ) ); + ret_map.insert( Qtopia::Department, QObject::tr( "Department" ) ); + ret_map.insert( Qtopia::Company, QObject::tr( "Company" ) ); + ret_map.insert( Qtopia::BusinessPhone, QObject::tr( "Business Phone" ) ); + ret_map.insert( Qtopia::BusinessFax, QObject::tr( "Business Fax" ) ); + ret_map.insert( Qtopia::BusinessMobile, QObject::tr( "Business Mobile" )); + + // email + ret_map.insert( Qtopia::DefaultEmail, QObject::tr( "Default Email" ) ); + ret_map.insert( Qtopia::Emails, QObject::tr( "Emails" ) ); + + ret_map.insert( Qtopia::HomePhone, QObject::tr( "Home Phone" ) ); + ret_map.insert( Qtopia::HomeFax, QObject::tr( "Home Fax" ) ); + ret_map.insert( Qtopia::HomeMobile, QObject::tr( "Home Mobile" ) ); + + // business + ret_map.insert( Qtopia::BusinessStreet, QObject::tr( "Business Street" ) ); + ret_map.insert( Qtopia::BusinessCity, QObject::tr( "Business City" ) ); + ret_map.insert( Qtopia::BusinessState, QObject::tr( "Business State" ) ); + ret_map.insert( Qtopia::BusinessZip, QObject::tr( "Business Zip" ) ); + ret_map.insert( Qtopia::BusinessCountry, QObject::tr( "Business Country" ) ); + ret_map.insert( Qtopia::BusinessPager, QObject::tr( "Business Pager" ) ); + ret_map.insert( Qtopia::BusinessWebPage, QObject::tr( "Business WebPage" ) ); + + ret_map.insert( Qtopia::Office, QObject::tr( "Office" ) ); + ret_map.insert( Qtopia::Profession, QObject::tr( "Profession" ) ); + ret_map.insert( Qtopia::Assistant, QObject::tr( "Assistant" ) ); + ret_map.insert( Qtopia::Manager, QObject::tr( "Manager" ) ); + + // home + ret_map.insert( Qtopia::HomeStreet, QObject::tr( "Home Street" ) ); + ret_map.insert( Qtopia::HomeCity, QObject::tr( "Home City" ) ); + ret_map.insert( Qtopia::HomeState, QObject::tr( "Home State" ) ); + ret_map.insert( Qtopia::HomeZip, QObject::tr( "Home Zip" ) ); + ret_map.insert( Qtopia::HomeCountry, QObject::tr( "Home Country" ) ); + ret_map.insert( Qtopia::HomeWebPage, QObject::tr( "Home Web Page" ) ); + + //personal + ret_map.insert( Qtopia::Spouse, QObject::tr( "Spouse" ) ); + ret_map.insert( Qtopia::Gender, QObject::tr( "Gender" ) ); + ret_map.insert( Qtopia::Birthday, QObject::tr( "Birthday" ) ); + ret_map.insert( Qtopia::Anniversary, QObject::tr( "Anniversary" ) ); + ret_map.insert( Qtopia::Nickname, QObject::tr( "Nickname" ) ); + ret_map.insert( Qtopia::Children, QObject::tr( "Children" ) ); + + // other + ret_map.insert( Qtopia::Notes, QObject::tr( "Notes" ) ); + + + return ret_map; +} + +QMap<int, QString> OContactFields::idToUntrFields() +{ + QMap<int, QString> ret_map; + + ret_map.insert( Qtopia::AddressUid, "User Id" ); + ret_map.insert( Qtopia::AddressCategory, "Categories" ); + + ret_map.insert( Qtopia::Title, "Name Title" ); + ret_map.insert( Qtopia::FirstName, "First Name" ); + ret_map.insert( Qtopia::MiddleName, "Middle Name" ); + ret_map.insert( Qtopia::LastName, "Last Name" ); + ret_map.insert( Qtopia::Suffix, "Suffix" ); + ret_map.insert( Qtopia::FileAs, "File As" ); + + ret_map.insert( Qtopia::JobTitle, "Job Title" ); + ret_map.insert( Qtopia::Department, "Department" ); + ret_map.insert( Qtopia::Company, "Company" ); + ret_map.insert( Qtopia::BusinessPhone, "Business Phone" ); + ret_map.insert( Qtopia::BusinessFax, "Business Fax" ); + ret_map.insert( Qtopia::BusinessMobile, "Business Mobile" ); + + // email + ret_map.insert( Qtopia::DefaultEmail, "Default Email" ); + ret_map.insert( Qtopia::Emails, "Emails" ); + + ret_map.insert( Qtopia::HomePhone, "Home Phone" ); + ret_map.insert( Qtopia::HomeFax, "Home Fax" ); + ret_map.insert( Qtopia::HomeMobile, "Home Mobile" ); + + // business + ret_map.insert( Qtopia::BusinessStreet, "Business Street" ); + ret_map.insert( Qtopia::BusinessCity, "Business City" ); + ret_map.insert( Qtopia::BusinessState, "Business State" ); + ret_map.insert( Qtopia::BusinessZip, "Business Zip" ); + ret_map.insert( Qtopia::BusinessCountry, "Business Country" ); + ret_map.insert( Qtopia::BusinessPager, "Business Pager" ); + ret_map.insert( Qtopia::BusinessWebPage, "Business WebPage" ); + + ret_map.insert( Qtopia::Office, "Office" ); + ret_map.insert( Qtopia::Profession, "Profession" ); + ret_map.insert( Qtopia::Assistant, "Assistant" ); + ret_map.insert( Qtopia::Manager, "Manager" ); + + // home + ret_map.insert( Qtopia::HomeStreet, "Home Street" ); + ret_map.insert( Qtopia::HomeCity, "Home City" ); + ret_map.insert( Qtopia::HomeState, "Home State" ); + ret_map.insert( Qtopia::HomeZip, "Home Zip" ); + ret_map.insert( Qtopia::HomeCountry, "Home Country" ); + ret_map.insert( Qtopia::HomeWebPage, "Home Web Page" ); + + //personal + ret_map.insert( Qtopia::Spouse, "Spouse" ); + ret_map.insert( Qtopia::Gender, "Gender" ); + ret_map.insert( Qtopia::Birthday, "Birthday" ); + ret_map.insert( Qtopia::Anniversary, "Anniversary" ); + ret_map.insert( Qtopia::Nickname, "Nickname" ); + ret_map.insert( Qtopia::Children, "Children" ); + + // other + ret_map.insert( Qtopia::Notes, "Notes" ); + ret_map.insert( Qtopia::Groups, "Groups" ); + + + return ret_map; +} + +QMap<QString, int> OContactFields::trFieldsToId() +{ + QMap<int, QString> idtostr = idToTrFields(); + QMap<QString, int> ret_map; + + + QMap<int, QString>::Iterator it; + for( it = idtostr.begin(); it != idtostr.end(); ++it ) + ret_map.insert( *it, it.key() ); + + + return ret_map; +} + +/* ======================================================================= */ + +QMap<QString, int> OContactFields::untrFieldsToId() +{ + QMap<int, QString> idtostr = idToUntrFields(); + QMap<QString, int> ret_map; + + + QMap<int, QString>::Iterator it; + for( it = idtostr.begin(); it != idtostr.end(); ++it ) + ret_map.insert( *it, it.key() ); + + + return ret_map; +} + + +OContactFields::OContactFields(): + fieldOrder( DEFAULT_FIELD_ORDER ), + changedFieldOrder( false ) +{ + // Get the global field order from the config file and + // use it as a start pattern + Config cfg ( "AddressBook" ); + cfg.setGroup( "ContactFieldOrder" ); + globalFieldOrder = cfg.readEntry( "General", DEFAULT_FIELD_ORDER ); +} + +OContactFields::~OContactFields(){ + + // We will store the fieldorder into the config file + // to reuse it for the future.. + if ( changedFieldOrder ){ + Config cfg ( "AddressBook" ); + cfg.setGroup( "ContactFieldOrder" ); + cfg.writeEntry( "General", globalFieldOrder ); + } +} + + + +void OContactFields::saveToRecord( OContact &cnt ){ + + qDebug("ocontactfields saveToRecord: >%s<",fieldOrder.latin1()); + + // Store fieldorder into this contact. + cnt.setCustomField( CONTACT_FIELD_ORDER_NAME, fieldOrder ); + + globalFieldOrder = fieldOrder; + changedFieldOrder = true; + +} + +void OContactFields::loadFromRecord( const OContact &cnt ){ + qDebug("ocontactfields loadFromRecord"); + qDebug("loading >%s<",cnt.fullName().latin1()); + + // Get fieldorder for this contact. If none is defined, + // we will use the global one from the config file.. + + fieldOrder = cnt.customField( CONTACT_FIELD_ORDER_NAME ); + + qDebug("fieldOrder from contact>%s<",fieldOrder.latin1()); + + if (fieldOrder.isEmpty()){ + fieldOrder = globalFieldOrder; + } + + + qDebug("effective fieldOrder in loadFromRecord >%s<",fieldOrder.latin1()); +} + +void OContactFields::setFieldOrder( int num, int index ){ + qDebug("qcontactfields setfieldorder pos %i -> %i",num,index); + + fieldOrder[num] = QString::number( index, 16 )[0]; + + // We will store this new fieldorder globally to + // remember it for contacts which have none + globalFieldOrder = fieldOrder; + changedFieldOrder = true; + + qDebug("fieldOrder >%s<",fieldOrder.latin1()); +} + +int OContactFields::getFieldOrder( int num, int defIndex ){ + qDebug("ocontactfields getFieldOrder"); + qDebug("fieldOrder >%s<",fieldOrder.latin1()); + + // Get index of combo as char.. + QChar poschar = fieldOrder[num]; + + bool ok; + int ret = 0; + // Convert char to number.. + if ( !( poschar == QChar::null ) ) + ret = QString( poschar ).toInt(&ok, 16); + else + ok = false; + + // Return default value if index for + // num was not set or if anything else happened.. + if ( !ok ) ret = defIndex; + + qDebug("returning >%i<",ret); + + return ret; + +} diff --git a/noncore/unsupported/libopie/pim/ocontactfields.h b/noncore/unsupported/libopie/pim/ocontactfields.h new file mode 100644 index 0000000..f105de7 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactfields.h @@ -0,0 +1,67 @@ +#ifndef OPIE_CONTACTS_FIELDS +#define OPIE_CONTACTS_FIELDS + +class QStringList; + +#include <qmap.h> +#include <qstring.h> +#include <opie/ocontact.h> + +#define CONTACT_FIELD_ORDER_NAME "opie-contactfield-order" +#define DEFAULT_FIELD_ORDER "__________" + +class OContactFields{ + + public: + OContactFields(); + ~OContactFields(); + /** Set the index for combo boxes. + * Sets the <b>index</b> of combo <b>num</b>. + * @param num selects the number of the combo + * @param index sets the index in the combo + */ + void setFieldOrder( int num, int index ); + + /** Get the index for combo boxes. + * Returns the index of combo <b>num</b> or defindex + * if none was defined.. + * @param num Selects the number of the combo + * @param defIndex will be returned if none was defined (either + * globally in the config file, nor by the contact which was used + * by loadFromRecord() ) + */ + int getFieldOrder( int num, int defIndex); + + /** Store fieldorder to contact. */ + void saveToRecord( OContact& ); + /** Get Fieldorder from contact. */ + void loadFromRecord( const OContact& ); + + private: + QString fieldOrder; + QString globalFieldOrder; + bool changedFieldOrder; + + public: + static QStringList personalfields( bool sorted = true, bool translated = false ); + static QStringList phonefields( bool sorted = true, bool translated = false ); + static QStringList detailsfields( bool sorted = true, bool translated = false ); + static QStringList fields( bool sorted = true, bool translated = false ); + + static QStringList trpersonalfields( bool sorted = true ); + static QStringList untrpersonalfields( bool sorted = true ); + static QStringList trphonefields( bool sorted = true ); + static QStringList untrphonefields( bool sorted = true ); + static QStringList trdetailsfields( bool sorted = true ); + static QStringList untrdetailsfields( bool sorted = true ); + static QStringList trfields( bool sorted = true ); + static QStringList untrfields( bool sorted = true ); + + static QMap<int, QString> idToTrFields(); + static QMap<QString, int> trFieldsToId(); + static QMap<int, QString> idToUntrFields(); + static QMap<QString, int> untrFieldsToId(); + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/oconversion.cpp b/noncore/unsupported/libopie/pim/oconversion.cpp new file mode 100644 index 0000000..0d15414 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oconversion.cpp @@ -0,0 +1,113 @@ +/**********************************************************************
+** Copyright (C) 2003 by Stefan Eilers (eilers.stefan@epost.de)
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU Lesser General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+**********************************************************************/
+
+#include "oconversion.h"
+#include <qpe/timeconversion.h>
+
+
+QString OConversion::dateToString( const QDate &d )
+{
+ if ( d.isNull() || !d.isValid() )
+ return QString::null;
+
+ // ISO format in year, month, day (YYYYMMDD); e.g. 20021231
+ QString year = QString::number( d.year() );
+ QString month = QString::number( d.month() );
+ month = month.rightJustify( 2, '0' );
+ QString day = QString::number( d.day() );
+ day = day.rightJustify( 2, '0' );
+
+ QString str = year + month + day;
+ //qDebug( "\tPimContact dateToStr = %s", str.latin1() );
+
+ return str;
+}
+
+QDate OConversion::dateFromString( const QString& s )
+{
+ QDate date;
+
+ if ( s.isEmpty() )
+ return date;
+
+ // Be backward compatible to old Opie format:
+ // Try to load old format. If it fails, try new ISO-Format!
+ date = TimeConversion::fromString ( s );
+ if ( date.isValid() )
+ return date;
+
+ // Read ISO-Format (YYYYMMDD)
+ int year = s.mid(0, 4).toInt();
+ int month = s.mid(4,2).toInt();
+ int day = s.mid(6,2).toInt();
+
+ // do some quick sanity checking -eilers
+ // but we isValid() again? -zecke
+ if ( year < 1900 || year > 3000 ) {
+ qWarning( "PimContact year is not in range");
+ return date;
+ }
+ if ( month < 0 || month > 12 ) {
+ qWarning( "PimContact month is not in range");
+ return date;
+ }
+ if ( day < 0 || day > 31 ) {
+ qWarning( "PimContact day is not in range");
+ return date;
+ }
+
+ date.setYMD( year, month, day );
+ if ( !date.isValid() ) {
+ qWarning( "PimContact date is not valid");
+ return date;
+ }
+
+ return date;
+}
+QString OConversion::dateTimeToString( const QDateTime& dt ) {
+ if (!dt.isValid() || dt.isNull() ) return QString::null;
+
+ QString year = QString::number( dt.date().year() );
+ QString month = QString::number( dt.date().month() );
+ QString day = QString::number( dt.date().day() );
+
+ QString hour = QString::number( dt.time().hour() );
+ QString min = QString::number( dt.time().minute() );
+ QString sec = QString::number( dt.time().second() );
+
+ month = month.rightJustify( 2, '0' );
+ day = day. rightJustify( 2, '0' );
+ hour = hour. rightJustify( 2, '0' );
+ min = min. rightJustify( 2, '0' );
+ sec = sec. rightJustify( 2, '0' );
+
+ QString str = day + month + year + hour + min + sec;
+
+ return str;
+}
+QDateTime OConversion::dateTimeFromString( const QString& str) {
+
+ if ( str.isEmpty() ) return QDateTime();
+ int day = str.mid(0, 2).toInt();
+ int month = str.mid(2, 2).toInt();
+ int year = str.mid(4, 4).toInt();
+ int hour = str.mid(8, 2).toInt();
+ int min = str.mid(10, 2).toInt();
+ int sec = str.mid(12, 2).toInt();
+
+ QDate date( year, month, day );
+ QTime time( hour, min, sec );
+ QDateTime dt( date, time );
+ return dt;
+}
+
diff --git a/noncore/unsupported/libopie/pim/oconversion.h b/noncore/unsupported/libopie/pim/oconversion.h new file mode 100644 index 0000000..4c0a497 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oconversion.h @@ -0,0 +1,48 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +**********************************************************************/ + +#ifndef __oconversion_h__ +#define __oconversion_h__ + +/* #include <time.h> */ +/* #include <sys/types.h> */ +#include <qdatetime.h> + +/* FIXME namespace? -zecke */ +class OConversion +{ +public: + static QString dateToString( const QDate &d ); + static QDate dateFromString( const QString &datestr ); + + /** + * simple function to store DateTime as string and read from string + * no timezone changing is done + * DDMMYYYYHHMMSS is the simple format + */ + static QString dateTimeToString( const QDateTime& ); + static QDateTime dateTimeFromString( const QString& ); + +private: + class Private; + Private* d; + +}; + +#endif // __oconversion_h__ + diff --git a/noncore/unsupported/libopie/pim/odatebookaccess.cpp b/noncore/unsupported/libopie/pim/odatebookaccess.cpp new file mode 100644 index 0000000..d95fed6 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccess.cpp @@ -0,0 +1,81 @@ +#include "obackendfactory.h" +#include "odatebookaccess.h" + +/** + * Simple constructor + * It takes a ODateBookAccessBackend as parent. If it is 0 the default implementation + * will be used! + * @param back The backend to be used or 0 for the default backend + * @param ac What kind of access is intended + */ +ODateBookAccess::ODateBookAccess( ODateBookAccessBackend* back, enum Access ac ) + : OPimAccessTemplate<OEvent>( back ) +{ + if (!back ) + back = OBackendFactory<ODateBookAccessBackend>::Default("datebook", QString::null ); + + m_backEnd = back; + setBackEnd( m_backEnd ); +} +ODateBookAccess::~ODateBookAccess() { +} + +/** + * @return all events available + */ +ODateBookAccess::List ODateBookAccess::rawEvents()const { + QArray<int> ints = m_backEnd->rawEvents(); + + List lis( ints, this ); + return lis; +} + +/** + * @return all repeating events + */ +ODateBookAccess::List ODateBookAccess::rawRepeats()const { + QArray<int> ints = m_backEnd->rawRepeats(); + + List lis( ints, this ); + return lis; +} + +/** + * @return all non repeating events + */ +ODateBookAccess::List ODateBookAccess::nonRepeats()const { + QArray<int> ints = m_backEnd->nonRepeats(); + + List lis( ints, this ); + return lis; +} + +/** + * @return dates in the time span between from and to + * @param from Include all events from... + * @param to Include all events to... + */ +OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDate& from, const QDate& to ) const { + return m_backEnd->effectiveEvents( from, to ); +} +/** + * @return all events at a given datetime + */ +OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) const { + return m_backEnd->effectiveEvents( start ); +} + +/** + * @return non repeating dates in the time span between from and to + * @param from Include all events from... + * @param to Include all events to... + */ +OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const { + return m_backEnd->effectiveNonRepeatingEvents( from, to ); +} +/** + * @return all non repeating events at a given datetime + */ +OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDateTime& start ) const { + return m_backEnd->effectiveNonRepeatingEvents( start ); +} diff --git a/noncore/unsupported/libopie/pim/odatebookaccess.h b/noncore/unsupported/libopie/pim/odatebookaccess.h new file mode 100644 index 0000000..62196da --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccess.h @@ -0,0 +1,44 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_H +#define OPIE_DATE_BOOK_ACCESS_H + +#include "odatebookaccessbackend.h" +#include "opimaccesstemplate.h" + +#include "oevent.h" + +/** + * This is the object orientated datebook database. It'll use OBackendFactory + * to query for a backend. + * All access to the datebook should be done via this class. + * Make sure to load and save the datebook this is not part of + * destructing and creating the object + * + * @author Holger Freyther, Stefan Eilers + */ +class ODateBookAccess : public OPimAccessTemplate<OEvent> { +public: + ODateBookAccess( ODateBookAccessBackend* = 0l, enum Access acc = Random ); + ~ODateBookAccess(); + + /* return all events */ + List rawEvents()const; + + /* return repeating events */ + List rawRepeats()const; + + /* return non repeating events */ + List nonRepeats()const; + + /* return non repeating events (from,to) */ + OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ) const; + OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ) const; + OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const; + OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ) const; + +private: + ODateBookAccessBackend* m_backEnd; + class Private; + Private* d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp new file mode 100644 index 0000000..f0c5d65 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp @@ -0,0 +1,182 @@ +#include <qtl.h> + +#include "orecur.h" + +#include "odatebookaccessbackend.h" + +namespace { +/* a small helper to get all NonRepeating events for a range of time */ + void events( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& events, + const QDate& from, const QDate& to ) { + QDateTime dtStart, dtEnd; + + for ( OEvent::ValueList::ConstIterator it = events.begin(); it != events.end(); ++it ) { + dtStart = (*it).startDateTime(); + dtEnd = (*it).endDateTime(); + + /* + * If in range + */ + if (dtStart.date() >= from && dtEnd.date() <= to ) { + OEffectiveEvent eff; + eff.setEvent( (*it) ); + eff.setDate( dtStart.date() ); + eff.setStartTime( dtStart.time() ); + + /* if not on the same day */ + if ( dtStart.date() != dtEnd.date() ) + eff.setEndTime( QTime(23, 59, 0 ) ); + else + eff.setEndTime( dtEnd.time() ); + + tmpList.append( eff ); + } + + /* we must also check for end date information... */ + if ( dtEnd.date() != dtStart.date() && dtEnd.date() >= from ) { + QDateTime dt = dtStart.addDays( 1 ); + dt.setTime( QTime(0, 0, 0 ) ); + QDateTime dtStop; + if ( dtEnd > to ) + dtStop = to; + else + dtStop = dtEnd; + + while ( dt <= dtStop ) { + OEffectiveEvent eff; + eff.setEvent( (*it) ); + eff.setDate( dt.date() ); + + if ( dt >= from ) { + eff.setStartTime( QTime(0, 0, 0 ) ); + if ( dt.date() == dtEnd.date() ) + eff.setEndTime( dtEnd.time() ); + else + eff.setEndTime( QTime(23, 59, 0 ) ); + tmpList.append( eff ); + } + dt = dt.addDays( 1 ); + } + } + } + } + + void repeat( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& list, + const QDate& from, const QDate& to ) { + QDate repeat; + for ( OEvent::ValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { + int dur = (*it).startDateTime().date().daysTo( (*it).endDateTime().date() ); + QDate itDate = from.addDays(-dur ); + ORecur rec = (*it).recurrence(); + if ( !rec.hasEndDate() || rec.endDate() > to ) { + rec.setEndDate( to ); + rec.setHasEndDate( true ); + } + while (rec.nextOcurrence(itDate, repeat ) ) { + if (repeat > to ) break; + OEffectiveEvent eff; + eff.setDate( repeat ); + if ( (*it).isAllDay() ) { + eff.setStartTime( QTime(0, 0, 0 ) ); + eff.setEndTime( QTime(23, 59, 59 ) ); + }else { + /* we only occur by days, not hours/minutes/seconds. Hence + * the actual end and start times will be the same for + * every repeated event. For multi day events this is + * fixed up later if on wronge day span + */ + eff.setStartTime( (*it).startDateTime().time() ); + eff.setEndTime( (*it).endDateTime().time() ); + } + if ( dur != 0 ) { + // multi-day repeating events + QDate sub_it = QMAX( repeat, from ); + QDate startDate = repeat; + QDate endDate = startDate.addDays( dur ); + + while ( sub_it <= endDate && sub_it <= to ) { + OEffectiveEvent tmpEff = eff; + tmpEff.setEvent( (*it) ); + if ( sub_it != startDate ) + tmpEff.setStartTime( QTime(0, 0, 0 ) ); + if ( sub_it != endDate ) + tmpEff.setEndTime( QTime( 23, 59, 59 ) ); + + tmpEff.setDate( sub_it ); + tmpEff.setEffectiveDates( startDate, endDate ); + tmpList.append( tmpEff ); + + sub_it = sub_it.addDays( 1 ); + } + itDate = endDate; + }else { + eff.setEvent( (*it) ); + tmpList.append( eff ); + itDate = repeat.addDays( 1 ); + } + } + } + } +} + +ODateBookAccessBackend::ODateBookAccessBackend() + : OPimAccessBackend<OEvent>() +{ + +} +ODateBookAccessBackend::~ODateBookAccessBackend() { + +} +OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDate& from, + const QDate& to ) { + OEffectiveEvent::ValueList tmpList; + OEvent::ValueList list = directNonRepeats(); + + events( tmpList, list, from, to ); + repeat( tmpList, directRawRepeats(),from,to ); + + list = directRawRepeats(); // Useless, isn't it ? (eilers) + + qHeapSort( tmpList ); + return tmpList; +} +OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDateTime& dt ) { + OEffectiveEvent::ValueList day = effectiveEvents( dt.date(), dt.date() ); + OEffectiveEvent::ValueList::Iterator it; + + OEffectiveEvent::ValueList tmpList; + QDateTime dtTmp; + for ( it = day.begin(); it != day.end(); ++it ) { + dtTmp = QDateTime( (*it).date(), (*it).startTime() ); + if ( QABS(dt.secsTo(dtTmp) ) < 60 ) + tmpList.append( (*it) ); + } + + return tmpList; +} + +OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, + const QDate& to ) { + OEffectiveEvent::ValueList tmpList; + OEvent::ValueList list = directNonRepeats(); + + events( tmpList, list, from, to ); + + qHeapSort( tmpList ); + return tmpList; +} + +OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt ) { + OEffectiveEvent::ValueList day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); + OEffectiveEvent::ValueList::Iterator it; + + OEffectiveEvent::ValueList tmpList; + QDateTime dtTmp; + for ( it = day.begin(); it != day.end(); ++it ) { + dtTmp = QDateTime( (*it).date(), (*it).startTime() ); + if ( QABS(dt.secsTo(dtTmp) ) < 60 ) + tmpList.append( (*it) ); + } + + return tmpList; +} diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend.h new file mode 100644 index 0000000..3472ab3 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend.h @@ -0,0 +1,90 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_H +#define OPIE_DATE_BOOK_ACCESS_BACKEND_H + +#include <qarray.h> + +#include "opimaccessbackend.h" +#include "oevent.h" + +/** + * This class is the interface to the storage of Events. + * @see OPimAccessBackend + * + */ +class ODateBookAccessBackend : public OPimAccessBackend<OEvent> { +public: + typedef int UID; + + /** + * c'tor without parameter + */ + ODateBookAccessBackend(); + ~ODateBookAccessBackend(); + + /** + * This method should return a list of UIDs containing + * all events. No filter should be applied + * @return list of events + */ + virtual QArray<UID> rawEvents()const = 0; + + /** + * This method should return a list of UIDs containing + * all repeating events. No filter should be applied + * @return list of repeating events + */ + virtual QArray<UID> rawRepeats()const = 0; + + /** + * This mthod should return a list of UIDs containing all non + * repeating events. No filter should be applied + * @return list of nonrepeating events + */ + virtual QArray<UID> nonRepeats() const = 0; + + /** + * If you do not want to implement the effectiveEvents methods below + * you need to supply it with directNonRepeats. + * This method can return empty lists if effectiveEvents is implememted + */ + virtual OEvent::ValueList directNonRepeats() = 0; + + /** + * Same as above but return raw repeats! + */ + virtual OEvent::ValueList directRawRepeats() = 0; + + /* is implemented by default but you can reimplement it*/ + /** + * Effective Events are special event occuring during a time frame. This method does calcualte + * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method + * yourself + */ + virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ); + + /** + * this is an overloaded member function + * @see effectiveEvents( const QDate& from, const QDate& to ) + */ + virtual OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ); + + /** + * Effective Events are special event occuring during a time frame. This method does calcualte + * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method + * yourself + */ + virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ); + + /** + * this is an overloaded member function + * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) + */ + virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ); + +private: + class Private; + Private *d; + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp new file mode 100644 index 0000000..5f87afe --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp @@ -0,0 +1,374 @@ +/* + * SQL Backend for the OPIE-Calender Database. + * + * Copyright (c) 2003 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2004/11/16 21:46:08 mickeyl + * libopie1 goes into unsupported + * + * Revision 1.4 2004/03/14 13:50:35 alwin + * namespace correction + * + * Revision 1.3 2003/12/22 11:41:39 eilers + * Fixing stupid bug, found by sourcode review.. + * + * Revision 1.2 2003/12/22 10:19:26 eilers + * Finishing implementation of sql-backend for datebook. But I have to + * port the PIM datebook application to use it, before I could debug the + * whole stuff. + * Thus, PIM-Database backend is finished, but highly experimental. And some + * parts are still generic. For instance, the "queryByExample()" methods are + * not (or not fully) implemented. Todo: custom-entries not stored. + * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular + * expression search in the database, which is not supported by sqlite ! + * Therefore we need either an extended sqlite or a workaround which would + * be very slow and memory consuming.. + * + * Revision 1.1 2003/12/08 15:18:12 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <qarray.h> +#include <qstringlist.h> + +#include <qpe/global.h> + +#include <opie2/osqldriver.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +#include "orecur.h" +#include "odatebookaccessbackend_sql.h" + +using namespace Opie::DB; + + +ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , + const QString& fileName ) + : ODateBookAccessBackend(), m_driver( NULL ) +{ + m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; + + // Get the standart sql-driver from the OSQLManager.. + OSQLManager man; + m_driver = man.standard(); + m_driver->setUrl( m_fileName ); + + initFields(); + + load(); +} + +ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { + if( m_driver ) + delete m_driver; +} + +void ODateBookAccessBackend_SQL::initFields() +{ + + // This map contains the translation of the fieldtype id's to + // the names of the table columns + m_fieldMap.insert( OEvent::FUid, "uid" ); + m_fieldMap.insert( OEvent::FCategories, "Categories" ); + m_fieldMap.insert( OEvent::FDescription, "Description" ); + m_fieldMap.insert( OEvent::FLocation, "Location" ); + m_fieldMap.insert( OEvent::FType, "Type" ); + m_fieldMap.insert( OEvent::FAlarm, "Alarm" ); + m_fieldMap.insert( OEvent::FSound, "Sound" ); + m_fieldMap.insert( OEvent::FRType, "RType" ); + m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" ); + m_fieldMap.insert( OEvent::FRPosition, "RPosition" ); + m_fieldMap.insert( OEvent::FRFreq, "RFreq" ); + m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" ); + m_fieldMap.insert( OEvent::FREndDate, "REndDate" ); + m_fieldMap.insert( OEvent::FRCreated, "RCreated" ); + m_fieldMap.insert( OEvent::FRExceptions, "RExceptions" ); + m_fieldMap.insert( OEvent::FStart, "Start" ); + m_fieldMap.insert( OEvent::FEnd, "End" ); + m_fieldMap.insert( OEvent::FNote, "Note" ); + m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" ); + m_fieldMap.insert( OEvent::FRecParent, "RecParent" ); + m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" ); + + // Create a map that maps the column name to the id + QMapConstIterator<int, QString> it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + m_reverseFieldMap.insert( it.data(), it.key() ); + } + +} + +bool ODateBookAccessBackend_SQL::load() +{ + if (!m_driver->open() ) + return false; + + // Don't expect that the database exists. + // It is save here to create the table, even if it + // do exist. ( Is that correct for all databases ?? ) + QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; + + QMap<int, QString>::Iterator it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() ); + } + qu += " );"; + + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; + + qWarning( "command: %s", qu.latin1() ); + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ) + return false; + + update(); + + return true; +} + +void ODateBookAccessBackend_SQL::update() +{ + + QString qu = "select uid from datebook"; + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + // m_uids.clear(); + return; + } + + m_uids = extractUids( res ); + +} + +bool ODateBookAccessBackend_SQL::reload() +{ + return load(); +} + +bool ODateBookAccessBackend_SQL::save() +{ + return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) +} + +QArray<int> ODateBookAccessBackend_SQL::allRecords()const +{ + return m_uids; +} + +QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) { + return QArray<int>(); +} + +void ODateBookAccessBackend_SQL::clear() +{ + QString qu = "drop table datebook;"; + qu += "drop table custom_data;"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + + reload(); +} + + +OEvent ODateBookAccessBackend_SQL::find( int uid ) const{ + QString qu = "select *"; + qu += "from datebook where uid = " + QString::number(uid); + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + + OSQLResultItem resItem = res.first(); + + // Create Map for date event and insert UID + QMap<int,QString> dateEventMap; + dateEventMap.insert( OEvent::FUid, QString::number( uid ) ); + + // Now insert the data out of the columns into the map. + QMapConstIterator<int, QString> it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) ); + } + + // Last step: Put map into date event and return it + OEvent retDate( dateEventMap ); + + return retDate; +} + +// FIXME: Speed up update of uid's.. +bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) +{ + QMap<int,QString> eventMap = ev.toMap(); + + QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() ); + QMap<int, QString>::Iterator it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + if ( !eventMap[it.key()].isEmpty() ) + qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] ); + else + qu += QString( ",\"\"" ); + } + qu += " );"; + + // Add custom entries + int id = 0; + QMap<QString, QString> customMap = ev.toExtraMap(); + for( QMap<QString, QString>::Iterator it = customMap.begin(); + it != customMap.end(); ++it ){ + qu += "insert into custom_data VALUES(" + + QString::number( ev.uid() ) + + "," + + QString::number( id++ ) + + ",'" + + it.key() //.latin1() + + "'," + + "0" // Priority for future enhancements + + ",'" + + it.data() //.latin1() + + "');"; + } + qWarning("add %s", qu.latin1() ); + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + return false; + } + + // Update list of uid's + update(); + + return true; +} + +// FIXME: Speed up update of uid's.. +bool ODateBookAccessBackend_SQL::remove( int uid ) +{ + QString qu = "DELETE from datebook where uid = " + + QString::number( uid ) + ";"; + qu += "DELETE from custom_data where uid = " + + QString::number( uid ) + ";"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + return false; + } + + // Update list of uid's + update(); + + return true; +} + +bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) +{ + remove( ev.uid() ); + return add( ev ); +} + +QArray<int> ODateBookAccessBackend_SQL::rawEvents()const +{ + return allRecords(); +} + +QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const +{ + QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\""; + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + QArray<int> nix; + return nix; + } + + return extractUids( res ); +} + +QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const +{ + QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\""; + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + QArray<int> nix; + return nix; + } + + return extractUids( res ); +} + +OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() +{ + QArray<int> nonRepUids = nonRepeats(); + OEvent::ValueList list; + + for (uint i = 0; i < nonRepUids.count(); ++i ){ + list.append( find( nonRepUids[i] ) ); + } + + return list; + +} +OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() +{ + QArray<int> rawRepUids = rawRepeats(); + OEvent::ValueList list; + + for (uint i = 0; i < rawRepUids.count(); ++i ){ + list.append( find( rawRepUids[i] ) ); + } + + return list; +} + + +QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + QArray<int> null; + return null; +} + +/* ===== Private Functions ========================================== */ + +QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const +{ + qWarning("extractUids"); + QTime t; + t.start(); + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray<int> ints(list.count() ); + qWarning(" count = %d", list.count() ); + + int i = 0; + for (it = list.begin(); it != list.end(); ++it ) { + ints[i] = (*it).data("uid").toInt(); + i++; + } + qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); + + return ints; + +} diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h new file mode 100644 index 0000000..ba514bc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h @@ -0,0 +1,65 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H +#define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H + +#include <qmap.h> +#include <opie2/osqlresult.h> + +#include "odatebookaccessbackend.h" + +namespace Opie { namespace DB { +class OSQLDriver; + +}} + +/** + * This is the default SQL implementation for DateBoook SQL storage + * It fully implements the interface + * @see ODateBookAccessBackend + * @see OPimAccessBackend + */ +class ODateBookAccessBackend_SQL : public ODateBookAccessBackend { +public: + ODateBookAccessBackend_SQL( const QString& appName, + const QString& fileName = QString::null); + ~ODateBookAccessBackend_SQL(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); + OEvent find( int uid )const; + void clear(); + bool add( const OEvent& ev ); + bool remove( int uid ); + bool replace( const OEvent& ev ); + + QArray<UID> rawEvents()const; + QArray<UID> rawRepeats()const; + QArray<UID> nonRepeats()const; + + OEvent::ValueList directNonRepeats(); + OEvent::ValueList directRawRepeats(); + +private: + bool loadFile(); + QString m_fileName; + QArray<int> m_uids; + + QMap<int, QString> m_fieldMap; + QMap<QString, int> m_reverseFieldMap; + + Opie::DB::OSQLDriver* m_driver; + + class Private; + Private *d; + + void initFields(); + void update(); + QArray<int> extractUids( Opie::DB::OSQLResult& res ) const; + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp new file mode 100644 index 0000000..929d004 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp @@ -0,0 +1,612 @@ +#include <errno.h> +#include <fcntl.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include <unistd.h> + +#include <qasciidict.h> +#include <qfile.h> + +#include <qtopia/global.h> +#include <qtopia/stringutil.h> +#include <qtopia/timeconversion.h> + +#include "opimnotifymanager.h" +#include "orecur.h" +#include "otimezone.h" +#include "odatebookaccessbackend_xml.h" + +namespace { + // FROM TT again +char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) +{ + char needleChar; + char haystackChar; + if (!needle || !haystack || !hLen || !nLen) + return 0; + + const char* hsearch = haystack; + + if ((needleChar = *needle++) != 0) { + nLen--; //(to make up for needle++) + do { + do { + if ((haystackChar = *hsearch++) == 0) + return (0); + if (hsearch >= haystack + hLen) + return (0); + } while (haystackChar != needleChar); + } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); + hsearch--; + } + return ((char *)hsearch); +} +} + +namespace { + time_t start, end, created, rp_end; + ORecur* rec; + ORecur* recur() { + if (!rec) + rec = new ORecur; + + return rec; + } + int alarmTime; + int snd; + enum Attribute{ + FDescription = 0, + FLocation, + FCategories, + FUid, + FType, + FAlarm, + FSound, + FRType, + FRWeekdays, + FRPosition, + FRFreq, + FRHasEndDate, + FREndDate, + FRStart, + FREnd, + FNote, + FCreated, // Should't this be called FRCreated ? + FTimeZone, + FRecParent, + FRecChildren, + FExceptions + }; + + // FIXME: Use OEvent::toMap() here !! (eilers) + inline void save( const OEvent& ev, QString& buf ) { + qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); + buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; + if (!ev.location().isEmpty() ) + buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; + + buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; + buf += " uid=\"" + QString::number( ev.uid() ) + "\""; + + if (ev.isAllDay() ) + buf += " type=\"AllDay\""; // is that all ?? (eilers) + + if (ev.hasNotifiers() ) { + OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first + int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; + buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; + if ( alarm.sound() == OPimAlarm::Loud ) + buf += "loud"; + else + buf += "silent"; + buf += "\""; + } + if ( ev.hasRecurrence() ) { + buf += ev.recurrence().toString(); + } + + /* + * fscking timezones :) well, we'll first convert + * the QDateTime to a QDateTime in UTC time + * and then we'll create a nice time_t + */ + OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); + buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; + buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; + if (!ev.note().isEmpty() ) { + buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; + } + + buf += " timezone=\""; + if ( ev.timeZone().isEmpty() ) + buf += "None"; + else + buf += ev.timeZone(); + buf += "\""; + + if (ev.parent() != 0 ) { + buf += " recparent=\""+QString::number(ev.parent() )+"\""; + } + + if (ev.children().count() != 0 ) { + QArray<int> children = ev.children(); + buf += " recchildren=\""; + for ( uint i = 0; i < children.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( children[i] ); + } + buf+= "\""; + } + + // skip custom writing + } + + inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { + QMap<int, OEvent>::ConstIterator it; + QString buf; + QCString str; + int total_written; + for ( it = list.begin(); it != list.end(); ++it ) { + buf = "<event"; + save( it.data(), buf ); + buf += " />\n"; + str = buf.utf8(); + + total_written = file.writeBlock(str.data(), str.length() ); + if ( total_written != int(str.length() ) ) + return false; + } + return true; + } +} + +ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , + const QString& fileName ) + : ODateBookAccessBackend() { + m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; + m_changed = false; +} +ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { +} +bool ODateBookAccessBackend_XML::load() { + return loadFile(); +} +bool ODateBookAccessBackend_XML::reload() { + clear(); + return load(); +} +bool ODateBookAccessBackend_XML::save() { + if (!m_changed) return true; + + int total_written; + QString strFileNew = m_name + ".new"; + + QFile f( strFileNew ); + if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; + + QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); + buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; + buf += "<events>\n"; + QCString str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + + if (!forAll( m_raw, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + if (!forAll( m_rep, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + + buf = "</events>\n</DATEBOOK>\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + f.close(); + + if ( ::rename( strFileNew, m_name ) < 0 ) { + QFile::remove( strFileNew ); + return false; + } + + m_changed = false; + return true; +} +QArray<int> ODateBookAccessBackend_XML::allRecords()const { + QArray<int> ints( m_raw.count()+ m_rep.count() ); + uint i = 0; + QMap<int, OEvent>::ConstIterator it; + + for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { + ints[i] = it.key(); + i++; + } + for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { + ints[i] = it.key(); + i++; + } + + return ints; +} +QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) { + return QArray<int>(); +} +void ODateBookAccessBackend_XML::clear() { + m_changed = true; + m_raw.clear(); + m_rep.clear(); +} +OEvent ODateBookAccessBackend_XML::find( int uid ) const{ + if ( m_raw.contains( uid ) ) + return m_raw[uid]; + else + return m_rep[uid]; +} +bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { + m_changed = true; + if (ev.hasRecurrence() ) + m_rep.insert( ev.uid(), ev ); + else + m_raw.insert( ev.uid(), ev ); + + return true; +} +bool ODateBookAccessBackend_XML::remove( int uid ) { + m_changed = true; + m_rep.remove( uid ); + m_rep.remove( uid ); + + return true; +} +bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { + replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) + return add( ev ); +} +QArray<int> ODateBookAccessBackend_XML::rawEvents()const { + return allRecords(); +} +QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { + QArray<int> ints( m_rep.count() ); + uint i = 0; + QMap<int, OEvent>::ConstIterator it; + + for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { + ints[i] = it.key(); + i++; + } + + return ints; +} +QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { + QArray<int> ints( m_raw.count() ); + uint i = 0; + QMap<int, OEvent>::ConstIterator it; + + for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { + ints[i] = it.key(); + i++; + } + + return ints; +} +OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { + OEvent::ValueList list; + QMap<int, OEvent>::ConstIterator it; + for (it = m_raw.begin(); it != m_raw.end(); ++it ) + list.append( it.data() ); + + return list; +} +OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { + OEvent::ValueList list; + QMap<int, OEvent>::ConstIterator it; + for (it = m_rep.begin(); it != m_rep.end(); ++it ) + list.append( it.data() ); + + return list; +} + +// FIXME: Use OEvent::fromMap() (eilers) +bool ODateBookAccessBackend_XML::loadFile() { + m_changed = false; + + int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); + if ( fd < 0 ) return false; + + struct stat attribute; + if ( ::fstat(fd, &attribute ) == -1 ) { + ::close( fd ); + return false; + } + void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if ( map_addr == ( (caddr_t)-1) ) { + ::close( fd ); + return false; + } + + ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); + ::close( fd ); + + QAsciiDict<int> dict(FExceptions+1); + dict.setAutoDelete( true ); + dict.insert( "description", new int(FDescription) ); + dict.insert( "location", new int(FLocation) ); + dict.insert( "categories", new int(FCategories) ); + dict.insert( "uid", new int(FUid) ); + dict.insert( "type", new int(FType) ); + dict.insert( "alarm", new int(FAlarm) ); + dict.insert( "sound", new int(FSound) ); + dict.insert( "rtype", new int(FRType) ); + dict.insert( "rweekdays", new int(FRWeekdays) ); + dict.insert( "rposition", new int(FRPosition) ); + dict.insert( "rfreq", new int(FRFreq) ); + dict.insert( "rhasenddate", new int(FRHasEndDate) ); + dict.insert( "enddt", new int(FREndDate) ); + dict.insert( "start", new int(FRStart) ); + dict.insert( "end", new int(FREnd) ); + dict.insert( "note", new int(FNote) ); + dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? + dict.insert( "recparent", new int(FRecParent) ); + dict.insert( "recchildren", new int(FRecChildren) ); + dict.insert( "exceptions", new int(FExceptions) ); + dict.insert( "timezone", new int(FTimeZone) ); + + char* dt = (char*)map_addr; + int len = attribute.st_size; + int i = 0; + char* point; + const char* collectionString = "<event "; + int strLen = ::strlen(collectionString); + int *find; + while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { + i = point -dt; + i+= strLen; + + alarmTime = -1; + snd = 0; // silent + + OEvent ev; + rec = 0; + + while ( TRUE ) { + while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) + ++i; + if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) + break; + + + // we have another attribute, read it. + int j = i; + while ( j < len && dt[j] != '=' ) + ++j; + QCString attr( dt+i, j-i+1); + + i = ++j; // skip = + + // find the start of quotes + while ( i < len && dt[i] != '"' ) + ++i; + j = ++i; + + bool haveUtf = FALSE; + bool haveEnt = FALSE; + while ( j < len && dt[j] != '"' ) { + if ( ((unsigned char)dt[j]) > 0x7f ) + haveUtf = TRUE; + if ( dt[j] == '&' ) + haveEnt = TRUE; + ++j; + } + if ( i == j ) { + // empty value + i = j + 1; + continue; + } + + QCString value( dt+i, j-i+1 ); + i = j + 1; + + QString str = (haveUtf ? QString::fromUtf8( value ) + : QString::fromLatin1( value ) ); + if ( haveEnt ) + str = Qtopia::plainString( str ); + + /* + * add key + value + */ + find = dict[attr.data()]; + if (!find) + ev.setCustomField( attr, str ); + else { + setField( ev, *find, str ); + } + } + /* time to finalize */ + finalizeRecord( ev ); + delete rec; + } + ::munmap(map_addr, attribute.st_size ); + m_changed = false; // changed during add + + return true; +} + +// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers) +void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { + /* AllDay is alway in UTC */ + if ( ev.isAllDay() ) { + OTimeZone utc = OTimeZone::utc(); + ev.setStartDateTime( utc.fromUTCDateTime( start ) ); + ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); + ev.setTimeZone( "UTC"); // make sure it is really utc + }else { + /* to current date time */ + // qWarning(" Start is %d", start ); + OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); + QDateTime date = zone.toDateTime( start ); + qWarning(" Start is %s", date.toString().latin1() ); + ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); + } + if ( rec && rec->doesRecur() ) { + OTimeZone utc = OTimeZone::utc(); + ORecur recu( *rec ); // call copy c'tor; + recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); + recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); + recu.setStart( ev.startDateTime().date() ); + ev.setRecurrence( recu ); + } + + if (alarmTime != -1 ) { + QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); + OPimAlarm al( snd , dt ); + ev.notifiers().add( al ); + } + if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { + qWarning("already contains assign uid"); + ev.setUid( 1 ); + } + qWarning("addind %d %s", ev.uid(), ev.description().latin1() ); + if ( ev.hasRecurrence() ) + m_rep.insert( ev.uid(), ev ); + else + m_raw.insert( ev.uid(), ev ); + +} +void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { +// qWarning(" setting %s", value.latin1() ); + switch( id ) { + case FDescription: + e.setDescription( value ); + break; + case FLocation: + e.setLocation( value ); + break; + case FCategories: + e.setCategories( e.idsFromString( value ) ); + break; + case FUid: + e.setUid( value.toInt() ); + break; + case FType: + if ( value == "AllDay" ) { + e.setAllDay( true ); + e.setTimeZone( "UTC" ); + } + break; + case FAlarm: + alarmTime = value.toInt(); + break; + case FSound: + snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; + break; + // recurrence stuff + case FRType: + if ( value == "Daily" ) + recur()->setType( ORecur::Daily ); + else if ( value == "Weekly" ) + recur()->setType( ORecur::Weekly); + else if ( value == "MonthlyDay" ) + recur()->setType( ORecur::MonthlyDay ); + else if ( value == "MonthlyDate" ) + recur()->setType( ORecur::MonthlyDate ); + else if ( value == "Yearly" ) + recur()->setType( ORecur::Yearly ); + else + recur()->setType( ORecur::NoRepeat ); + break; + case FRWeekdays: + recur()->setDays( value.toInt() ); + break; + case FRPosition: + recur()->setPosition( value.toInt() ); + break; + case FRFreq: + recur()->setFrequency( value.toInt() ); + break; + case FRHasEndDate: + recur()->setHasEndDate( value.toInt() ); + break; + case FREndDate: { + rp_end = (time_t) value.toLong(); + break; + } + case FRStart: { + start = (time_t) value.toLong(); + break; + } + case FREnd: { + end = ( (time_t) value.toLong() ); + break; + } + case FNote: + e.setNote( value ); + break; + case FCreated: + created = value.toInt(); + break; + case FRecParent: + e.setParent( value.toInt() ); + break; + case FRecChildren:{ + QStringList list = QStringList::split(' ', value ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + e.addChild( (*it).toInt() ); + } + } + break; + case FExceptions:{ + QStringList list = QStringList::split(' ', value ); + for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); + qWarning("adding exception %s", date.toString().latin1() ); + recur()->exceptions().append( date ); + } + } + break; + case FTimeZone: + if ( value != "None" ) + e.setTimeZone( value ); + break; + default: + break; + } +} +QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const +{ + QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() ); + uint arraycounter = 0; + QMap<int, OEvent>::ConstIterator it; + + for ( it = m_raw.begin(); it != m_raw.end(); ++it ) + if ( it.data().match( r ) ) + m_currentQuery[arraycounter++] = it.data().uid(); + for ( it = m_rep.begin(); it != m_rep.end(); ++it ) + if ( it.data().match( r ) ) + m_currentQuery[arraycounter++] = it.data().uid(); + + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; +} diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h new file mode 100644 index 0000000..a5cc0fc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h @@ -0,0 +1,55 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H +#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H + +#include <qmap.h> + +#include "odatebookaccessbackend.h" + +/** + * This is the default XML implementation for DateBoook XML storage + * It fully implements the interface + * @see ODateBookAccessBackend + * @see OPimAccessBackend + */ +class ODateBookAccessBackend_XML : public ODateBookAccessBackend { +public: + ODateBookAccessBackend_XML( const QString& appName, + const QString& fileName = QString::null); + ~ODateBookAccessBackend_XML(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); + OEvent find( int uid )const; + void clear(); + bool add( const OEvent& ev ); + bool remove( int uid ); + bool replace( const OEvent& ev ); + + QArray<UID> rawEvents()const; + QArray<UID> rawRepeats()const; + QArray<UID> nonRepeats()const; + + OEvent::ValueList directNonRepeats(); + OEvent::ValueList directRawRepeats(); + +private: + bool m_changed :1 ; + bool loadFile(); + inline void finalizeRecord( OEvent& ev ); + inline void setField( OEvent&, int field, const QString& val ); + QString m_name; + QMap<int, OEvent> m_raw; + QMap<int, OEvent> m_rep; + + struct Data; + Data* data; + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/oevent.cpp b/noncore/unsupported/libopie/pim/oevent.cpp new file mode 100644 index 0000000..9b31957 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oevent.cpp @@ -0,0 +1,717 @@ +#include <qshared.h> +#include <qarray.h> + +#include <qpe/palmtopuidgen.h> +#include <qpe/categories.h> +#include <qpe/stringutil.h> + +#include "orecur.h" +#include "opimresolver.h" +#include "opimnotifymanager.h" + +#include "oevent.h" + +int OCalendarHelper::week( const QDate& date) { + // Calculates the week this date is in within that + // month. Equals the "row" is is in in the month view + int week = 1; + QDate tmp( date.year(), date.month(), 1 ); + if ( date.dayOfWeek() < tmp.dayOfWeek() ) + ++week; + + week += ( date.day() - 1 ) / 7; + + return week; +} +int OCalendarHelper::ocurrence( const QDate& date) { + // calculates the number of occurrances of this day of the + // week till the given date (e.g 3rd Wednesday of the month) + return ( date.day() - 1 ) / 7 + 1; +} +int OCalendarHelper::dayOfWeek( char day ) { + int dayOfWeek = 1; + char i = ORecur::MON; + while ( !( i & day ) && i <= ORecur::SUN ) { + i <<= 1; + ++dayOfWeek; + } + return dayOfWeek; +} +int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) { + return ( second.year() - first.year() ) * 12 + + second.month() - first.month(); +} + +struct OEvent::Data : public QShared { + Data() : QShared() { + child = 0; + recur = 0; + manager = 0; + isAllDay = false; + parent = 0; + } + ~Data() { + delete manager; + delete recur; + } + QString description; + QString location; + OPimNotifyManager* manager; + ORecur* recur; + QString note; + QDateTime created; + QDateTime start; + QDateTime end; + bool isAllDay : 1; + QString timezone; + QArray<int>* child; + int parent; +}; + +OEvent::OEvent( int uid ) + : OPimRecord( uid ) { + data = new Data; +} +OEvent::OEvent( const OEvent& ev) + : OPimRecord( ev ), data( ev.data ) +{ + data->ref(); +} + +OEvent::OEvent( const QMap<int, QString> map ) + : OPimRecord( 0 ) +{ + data = new Data; + + fromMap( map ); +} + +OEvent::~OEvent() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +OEvent& OEvent::operator=( const OEvent& ev) { + if ( this == &ev ) return *this; + + OPimRecord::operator=( ev ); + ev.data->ref(); + deref(); + data = ev.data; + + + return *this; +} +QString OEvent::description()const { + return data->description; +} +void OEvent::setDescription( const QString& description ) { + changeOrModify(); + data->description = description; +} +void OEvent::setLocation( const QString& loc ) { + changeOrModify(); + data->location = loc; +} +QString OEvent::location()const { + return data->location; +} +OPimNotifyManager &OEvent::notifiers()const { + // I hope we can skip the changeOrModify here + // the notifier should take care of it + // and OPimNotify is shared too + if (!data->manager ) + data->manager = new OPimNotifyManager; + + return *data->manager; +} +bool OEvent::hasNotifiers()const { + if (!data->manager ) + return false; + if (data->manager->reminders().isEmpty() && + data->manager->alarms().isEmpty() ) + return false; + + return true; +} +ORecur OEvent::recurrence()const { + if (!data->recur) + data->recur = new ORecur; + + return *data->recur; +} +void OEvent::setRecurrence( const ORecur& rec) { + changeOrModify(); + if (data->recur ) + (*data->recur) = rec; + else + data->recur = new ORecur( rec ); +} +bool OEvent::hasRecurrence()const { + if (!data->recur ) return false; + return data->recur->doesRecur(); +} +QString OEvent::note()const { + return data->note; +} +void OEvent::setNote( const QString& note ) { + changeOrModify(); + data->note = note; +} +QDateTime OEvent::createdDateTime()const { + return data->created; +} +void OEvent::setCreatedDateTime( const QDateTime& time ) { + changeOrModify(); + data->created = time; +} +QDateTime OEvent::startDateTime()const { + if ( data->isAllDay ) + return QDateTime( data->start.date(), QTime(0, 0, 0 ) ); + return data->start; +} +QDateTime OEvent::startDateTimeInZone()const { + /* if no timezone, or all day event or if the current and this timeZone match... */ + if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return startDateTime(); + + OTimeZone zone(data->timezone ); + return zone.toDateTime( data->start, OTimeZone::current() ); +} +void OEvent::setStartDateTime( const QDateTime& dt ) { + changeOrModify(); + data->start = dt; +} +QDateTime OEvent::endDateTime()const { + /* + * if all Day event the end time needs + * to be on the same day as the start + */ + if ( data->isAllDay ) + return QDateTime( data->start.date(), QTime(23, 59, 59 ) ); + return data->end; +} +QDateTime OEvent::endDateTimeInZone()const { + /* if no timezone, or all day event or if the current and this timeZone match... */ + if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return endDateTime(); + + OTimeZone zone(data->timezone ); + return zone.toDateTime( data->end, OTimeZone::current() ); +} +void OEvent::setEndDateTime( const QDateTime& dt ) { + changeOrModify(); + data->end = dt; +} +bool OEvent::isMultipleDay()const { + return data->end.date().day() - data->start.date().day(); +} +bool OEvent::isAllDay()const { + return data->isAllDay; +} +void OEvent::setAllDay( bool allDay ) { + changeOrModify(); + data->isAllDay = allDay; + if (allDay ) data->timezone = "UTC"; +} +void OEvent::setTimeZone( const QString& tz ) { + changeOrModify(); + data->timezone = tz; +} +QString OEvent::timeZone()const { + if (data->isAllDay ) return QString::fromLatin1("UTC"); + return data->timezone; +} +bool OEvent::match( const QRegExp& re )const { + if ( re.match( data->description ) != -1 ){ + setLastHitField( Qtopia::DatebookDescription ); + return true; + } + if ( re.match( data->note ) != -1 ){ + setLastHitField( Qtopia::Note ); + return true; + } + if ( re.match( data->location ) != -1 ){ + setLastHitField( Qtopia::Location ); + return true; + } + if ( re.match( data->start.toString() ) != -1 ){ + setLastHitField( Qtopia::StartDateTime ); + return true; + } + if ( re.match( data->end.toString() ) != -1 ){ + setLastHitField( Qtopia::EndDateTime ); + return true; + } + return false; +} +QString OEvent::toRichText()const { + QString text, value; + + // description + text += "<b><h3><img src=\"datebook/DateBook\">"; + if ( !description().isEmpty() ) { + text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "" ); + } + text += "</h3></b><br><hr><br>"; + + // location + if ( !(value = location()).isEmpty() ) { + text += "<b>" + QObject::tr( "Location:" ) + "</b> "; + text += Qtopia::escapeString(value) + "<br>"; + } + + // all day event + if ( isAllDay() ) { + text += "<b><i>" + QObject::tr( "This is an all day event" ) + "</i></b><br>"; + } + // multiple day event + else if ( isMultipleDay () ) { + text += "<b><i>" + QObject::tr( "This is a multiple day event" ) + "</i></b><br>"; + } + // start & end times + else { + // start time + if ( startDateTime().isValid() ) { + text += "<b>" + QObject::tr( "Start:") + "</b> "; + text += Qtopia::escapeString(startDateTime().toString() ). + replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; + } + + // end time + if ( endDateTime().isValid() ) { + text += "<b>" + QObject::tr( "End:") + "</b> "; + text += Qtopia::escapeString(endDateTime().toString() ). + replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; + } + } + + // categories + if ( categoryNames("Calendar").count() ){ + text += "<b>" + QObject::tr( "Category:") + "</b> "; + text += categoryNames("Calendar").join(", "); + text += "<br>"; + } + + //notes + if ( !note().isEmpty() ) { + text += "<b>" + QObject::tr( "Note:") + "</b><br>"; + text += note(); +// text += Qtopia::escapeString(note() ). +// replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; + } + return text; +} +QString OEvent::toShortText()const { + QString text; + text += QString::number( startDateTime().date().day() ); + text += "."; + text += QString::number( startDateTime().date().month() ); + text += "."; + text += QString::number( startDateTime().date().year() ); + text += " "; + text += QString::number( startDateTime().time().hour() ); + text += ":"; + text += QString::number( startDateTime().time().minute() ); + text += " - "; + text += description(); + return text; +} +QString OEvent::type()const { + return QString::fromLatin1("OEvent"); +} +QString OEvent::recordField( int /*id */ )const { + return QString::null; +} +int OEvent::rtti() { + return OPimResolver::DateBook; +} +bool OEvent::loadFromStream( QDataStream& ) { + return true; +} +bool OEvent::saveToStream( QDataStream& )const { + return true; +} +void OEvent::changeOrModify() { + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->description = data->description; + d2->location = data->location; + + if (data->manager ) + d2->manager = new OPimNotifyManager( *data->manager ); + + if ( data->recur ) + d2->recur = new ORecur( *data->recur ); + + d2->note = data->note; + d2->created = data->created; + d2->start = data->start; + d2->end = data->end; + d2->isAllDay = data->isAllDay; + d2->timezone = data->timezone; + d2->parent = data->parent; + + if ( data->child ) { + d2->child = new QArray<int>( *data->child ); + d2->child->detach(); + } + + data = d2; + } +} +void OEvent::deref() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +// Exporting Event data to map. Using the same +// encoding as ODateBookAccessBackend_xml does.. +// Thus, we could remove the stuff there and use this +// for it and for all other places.. +// Encoding should happen at one place, only ! (eilers) +QMap<int, QString> OEvent::toMap()const { + QMap<int, QString> retMap; + + retMap.insert( OEvent::FUid, QString::number( uid() ) ); + retMap.insert( OEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) )); + retMap.insert( OEvent::FDescription, Qtopia::escapeString( description() ) ); + retMap.insert( OEvent::FLocation, Qtopia::escapeString( location() ) ); + retMap.insert( OEvent::FType, isAllDay() ? "AllDay" : "" ); + OPimAlarm alarm = notifiers().alarms()[0]; + retMap.insert( OEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) ); + retMap.insert( OEvent::FSound, (alarm.sound() == OPimAlarm::Loud) ? "loud" : "silent" ); + + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + retMap.insert( OEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FNote, Qtopia::escapeString( note() ) ); + retMap.insert( OEvent::FTimeZone, timeZone().isEmpty() ? QString( "None" ) : timeZone() ); + if( parent() ) + retMap.insert( OEvent::FRecParent, QString::number( parent() ) ); + if( children().count() ){ + QArray<int> childr = children(); + QString buf; + for ( uint i = 0; i < childr.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( childr[i] ); + } + retMap.insert( OEvent::FRecChildren, buf ); + } + + // Add recurrence stuff + if( hasRecurrence() ){ + ORecur recur = recurrence(); + QMap<int, QString> recFields = recur.toMap(); + retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); + retMap.insert( OEvent::FRWeekdays, recFields[ORecur::RWeekdays] ); + retMap.insert( OEvent::FRPosition, recFields[ORecur::RPosition] ); + retMap.insert( OEvent::FRFreq, recFields[ORecur::RFreq] ); + retMap.insert( OEvent::FRHasEndDate, recFields[ORecur::RHasEndDate] ); + retMap.insert( OEvent::FREndDate, recFields[ORecur::EndDate] ); + retMap.insert( OEvent::FRCreated, recFields[ORecur::Created] ); + retMap.insert( OEvent::FRExceptions, recFields[ORecur::Exceptions] ); + } else { + ORecur recur = recurrence(); + QMap<int, QString> recFields = recur.toMap(); + retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); + } + + return retMap; +} + +void OEvent::fromMap( const QMap<int, QString>& map ) +{ + + // We just want to set the UID if it is really stored. + if ( !map[OEvent::FUid].isEmpty() ) + setUid( map[OEvent::FUid].toInt() ); + + setCategories( idsFromString( map[OEvent::FCategories] ) ); + setDescription( map[OEvent::FDescription] ); + setLocation( map[OEvent::FLocation] ); + + if ( map[OEvent::FType] == "AllDay" ) + setAllDay( true ); + else + setAllDay( false ); + + int alarmTime = -1; + if( !map[OEvent::FAlarm].isEmpty() ) + alarmTime = map[OEvent::FAlarm].toInt(); + + int sound = ( ( map[OEvent::FSound] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); + if ( ( alarmTime != -1 ) ){ + QDateTime dt = startDateTime().addSecs( -1*alarmTime*60 ); + OPimAlarm al( sound , dt ); + notifiers().add( al ); + } + if ( !map[OEvent::FTimeZone].isEmpty() && ( map[OEvent::FTimeZone] != "None" ) ){ + setTimeZone( map[OEvent::FTimeZone] ); + } + + time_t start = (time_t) map[OEvent::FStart].toLong(); + time_t end = (time_t) map[OEvent::FEnd].toLong(); + + /* AllDay is always in UTC */ + if ( isAllDay() ) { + OTimeZone utc = OTimeZone::utc(); + setStartDateTime( utc.fromUTCDateTime( start ) ); + setEndDateTime ( utc.fromUTCDateTime( end ) ); + setTimeZone( "UTC"); // make sure it is really utc + }else { + /* to current date time */ + // qWarning(" Start is %d", start ); + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + QDateTime date = zone.toDateTime( start ); + qWarning(" Start is %s", date.toString().latin1() ); + setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); + } + + if ( !map[OEvent::FRecParent].isEmpty() ) + setParent( map[OEvent::FRecParent].toInt() ); + + if ( !map[OEvent::FRecChildren].isEmpty() ){ + QStringList list = QStringList::split(' ', map[OEvent::FRecChildren] ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + addChild( (*it).toInt() ); + } + } + + // Fill recurrence stuff and put it directly into the ORecur-Object using fromMap.. + if( !map[OEvent::FRType].isEmpty() ){ + QMap<int, QString> recFields; + recFields.insert( ORecur::RType, map[OEvent::FRType] ); + recFields.insert( ORecur::RWeekdays, map[OEvent::FRWeekdays] ); + recFields.insert( ORecur::RPosition, map[OEvent::FRPosition] ); + recFields.insert( ORecur::RFreq, map[OEvent::FRFreq] ); + recFields.insert( ORecur::RHasEndDate, map[OEvent::FRHasEndDate] ); + recFields.insert( ORecur::EndDate, map[OEvent::FREndDate] ); + recFields.insert( ORecur::Created, map[OEvent::FRCreated] ); + recFields.insert( ORecur::Exceptions, map[OEvent::FRExceptions] ); + ORecur recur( recFields ); + setRecurrence( recur ); + } + +} + + +int OEvent::parent()const { + return data->parent; +} +void OEvent::setParent( int uid ) { + changeOrModify(); + data->parent = uid; +} +QArray<int> OEvent::children() const{ + if (!data->child) return QArray<int>(); + else + return data->child->copy(); +} +void OEvent::setChildren( const QArray<int>& arr ) { + changeOrModify(); + if (data->child) delete data->child; + + data->child = new QArray<int>( arr ); + data->child->detach(); +} +void OEvent::addChild( int uid ) { + changeOrModify(); + if (!data->child ) { + data->child = new QArray<int>(1); + (*data->child)[0] = uid; + }else{ + int count = data->child->count(); + data->child->resize( count + 1 ); + (*data->child)[count] = uid; + } +} +void OEvent::removeChild( int uid ) { + if (!data->child || !data->child->contains( uid ) ) return; + changeOrModify(); + QArray<int> newAr( data->child->count() - 1 ); + int j = 0; + uint count = data->child->count(); + for ( uint i = 0; i < count; i++ ) { + if ( (*data->child)[i] != uid ) { + newAr[j] = (*data->child)[i]; + j++; + } + } + (*data->child) = newAr; +} +struct OEffectiveEvent::Data : public QShared { + Data() : QShared() { + } + OEvent event; + QDate date; + QTime start, end; + QDate startDate, endDate; + bool dates : 1; +}; + +OEffectiveEvent::OEffectiveEvent() { + data = new Data; + data->date = QDate::currentDate(); + data->start = data->end = QTime::currentTime(); + data->dates = false; +} +OEffectiveEvent::OEffectiveEvent( const OEvent& ev, const QDate& startDate, + Position pos ) { + data = new Data; + data->event = ev; + data->date = startDate; + if ( pos & Start ) + data->start = ev.startDateTime().time(); + else + data->start = QTime( 0, 0, 0 ); + + if ( pos & End ) + data->end = ev.endDateTime().time(); + else + data->end = QTime( 23, 59, 59 ); + + data->dates = false; +} +OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev) { + data = ev.data; + data->ref(); +} +OEffectiveEvent::~OEffectiveEvent() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +OEffectiveEvent& OEffectiveEvent::operator=( const OEffectiveEvent& ev ) { + if ( *this == ev ) return *this; + + ev.data->ref(); + deref(); + data = ev.data; + + return *this; +} + +void OEffectiveEvent::setStartTime( const QTime& ti) { + changeOrModify(); + data->start = ti; +} +void OEffectiveEvent::setEndTime( const QTime& en) { + changeOrModify(); + data->end = en; +} +void OEffectiveEvent::setEvent( const OEvent& ev) { + changeOrModify(); + data->event = ev; +} +void OEffectiveEvent::setDate( const QDate& da) { + changeOrModify(); + data->date = da; +} +void OEffectiveEvent::setEffectiveDates( const QDate& from, + const QDate& to ) { + if (!from.isValid() ) { + data->dates = false; + return; + } + + data->startDate = from; + data->endDate = to; +} +QString OEffectiveEvent::description()const { + return data->event.description(); +} +QString OEffectiveEvent::location()const { + return data->event.location(); +} +QString OEffectiveEvent::note()const { + return data->event.note(); +} +OEvent OEffectiveEvent::event()const { + return data->event; +} +QTime OEffectiveEvent::startTime()const { + return data->start; +} +QTime OEffectiveEvent::endTime()const { + return data->end; +} +QDate OEffectiveEvent::date()const { + return data->date; +} +int OEffectiveEvent::length()const { + return (data->end.hour() * 60 - data->start.hour() * 60) + + QABS(data->start.minute() - data->end.minute() ); +} +int OEffectiveEvent::size()const { + return ( data->end.hour() - data->start.hour() ) * 3600 + + (data->end.minute() - data->start.minute() * 60 + + data->end.second() - data->start.second() ); +} +QDate OEffectiveEvent::startDate()const { + if ( data->dates ) + return data->startDate; + else if ( data->event.hasRecurrence() ) // single day, since multi-day should have a d pointer + return data->date; + else + return data->event.startDateTime().date(); +} +QDate OEffectiveEvent::endDate()const { + if ( data->dates ) + return data->endDate; + else if ( data->event.hasRecurrence() ) + return data->date; + else + return data->event.endDateTime().date(); +} +void OEffectiveEvent::deref() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +void OEffectiveEvent::changeOrModify() { + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->event = data->event; + d2->date = data->date; + d2->start = data->start; + d2->end = data->end; + d2->startDate = data->startDate; + d2->endDate = data->endDate; + d2->dates = data->dates; + data = d2; + } +} +bool OEffectiveEvent::operator<( const OEffectiveEvent &e ) const{ + if ( data->date < e.date() ) + return TRUE; + if ( data->date == e.date() ) + return ( startTime() < e.startTime() ); + else + return FALSE; +} +bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const{ + return (data->date <= e.date() ); +} +bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const { + return ( date() == e.date() + && startTime() == e.startTime() + && endTime()== e.endTime() + && event() == e.event() ); +} +bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const { + return !(*this == e ); +} +bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const { + return !(*this <= e ); +} +bool OEffectiveEvent::operator>= ( const OEffectiveEvent &e ) const { + return !(*this < e); +} diff --git a/noncore/unsupported/libopie/pim/oevent.h b/noncore/unsupported/libopie/pim/oevent.h new file mode 100644 index 0000000..9eb948f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oevent.h @@ -0,0 +1,236 @@ +// CONTAINS GPLed code of TT + +#ifndef OPIE_PIM_EVENT_H +#define OPIE_PIM_EVENT_H + +#include <qstring.h> +#include <qdatetime.h> +#include <qvaluelist.h> + +#include <qpe/recordfields.h> +#include <qpe/palmtopuidgen.h> + +#include "otimezone.h" +#include "opimrecord.h" + +struct OCalendarHelper { + /** calculate the week number of the date */ + static int week( const QDate& ); + /** calculate the occurence of week days since the start of the month */ + static int ocurrence( const QDate& ); + + // returns the dayOfWeek for the *first* day it finds (ignores + // any further days!). Returns 1 (Monday) if there isn't any day found + static int dayOfWeek( char day ); + + /** returns the diff of month */ + static int monthDiff( const QDate& first, const QDate& second ); + +}; + +class OPimNotifyManager; +class ORecur; + +/** + * This is the container for all Events. It encapsules all + * available information for a single Event + * @short container for events. + */ +class OEvent : public OPimRecord { +public: + typedef QValueList<OEvent> ValueList; + /** + * RecordFields contain possible attributes + * used in the Results of toMap().. + */ + enum RecordFields { + FUid = Qtopia::UID_ID, + FCategories = Qtopia::CATEGORY_ID, + FDescription = 0, + FLocation, + FType, + FAlarm, + FSound, + FRType, + FRWeekdays, + FRPosition, + FRFreq, + FRHasEndDate, + FREndDate, + FRCreated, + FRExceptions, + FStart, + FEnd, + FNote, + FTimeZone, + FRecParent, + FRecChildren, + }; + + /** + * Start with an Empty OEvent. UID == 0 means that it is empty + */ + OEvent(int uid = 0); + + /** + * copy c'tor + */ + OEvent( const OEvent& ); + + /** + * Create OEvent, initialized by map + * @see enum RecordFields + */ + OEvent( const QMap<int, QString> map ); + ~OEvent(); + OEvent &operator=( const OEvent& ); + + QString description()const; + void setDescription( const QString& description ); + + QString location()const; + void setLocation( const QString& loc ); + + bool hasNotifiers()const; + OPimNotifyManager ¬ifiers()const; + + ORecur recurrence()const; + void setRecurrence( const ORecur& ); + bool hasRecurrence()const; + + QString note()const; + void setNote( const QString& note ); + + + QDateTime createdDateTime()const; + void setCreatedDateTime( const QDateTime& dt); + + /** set the date to dt. dt is the QDateTime in localtime */ + void setStartDateTime( const QDateTime& ); + /** returns the datetime in the local timeZone */ + QDateTime startDateTime()const; + + /** returns the start datetime in the current zone */ + QDateTime startDateTimeInZone()const; + + /** in current timezone */ + void setEndDateTime( const QDateTime& ); + /** in current timezone */ + QDateTime endDateTime()const; + QDateTime endDateTimeInZone()const; + + bool isMultipleDay()const; + bool isAllDay()const; + void setAllDay( bool isAllDay ); + + /* pin this event to a timezone! FIXME */ + void setTimeZone( const QString& timeZone ); + QString timeZone()const; + + + virtual bool match( const QRegExp& )const; + + /** For exception to recurrence here is a list of children... */ + QArray<int> children()const; + void setChildren( const QArray<int>& ); + void addChild( int uid ); + void removeChild( int uid ); + + /** return the parent OEvent */ + int parent()const; + void setParent( int uid ); + + + /* needed reimp */ + QString toRichText()const; + QString toShortText()const; + QString type()const; + + QMap<int, QString> toMap()const; + void fromMap( const QMap<int, QString>& map ); + QString recordField(int )const; + + static int rtti(); + + bool loadFromStream( QDataStream& ); + bool saveToStream( QDataStream& )const; + +/* bool operator==( const OEvent& ); + bool operator!=( const OEvent& ); + bool operator<( const OEvent& ); + bool operator<=( const OEvent& ); + bool operator>( const OEvent& ); + bool operator>=(const OEvent& ); +*/ +private: + inline void changeOrModify(); + void deref(); + struct Data; + Data* data; + class Private; + Private* priv; + +}; + +/** + * AN Event can span through multiple days. We split up a multiday eve + */ +class OEffectiveEvent { +public: + typedef QValueList<OEffectiveEvent> ValueList; + enum Position { MidWay, Start, End, StartEnd }; + // If we calculate the effective event of a multi-day event + // we have to figure out whether we are at the first day, + // at the end, or anywhere else ("middle"). This is important + // for the start/end times (00:00/23:59) + // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi- + // day event + // Start: start time -> 23:59 + // End: 00:00 -> end time + // Start | End == StartEnd: for single-day events (default) + // here we draw start time -> end time + OEffectiveEvent(); + OEffectiveEvent( const OEvent& event, const QDate& startDate, Position pos = StartEnd ); + OEffectiveEvent( const OEffectiveEvent& ); + OEffectiveEvent &operator=(const OEffectiveEvent& ); + ~OEffectiveEvent(); + + void setStartTime( const QTime& ); + void setEndTime( const QTime& ); + void setEvent( const OEvent& ); + void setDate( const QDate& ); + + void setEffectiveDates( const QDate& from, const QDate& to ); + + QString description()const; + QString location()const; + QString note()const; + OEvent event()const; + QTime startTime()const; + QTime endTime()const; + QDate date()const; + + /* return the length in hours */ + int length()const; + int size()const; + + QDate startDate()const; + QDate endDate()const; + + bool operator<( const OEffectiveEvent &e ) const; + bool operator<=( const OEffectiveEvent &e ) const; + bool operator==( const OEffectiveEvent &e ) const; + bool operator!=( const OEffectiveEvent &e ) const; + bool operator>( const OEffectiveEvent &e ) const; + bool operator>= ( const OEffectiveEvent &e ) const; + +private: + void deref(); + inline void changeOrModify(); + class Private; + Private* priv; + struct Data; + Data* data; + +}; +#endif diff --git a/noncore/unsupported/libopie/pim/opimaccessbackend.h b/noncore/unsupported/libopie/pim/opimaccessbackend.h new file mode 100644 index 0000000..fd264fc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimaccessbackend.h @@ -0,0 +1,160 @@ +#ifndef OPIE_PIM_ACCESS_BACKEND +#define OPIE_PIM_ACCESS_BACKEND + +#include <qarray.h> +#include <qdatetime.h> + +#include <opie/otemplatebase.h> +#include <opie/opimrecord.h> + + +class OPimAccessBackendPrivate; +/** + * OPimAccessBackend is the base class + * for all private backends + * it operates on OPimRecord as the base class + * and it's responsible for fast manipulating + * the resource the implementation takes care + * of + */ +template <class T = OPimRecord> +class OPimAccessBackend { +public: + typedef OTemplateBase<T> Frontend; + + /** The access hint from the frontend */ + OPimAccessBackend(int access = 0); + virtual ~OPimAccessBackend(); + + /** + * load the resource + */ + virtual bool load() = 0; + + /** + * reload the resource + */ + virtual bool reload() = 0; + + /** + * save the resource and + * all it's changes + */ + virtual bool save() = 0; + + /** + * return an array of + * all available uids + */ + virtual QArray<int> allRecords()const = 0; + + /** + * return a List of records + * that match the regex + */ + virtual QArray<int> matchRegexp(const QRegExp &r) const = 0; + + /** + * queryByExample for T with the given Settings + * + */ + virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; + + /** + * find the OPimRecord with uid @param uid + * returns T and T.isEmpty() if nothing was found + */ + virtual T find(int uid )const = 0; + + virtual T find(int uid, const QArray<int>& items, + uint current, typename Frontend::CacheDirection )const ; + /** + * clear the back end + */ + virtual void clear() = 0; + + /** + * add T + */ + virtual bool add( const T& t ) = 0; + + /** + * remove + */ + virtual bool remove( int uid ) = 0; + + /** + * replace a record with T.uid() + */ + virtual bool replace( const T& t ) = 0; + + /* + * setTheFrontEnd!!! + */ + void setFrontend( Frontend* front ); + + /** + * set the read ahead count + */ + void setReadAhead( uint count ); +protected: + int access()const; + void cache( const T& t )const; + + /** + * use a prime number here! + */ + void setSaneCacheSize( int ); + + uint readAhead()const; + +private: + OPimAccessBackendPrivate *d; + Frontend* m_front; + uint m_read; + int m_acc; + +}; + +template <class T> +OPimAccessBackend<T>::OPimAccessBackend(int acc) + : m_acc( acc ) +{ + m_front = 0l; +} +template <class T> +OPimAccessBackend<T>::~OPimAccessBackend() { + +} +template <class T> +void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { + m_front = fr; +} +template <class T> +void OPimAccessBackend<T>::cache( const T& t )const { + if (m_front ) + m_front->cache( t ); +} +template <class T> +void OPimAccessBackend<T>::setSaneCacheSize( int size) { + if (m_front ) + m_front->setSaneCacheSize( size ); +} +template <class T> +T OPimAccessBackend<T>::find( int uid, const QArray<int>&, + uint, typename Frontend::CacheDirection )const { + return find( uid ); +} +template <class T> +void OPimAccessBackend<T>::setReadAhead( uint count ) { + m_read = count; +} +template <class T> +uint OPimAccessBackend<T>::readAhead()const { + return m_read; +} +template <class T> +int OPimAccessBackend<T>::access()const { + return m_acc; +} +#endif diff --git a/noncore/unsupported/libopie/pim/opimaccesstemplate.h b/noncore/unsupported/libopie/pim/opimaccesstemplate.h new file mode 100644 index 0000000..ecbeb68 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimaccesstemplate.h @@ -0,0 +1,302 @@ +#ifndef OPIE_PIM_ACCESS_TEMPLATE_H +#define OPIE_PIM_ACCESS_TEMPLATE_H + +#include <qarray.h> + +#include <opie/opimrecord.h> +#include <opie/opimaccessbackend.h> +#include <opie/orecordlist.h> + +#include "opimcache.h" +#include "otemplatebase.h" + +class OPimAccessTemplatePrivate; +/** + * Thats the frontend to our OPIE PIM + * Library. Either you want to use it's + * interface or you want to implement + * your own Access lib + * Just create a OPimRecord and inherit from + * the plugins + */ + +template <class T = OPimRecord > +class OPimAccessTemplate : public OTemplateBase<T> { +public: + enum Access { + Random = 0, + SortedAccess + }; + typedef ORecordList<T> List; + typedef OPimAccessBackend<T> BackEnd; + typedef OPimCache<T> Cache; + + /** + * c'tor BackEnd + * enum Access a small hint on how to handle the backend + */ + OPimAccessTemplate( BackEnd* end); + + virtual ~OPimAccessTemplate(); + + /** + * load from the backend + */ + bool load(); + + /** Reload database. + * You should execute this function if the external database + * was changed. + * This function will load the external database and afterwards + * rejoin the local changes. Therefore the local database will be set consistent. + */ + virtual bool reload(); + + /** Save contacts database. + * Save is more a "commit". After calling this function, all changes are public available. + * @return true if successful + */ + bool save(); + + /** + * if the resource was changed externally + * You should use the signal handling instead of polling possible changes ! + * zecke: Do you implement a signal for otodoaccess ? + */ + bool wasChangedExternally()const; + + /** + * return a List of records + * you can iterate over them + */ + virtual List allRecords()const; + + /** + * return a List of records + * that match the regex + */ + virtual List matchRegexp( const QRegExp &r ) const; + + /** + * queryByExample. + * @see otodoaccess, ocontactaccess + */ + virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() ); + + /** + * find the OPimRecord uid + */ + virtual T find( int uid )const; + + /** + * read ahead cache find method ;) + */ + virtual T find( int uid, const QArray<int>&, + uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; + + /* invalidate cache here */ + /** + * clears the backend and invalidates the backend + */ + void clear() ; + + /** + * add T to the backend + * @param t The item to add. + * @return <i>true</i> if added successfully. + */ + virtual bool add( const T& t ) ; + bool add( const OPimRecord& ); + + /* only the uid matters */ + /** + * remove T from the backend + * @param t The item to remove + * @return <i>true</i> if successful. + */ + virtual bool remove( const T& t ); + + /** + * remove the OPimRecord with uid + * @param uid The ID of the item to remove + * @return <i>true</i> if successful. + */ + bool remove( int uid ); + bool remove( const OPimRecord& ); + + /** + * replace T from backend + * @param t The item to replace + * @return <i>true</i> if successful. + */ + virtual bool replace( const T& t) ; + + void setReadAhead( uint count ); + /** + * @internal + */ + void cache( const T& )const; + void setSaneCacheSize( int ); + + QArray<int> records()const; +protected: + /** + * invalidate the cache + */ + void invalidateCache(); + + void setBackEnd( BackEnd* end ); + /** + * returns the backend + */ + BackEnd* backEnd(); + BackEnd* m_backEnd; + Cache m_cache; + +private: + OPimAccessTemplatePrivate *d; + +}; + +template <class T> +OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) + : OTemplateBase<T>(), m_backEnd( end ) +{ + if (end ) + end->setFrontend( this ); +} +template <class T> +OPimAccessTemplate<T>::~OPimAccessTemplate() { + qWarning("~OPimAccessTemplate<T>"); + delete m_backEnd; +} +template <class T> +bool OPimAccessTemplate<T>::load() { + invalidateCache(); + return m_backEnd->load(); +} +template <class T> +bool OPimAccessTemplate<T>::reload() { + invalidateCache(); // zecke: I think this should be added (se) + return m_backEnd->reload(); +} +template <class T> +bool OPimAccessTemplate<T>::save() { + return m_backEnd->save(); +} +template <class T> +typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { + QArray<int> ints = m_backEnd->allRecords(); + List lis(ints, this ); + return lis; +} +template <class T> +typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::matchRegexp( const QRegExp &r )const { + QArray<int> ints = m_backEnd->matchRegexp( r ); + List lis(ints, this ); + return lis; +} +template <class T> +QArray<int> OPimAccessTemplate<T>::records()const { + return m_backEnd->allRecords(); +} +template <class T> +typename OPimAccessTemplate<T>::List +OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) { + QArray<int> ints = m_backEnd->queryByExample( t, settings, d ); + + List lis(ints, this ); + return lis; +} +template <class T> +T OPimAccessTemplate<T>::find( int uid ) const{ + T t = m_backEnd->find( uid ); + cache( t ); + return t; +} +template <class T> +T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, + uint current, typename OTemplateBase<T>::CacheDirection dir )const { + /* + * better do T.isEmpty() + * after a find this way we would + * avoid two finds in QCache... + */ + // qWarning("find it now %d", uid ); + if (m_cache.contains( uid ) ) { + return m_cache.find( uid ); + } + + T t = m_backEnd->find( uid, ar, current, dir ); + cache( t ); + return t; +} +template <class T> +void OPimAccessTemplate<T>::clear() { + invalidateCache(); + m_backEnd->clear(); +} +template <class T> +bool OPimAccessTemplate<T>::add( const T& t ) { + cache( t ); + return m_backEnd->add( t ); +} +template <class T> +bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { + /* same type */ + if ( rec.rtti() == T::rtti() ) { + const T &t = static_cast<const T&>(rec); + return add(t); + } + return false; +} +template <class T> +bool OPimAccessTemplate<T>::remove( const T& t ) { + return remove( t.uid() ); +} +template <class T> +bool OPimAccessTemplate<T>::remove( int uid ) { + m_cache.remove( uid ); + return m_backEnd->remove( uid ); +} +template <class T> +bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { + return remove( rec.uid() ); +} +template <class T> +bool OPimAccessTemplate<T>::replace( const T& t ) { + m_cache.replace( t ); + return m_backEnd->replace( t ); +} +template <class T> +void OPimAccessTemplate<T>::invalidateCache() { + m_cache.invalidate(); +} +template <class T> +typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { + return m_backEnd; +} +template <class T> +bool OPimAccessTemplate<T>::wasChangedExternally()const { + return false; +} +template <class T> +void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { + m_backEnd = end; + if (m_backEnd ) + m_backEnd->setFrontend( this ); +} +template <class T> +void OPimAccessTemplate<T>::cache( const T& t ) const{ + /* hacky we need to work around the const*/ + ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); +} +template <class T> +void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { + m_cache.setSize( size ); +} +template <class T> +void OPimAccessTemplate<T>::setReadAhead( uint count ) { + m_backEnd->setReadAhead( count ); +} +#endif diff --git a/noncore/unsupported/libopie/pim/opimcache.h b/noncore/unsupported/libopie/pim/opimcache.h new file mode 100644 index 0000000..7f7cff5 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimcache.h @@ -0,0 +1,131 @@ +#ifndef OPIE_PIM_CACHE_H +#define OPIE_PIM_CACHE_H + +#include <qintcache.h> + +#include "opimrecord.h" + +class OPimCacheItemPrivate; + +template <class T = OPimRecord> +class OPimCacheItem { +public: + OPimCacheItem( const T& t = T() ); + OPimCacheItem( const OPimCacheItem& ); + ~OPimCacheItem(); + + OPimCacheItem &operator=( const OPimCacheItem& ); + + T record()const; + void setRecord( const T& ); +private: + T m_t; + OPimCacheItemPrivate *d; +}; + + +class OPimCachePrivate; +/** + * OPimCache for caching the items + * We support adding, removing + * and finding + */ +template <class T = OPimRecord> +class OPimCache { +public: + typedef OPimCacheItem<T> Item; + OPimCache(); + OPimCache( const OPimCache& ); + ~OPimCache(); + + OPimCache &operator=( const OPimCache& ); + + bool contains(int uid)const; + void invalidate(); + void setSize( int size ); + + T find(int uid )const; + void add( const T& ); + void remove( int uid ); + void replace( const T& ); + +private: + QIntCache<Item> m_cache; + OPimCachePrivate* d; +}; + +// Implementation +template <class T> +OPimCacheItem<T>::OPimCacheItem( const T& t ) + : m_t(t) { +} +template <class T> +OPimCacheItem<T>::~OPimCacheItem() { + +} +template <class T> +T OPimCacheItem<T>::record()const { + return m_t; +} +template <class T> +void OPimCacheItem<T>::setRecord( const T& t ) { + m_t = t; +} +// Cache +template <class T> +OPimCache<T>::OPimCache() + : m_cache(100, 53 ) +{ + m_cache.setAutoDelete( TRUE ); +} +template <class T> +OPimCache<T>::~OPimCache() { + +} +template <class T> +bool OPimCache<T>::contains(int uid )const { + Item* it = m_cache.find( uid, FALSE ); + if (!it) + return false; + return true; +} +template <class T> +void OPimCache<T>::invalidate() { + m_cache.clear(); +} +template <class T> +void OPimCache<T>::setSize( int size ) { + m_cache.setMaxCost( size ); +} +template <class T> +T OPimCache<T>::find(int uid )const { + Item *it = m_cache.find( uid ); + if (it) + return it->record(); + return T(); +} +template <class T> +void OPimCache<T>::add( const T& t ) { + Item* it = 0l; + it = m_cache.find(t.uid(), FALSE ); + + if (it ) + it->setRecord( t ); + + it = new Item( t ); + if (!m_cache.insert( t.uid(), it ) ) + delete it; +} +template <class T> +void OPimCache<T>::remove( int uid ) { + m_cache.remove( uid ); +} +template <class T> +void OPimCache<T>::replace( const T& t) { + Item *it = m_cache.find( t.uid() ); + if ( it ) { + it->setRecord( t ); + } +} + +#endif diff --git a/noncore/unsupported/libopie/pim/opimmaintainer.cpp b/noncore/unsupported/libopie/pim/opimmaintainer.cpp new file mode 100644 index 0000000..92cb25a --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmaintainer.cpp @@ -0,0 +1,37 @@ +#include "opimmaintainer.h" + +OPimMaintainer::OPimMaintainer( int mode, int uid ) + : m_mode(mode), m_uid(uid ) +{} +OPimMaintainer::~OPimMaintainer() { +} +OPimMaintainer::OPimMaintainer( const OPimMaintainer& main ) { + *this = main; +} +OPimMaintainer &OPimMaintainer::operator=( const OPimMaintainer& main ) { + m_mode = main.m_mode; + m_uid = main.m_uid; + + return *this; +} +bool OPimMaintainer::operator==( const OPimMaintainer& main ) { + if (m_mode != main.m_mode ) return false; + if (m_uid != main.m_uid ) return false; + + return true; +} +bool OPimMaintainer::operator!=( const OPimMaintainer& main ) { + return !(*this == main ); +} +int OPimMaintainer::mode()const { + return m_mode; +} +int OPimMaintainer::uid()const { + return m_uid; +} +void OPimMaintainer::setMode( int mo) { + m_mode = mo; +} +void OPimMaintainer::setUid( int uid ) { + m_uid = uid; +} diff --git a/noncore/unsupported/libopie/pim/opimmaintainer.h b/noncore/unsupported/libopie/pim/opimmaintainer.h new file mode 100644 index 0000000..793d066 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmaintainer.h @@ -0,0 +1,40 @@ +#ifndef OPIE_PIM_MAINTAINER_H +#define OPIE_PIM_MAINTAINER_H + +#include <qstring.h> + +/** + * Who maintains what? + */ +class OPimMaintainer { +public: + enum Mode { Undefined = -1, + Nothing = 0, + Responsible, + DoneBy, + Coordinating, + }; + OPimMaintainer( int mode = Undefined, int uid = 0); + OPimMaintainer( const OPimMaintainer& ); + ~OPimMaintainer(); + + OPimMaintainer &operator=( const OPimMaintainer& ); + bool operator==( const OPimMaintainer& ); + bool operator!=( const OPimMaintainer& ); + + + int mode()const; + int uid()const; + + void setMode( int mode ); + void setUid( int uid ); + +private: + int m_mode; + int m_uid; + class Private; + Private *d; + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimmainwindow.cpp b/noncore/unsupported/libopie/pim/opimmainwindow.cpp new file mode 100644 index 0000000..99a0333 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmainwindow.cpp @@ -0,0 +1,150 @@ +#include <qapplication.h> +#include <qdatetime.h> +#include <qcopchannel_qws.h> + +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> +#include <qpe/qpeapplication.h> + +#include "opimresolver.h" +#include "opimmainwindow.h" + +OPimMainWindow::OPimMainWindow( const QString& service, QWidget* parent, + const char* name, WFlags flag ) + : QMainWindow( parent, name, flag ), m_rtti(-1), m_service( service ), m_fallBack(0l) { + + /* + * let's generate our QCopChannel + */ + m_str = QString("QPE/"+m_service).local8Bit(); + m_channel= new QCopChannel(m_str, this ); + connect(m_channel, SIGNAL(received(const QCString&,const QByteArray&) ), + this, SLOT( appMessage(const QCString&,const QByteArray&) ) ); + connect(qApp, SIGNAL(appMessage(const QCString&,const QByteArray&) ), + this, SLOT( appMessage(const QCString&,const QByteArray&) ) ); + + /* connect flush and reload */ + connect(qApp, SIGNAL(flush() ), + this, SLOT(flush() ) ); + connect(qApp, SIGNAL(reload() ), + this, SLOT(reload() ) ); +} +OPimMainWindow::~OPimMainWindow() { + delete m_channel; +} +QCopChannel* OPimMainWindow::channel() { + return m_channel; +} +void OPimMainWindow::doSetDocument( const QString& ) { + +} +void OPimMainWindow::appMessage( const QCString& cmd, const QByteArray& array ) { + bool needShow = false; + /* + * create demands to create + * a new record... + */ + QDataStream stream(array, IO_ReadOnly); + if ( cmd == "create()" ) { + raise(); + int uid = create(); + QCopEnvelope e(m_str, "created(int)" ); + e << uid; + needShow = true; + }else if ( cmd == "remove(int)" ) { + int uid; + stream >> uid; + bool rem = remove( uid ); + QCopEnvelope e(m_str, "removed(bool)" ); + e << rem; + needShow = true; + }else if ( cmd == "beam(int)" ) { + int uid; + stream >> uid; + beam( uid); + }else if ( cmd == "show(int)" ) { + raise(); + int uid; + stream >> uid; + show( uid ); + needShow = true; + }else if ( cmd == "edit(int)" ) { + raise(); + int uid; + stream >> uid; + edit( uid ); + }else if ( cmd == "add(int,QByteArray)" ) { + int rtti; + QByteArray array; + stream >> rtti; + stream >> array; + m_fallBack = record(rtti, array ); + if (!m_fallBack) return; + add( *m_fallBack ); + delete m_fallBack; + }else if ( cmd == "alarm(QDateTime,int)" ) { + raise(); + QDateTime dt; int uid; + stream >> dt; + stream >> uid; + qWarning(" Date: %s Uid: %d", dt.toString().latin1(), uid ); + QDateTime current = QDateTime::currentDateTime(); + if ( current.time().hour() != dt.time().hour() && current.time().minute() != dt.time().minute() ) + return; + doAlarm( dt, uid ); + needShow = true; + } + + if (needShow ) + QPEApplication::setKeepRunning(); +} +/* implement the url scripting here */ +void OPimMainWindow::setDocument( const QString& str) { + doSetDocument( str ); +} +/* + * we now try to get the array demarshalled + * check if the rtti matches this one + */ +OPimRecord* OPimMainWindow::record( int rtti, const QByteArray& array ) { + if ( service() != rtti ) + return 0l; + + OPimRecord* record = OPimResolver::self()->record( rtti ); + QDataStream str(array, IO_ReadOnly ); + if ( !record || !record->loadFromStream(str) ) { + delete record; + record = 0l; + } + + return record; +} +/* + * get the rtti for the service + */ +int OPimMainWindow::service() { + if ( m_rtti == -1 ) + m_rtti = OPimResolver::self()->serviceId( m_service ); + + return m_rtti; +} +void OPimMainWindow::doAlarm( const QDateTime&, int ) { + +} +void OPimMainWindow::startAlarm(int count ) { + m_alarmCount = count; + m_playedCount = 0; + Sound::soundAlarm(); + m_timerId = startTimer( 5000 ); +} +void OPimMainWindow::killAlarm() { + killTimer( m_timerId ); +} +void OPimMainWindow::timerEvent( QTimerEvent* e) { + if ( m_playedCount <m_alarmCount ) { + m_playedCount++; + Sound::soundAlarm(); + }else { + killTimer( e->timerId() ); + } +} diff --git a/noncore/unsupported/libopie/pim/opimmainwindow.h b/noncore/unsupported/libopie/pim/opimmainwindow.h new file mode 100644 index 0000000..855d364 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmainwindow.h @@ -0,0 +1,99 @@ +#ifndef OPIE_PIM_MAINWINDOW_H +#define OPIE_PIM_MAINWINDOW_H + +#include <qmainwindow.h> + +#include <opie/opimrecord.h> + +/** + * This is a common Opie PIM MainWindow + * it takes care of the QCOP internals + * and implements some functions + * for the URL scripting schema + */ +/* + * due Qt and Templates with signal and slots + * do not work that good :( + * (Ok how to moc a template ;) ) + * We will have the mainwindow which calls a struct which + * is normally reimplemented as a template ;) + */ + +class QCopChannel; +class QDateTime; +class OPimMainWindow : public QMainWindow { + Q_OBJECT +public: + enum TransPort { BlueTooth=0, + IrDa }; + + OPimMainWindow( const QString& service, QWidget *parent = 0, const char* name = 0, + WFlags f = WType_TopLevel); + virtual ~OPimMainWindow(); + + +protected slots: + /* + * called when a setDocument + * couldn't be handled by this window + */ + virtual void doSetDocument( const QString& ); + /* for syncing */ + virtual void flush() = 0; + virtual void reload() = 0; + + /** create a new Records and return the uid */ + virtual int create() = 0; + /** remove a record with UID == uid */ + virtual bool remove( int uid ) = 0; + /** beam the record with UID = uid */ + virtual void beam( int uid ) = 0; + + /** show the record with UID == uid */ + virtual void show( int uid ) = 0; + /** edit the record */ + virtual void edit( int uid ) = 0; + + /** make a copy of it! */ + virtual void add( const OPimRecord& ) = 0; + + virtual void doAlarm( const QDateTime&, int uid ); + + QCopChannel* channel(); + +protected: + /** + * start to play soundAlarm() + * @param count How many times the alarm is played + */ + void startAlarm(int count = 10); + void killAlarm(); + void timerEvent( QTimerEvent* ); + +private slots: + void appMessage( const QCString&, const QByteArray& ); + void setDocument( const QString& ); + + +private: + class Private; + Private* d; + + int m_rtti; + QCopChannel* m_channel; + QString m_service; + QCString m_str; + OPimRecord* m_fallBack; + int m_alarmCount; + int m_playedCount; + int m_timerId; + /* I would love to do this as a template + * but can't think of a right way + * because I need signal and slots -zecke + */ + virtual OPimRecord* record( int rtti, const QByteArray& ) ; + int service(); +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/opimnotify.cpp b/noncore/unsupported/libopie/pim/opimnotify.cpp new file mode 100644 index 0000000..af5514b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotify.cpp @@ -0,0 +1,227 @@ +#include <qshared.h> + +#include "opimnotify.h" + +struct OPimNotify::Data : public QShared { + Data() : QShared(),dur(-1),parent(0) { + + } + QDateTime start; + int dur; + QString application; + int parent; +}; + +OPimNotify::OPimNotify( const QDateTime& start, int duration, int parent ) { + data = new Data; + data->start = start; + data->dur = duration; + data->parent = parent; +} +OPimNotify::OPimNotify( const OPimNotify& noti) + : data( noti.data ) +{ + data->ref(); +} +OPimNotify::~OPimNotify() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} + +OPimNotify &OPimNotify::operator=( const OPimNotify& noti) { + noti.data->ref(); + deref(); + data = noti.data; + + return *this; +} +bool OPimNotify::operator==( const OPimNotify& noti ) { + if ( data == noti.data ) return true; + if ( data->dur != noti.data->dur ) return false; + if ( data->parent != noti.data->parent ) return false; + if ( data->application != noti.data->application ) return false; + if ( data->start != noti.data->start ) return false; + + return true; +} +QDateTime OPimNotify::dateTime()const { + return data->start; +} +QString OPimNotify::service()const { + return data->application; +} +int OPimNotify::parent()const { + return data->parent; +} +int OPimNotify::duration()const { + return data->dur; +} +QDateTime OPimNotify::endTime()const { + return QDateTime( data->start.date(), data->start.time().addSecs( data->dur) ); +} +void OPimNotify::setDateTime( const QDateTime& time ) { + copyIntern(); + data->start = time; +} +void OPimNotify::setDuration( int dur ) { + copyIntern(); + data->dur = dur; +} +void OPimNotify::setParent( int uid ) { + copyIntern(); + data->parent = uid; +} +void OPimNotify::setService( const QString& str ) { + copyIntern(); + data->application = str; +} +void OPimNotify::copyIntern() { + if ( data->count != 1 ) { + data->deref(); + Data* dat = new Data; + dat->start = data->start; + dat->dur = data->dur; + dat->application = data->application; + dat->parent = data->parent; + data = dat; + } +} +void OPimNotify::deref() { + if ( data->deref() ) { + delete data; + data = 0; + } +} + +/***********************************************************/ +struct OPimAlarm::Data : public QShared { + Data() : QShared() { + sound = 1; + } + int sound; + QString file; +}; +OPimAlarm::OPimAlarm( int sound, const QDateTime& start, int duration, int parent ) + : OPimNotify( start, duration, parent ) +{ + data = new Data; + data->sound = sound; +} +OPimAlarm::OPimAlarm( const OPimAlarm& al) + : OPimNotify(al), data( al.data ) +{ + data->ref(); +} +OPimAlarm::~OPimAlarm() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +OPimAlarm &OPimAlarm::operator=( const OPimAlarm& al) +{ + OPimNotify::operator=( al ); + deref(); + al.data->ref(); + + data = al.data; + + + return *this; +} +bool OPimAlarm::operator==( const OPimAlarm& al) { + if ( data->sound != al.data->sound ) return false; + else if ( data->sound == Custom && data->file != al.data->file ) + return false; + + return OPimNotify::operator==( al ); +} +QString OPimAlarm::type()const { + return QString::fromLatin1("OPimAlarm"); +} +int OPimAlarm::sound()const { + return data->sound; +} +QString OPimAlarm::file()const { + return data->file; +} +void OPimAlarm::setSound( int snd) { + copyIntern(); + data->sound = snd; +} +void OPimAlarm::setFile( const QString& sound ) { + copyIntern(); + data->file = sound; +} +void OPimAlarm::deref() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +void OPimAlarm::copyIntern() { + if ( data->count != 1 ) { + data->deref(); + Data *newDat = new Data; + newDat->sound = data->sound; + newDat->file = data->file; + data = newDat; + } +} +/************************/ +struct OPimReminder::Data : public QShared { + Data() : QShared(), record( 0) { + } + int record; + +}; +OPimReminder::OPimReminder( int uid, const QDateTime& start, int dur, int parent ) + : OPimNotify( start, dur, parent ) +{ + data = new Data; + data->record = uid; +} +OPimReminder::OPimReminder( const OPimReminder& rem ) + : OPimNotify( rem ), data( rem.data ) +{ + data->ref(); +} +OPimReminder& OPimReminder::operator=( const OPimReminder& rem) { + OPimNotify::operator=(rem ); + + deref(); + rem.data->ref(); + data = rem.data; + + return *this; +} +bool OPimReminder::operator==( const OPimReminder& rem) { + if ( data->record != rem.data->record ) return false; + + return OPimNotify::operator==( rem ); +} +QString OPimReminder::type()const { + return QString::fromLatin1("OPimReminder"); +} +int OPimReminder::recordUid()const { + return data->record; +} +void OPimReminder::setRecordUid( int uid ) { + copyIntern(); + data->record = uid; +} +void OPimReminder::deref() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +void OPimReminder::copyIntern() { + if ( data->count != 1 ) { + Data* da = new Data; + da->record = data->record; + data = da; + } +} diff --git a/noncore/unsupported/libopie/pim/opimnotify.h b/noncore/unsupported/libopie/pim/opimnotify.h new file mode 100644 index 0000000..58417db --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotify.h @@ -0,0 +1,144 @@ +#ifndef OPIE_PIM_NOTIFY_H +#define OPIE_PIM_NOTIFY_H + +#include <qdatetime.h> +#include <qvaluelist.h> + +/** + * This is the base class of Notifiers. Possible + * notifiers would be Alarms, Reminders + * What they share is that they have + * A DateTime, Type, Duration + * This is what this base class takes care of + * on top of that it's shared + */ +/* + * TALK to eilers: have a class OPimDuration which sets the Duration + * given on the Due/Start Date? -zecke + * discuss: do we need a uid for the notify? -zecke + */ +class OPimNotify { +public: + typedef QValueList<OPimNotify> ValueList; + OPimNotify( const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 ); + OPimNotify( const OPimNotify& ); + virtual ~OPimNotify(); + + OPimNotify &operator=(const OPimNotify& ); + bool operator==( const OPimNotify& ); + + virtual QString type()const = 0; + + /** start date */ + QDateTime dateTime()const; + QString service()const; + + /** + * RETURN the parent uid + */ + int parent()const; + + /** + * in Seconds + */ + int duration()const; + + /** + * Start Time + Duration + */ + QDateTime endTime()const; + + void setDateTime( const QDateTime& ); + void setDuration( int dur ); + void setParent(int uid ); + void setService( const QString& ); + + +private: + inline void copyIntern(); + void deref(); + struct Data; + Data* data; + + /* d-pointer */ + class NotifyPrivate; + NotifyPrivate* d; + +}; +/** + * An alarm is a sound/mail/buzzer played/send + * at a given time to inform about + * an Event + */ +class OPimAlarm : public OPimNotify { +public: + enum Sound{Loud=1, Silent=0, Custom=2 }; + OPimAlarm( int sound = Silent, const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 ); + OPimAlarm( const OPimAlarm& ); + ~OPimAlarm(); + + OPimAlarm &operator=( const OPimAlarm& ); + bool operator==( const OPimAlarm& ); + QString type()const; + + int sound()const; + QString file()const; + + void setSound( int ); + /* only when sound is custom... */ + void setFile( const QString& sound ); + +private: + void deref(); + void copyIntern(); + struct Data; + Data * data; + + class Private; + Private* d; + +}; + +/** + * A Reminder will be put into the + * datebook + * Note that the returned dateTime() may be not valid. + * In these cases one must resolve the uid and get the OEvent + */ +class OPimReminder : public OPimNotify { +public: + + /** + * c'tor of a reminder + * @param uid The uid of the Record inside the Datebook + * @param start the StartDate invalid for all day... + * @param duration The duration of the event ( -1 for all day ) + * @param parent The 'parent' record of this reminder + */ + OPimReminder( int uid = 0, const QDateTime& start = QDateTime(), + int duration = 0, int parent = 0 ); + OPimReminder( const OPimReminder& ); + OPimReminder &operator=(const OPimReminder& ); + + QString type()const; + + bool operator==( const OPimReminder& ); + + /** + * the uid of the alarm + * inside the 'datebook' application + */ + int recordUid()const; + void setRecordUid( int uid ); + +private: + void deref(); + void copyIntern(); + + struct Data; + Data* data; + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimnotifymanager.cpp b/noncore/unsupported/libopie/pim/opimnotifymanager.cpp new file mode 100644 index 0000000..d6f0ead --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotifymanager.cpp @@ -0,0 +1,162 @@ +#include "opimnotifymanager.h" + +#include "oconversion.h" + +#include <qstringlist.h> + +OPimNotifyManager::OPimNotifyManager( const Reminders& rem, const Alarms& al) + : m_rem( rem ), m_al( al ) +{} +OPimNotifyManager::~OPimNotifyManager() { +} +/* use static_cast and type instead of dynamic... */ +void OPimNotifyManager::add( const OPimNotify& noti) { + if ( noti.type() == QString::fromLatin1("OPimReminder") ) { + const OPimReminder& rem = static_cast<const OPimReminder&>(noti); + m_rem.append( rem ); + }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { + const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); + m_al.append( al ); + } +} +void OPimNotifyManager::remove( const OPimNotify& noti) { + if ( noti.type() == QString::fromLatin1("OPimReminder") ) { + const OPimReminder& rem = static_cast<const OPimReminder&>(noti); + m_rem.remove( rem ); + }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { + const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); + m_al.remove( al ); + } +} +void OPimNotifyManager::replace( const OPimNotify& noti) { + if ( noti.type() == QString::fromLatin1("OPimReminder") ) { + const OPimReminder& rem = static_cast<const OPimReminder&>(noti); + m_rem.remove( rem ); + m_rem.append( rem ); + }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { + const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); + m_al.remove( al ); + m_al.append( al ); + } +} +OPimNotifyManager::Reminders OPimNotifyManager::reminders()const { + return m_rem; +} +OPimNotifyManager::Alarms OPimNotifyManager::alarms()const { + return m_al; +} +OPimAlarm OPimNotifyManager::alarmAtDateTime( const QDateTime& when, bool& found ) const { + Alarms::ConstIterator it; + found = true; + + for ( it = m_al.begin(); it != m_al.end(); ++it ){ + if ( (*it).dateTime() == when ) + return (*it); + } + + // Fall through if nothing could be found + found = false; + OPimAlarm empty; + return empty; +} + + +void OPimNotifyManager::setAlarms( const Alarms& al) { + m_al = al; +} +void OPimNotifyManager::setReminders( const Reminders& rem) { + m_rem = rem; +} +/* FIXME!!! */ +/** + * The idea is to check if the provider for our service + * is online + * if it is we will use QCOP + * if not the Factory to get the backend... + * Qtopia1.6 services would be kewl to have here.... + */ +void OPimNotifyManager::registerNotify( const OPimNotify& ) { + +} +/* FIXME!!! */ +/** + * same as above... + * Also implement Url model + * have a MainWindow.... + */ +void OPimNotifyManager::deregister( const OPimNotify& ) { + +} + +bool OPimNotifyManager::isEmpty()const { + qWarning("is Empty called on OPimNotifyManager %d %d", m_rem.count(), m_al.count() ); + if ( m_rem.isEmpty() && m_al.isEmpty() ) return true; + else return false; +} + +// Taken from otodoaccessxml.. +QString OPimNotifyManager::alarmsToString() const +{ + QString str; + + OPimNotifyManager::Alarms alarms = m_al; + if ( !alarms.isEmpty() ) { + QStringList als; + OPimNotifyManager::Alarms::Iterator it = alarms.begin(); + for ( ; it != alarms.end(); ++it ) { + /* only if time is valid */ + if ( (*it).dateTime().isValid() ) { + als << OConversion::dateTimeToString( (*it).dateTime() ) + + ":" + QString::number( (*it).duration() ) + + ":" + QString::number( (*it).sound() ) + + ":"; + } + } + // now write the list + qWarning("als: %s", als.join("____________").latin1() ); + str = als.join(";"); + } + + return str; +} +QString OPimNotifyManager::remindersToString() const +{ + QString str; + + OPimNotifyManager::Reminders reminders = m_rem; + if (!reminders.isEmpty() ) { + OPimNotifyManager::Reminders::Iterator it = reminders.begin(); + QStringList records; + for ( ; it != reminders.end(); ++it ) { + records << QString::number( (*it).recordUid() ); + } + str = records.join(";"); + } + + return str; +} + +void OPimNotifyManager::alarmsFromString( const QString& str ) +{ + QStringList als = QStringList::split(";", str ); + for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { + QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty + qWarning("alarm: %s", alarm.join("___").latin1() ); + qWarning("alarm[0]: %s %s", alarm[0].latin1(), + OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); + OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), + alarm[1].toInt() ); + add( al ); + } +} + +void OPimNotifyManager::remindersFromString( const QString& str ) +{ + + QStringList rems = QStringList::split(";", str ); + for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { + OPimReminder rem( (*it).toInt() ); + add( rem ); + } + +} diff --git a/noncore/unsupported/libopie/pim/opimnotifymanager.h b/noncore/unsupported/libopie/pim/opimnotifymanager.h new file mode 100644 index 0000000..f3c22f9 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotifymanager.h @@ -0,0 +1,91 @@ +#ifndef OPIE_PIM_NOTIFY_MANAGER_H +#define OPIE_PIM_NOTIFY_MANAGER_H + +#include <qvaluelist.h> + +#include <opie/opimnotify.h> + +/** + * The notify manager keeps track of the Notifiers.... + */ +class OPimNotifyManager { +public: + typedef QValueList<OPimReminder> Reminders; + typedef QValueList<OPimAlarm> Alarms; + OPimNotifyManager( const Reminders& rems = Reminders(), const Alarms& alarms = Alarms() ); + ~OPimNotifyManager(); + + /* we will cast it for you ;) */ + void add( const OPimNotify& ); + void remove( const OPimNotify& ); + /* replaces all with this one! */ + void replace( const OPimNotify& ); + + Reminders reminders()const; + + /** + * Return + */ + Alarms alarms()const; + + /** + * Return alarm at DateTime "when". If more than one is registered at this + * DateTime, the first one is returned. + * If none was found, an empty Alarm is returned. + * @param when The date and time of the returned alarm + * @param found Returns true if anything was found. + * @return Returns the found alarm at given DateTime. It is empty if found is false + * (nothing could be found at given date and time) + */ + OPimAlarm alarmAtDateTime( const QDateTime& when, bool& found ) const; + + void setAlarms( const Alarms& ); + void setReminders( const Reminders& ); + + /* register is a Ansi C keyword... */ + /** + * This function will register the Notify to the Alarm Server + * or datebook depending on the type of the notify + */ + void registerNotify( const OPimNotify& ); + + /** + * this will do the opposite.. + */ + void deregister( const OPimNotify& ); + + bool isEmpty()const; + + /** + * Return all alarms as string + */ + QString alarmsToString() const; + /** + * Return all notifiers as string + */ + QString remindersToString() const; + + /** + * Convert string to alarms + * @param str String created by alarmsToString() + */ + void alarmsFromString( const QString& str ); + + /** + * Convert string to reminders + * @param str String created by remindersToString() + */ + void remindersFromString( const QString& str ); + + + +private: + Reminders m_rem; + Alarms m_al; + + class Private; + Private *d; + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimrecord.cpp b/noncore/unsupported/libopie/pim/opimrecord.cpp new file mode 100644 index 0000000..2365748 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimrecord.cpp @@ -0,0 +1,182 @@ +#include <qarray.h> + +#include <qpe/categories.h> +#include <qpe/categoryselect.h> + +#include "opimrecord.h" + +Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia ); + + +OPimRecord::OPimRecord( int uid ) + : Qtopia::Record() { + + m_lastHit = -1; + setUid( uid ); +} +OPimRecord::~OPimRecord() { +} +OPimRecord::OPimRecord( const OPimRecord& rec ) + : Qtopia::Record( rec ) +{ + (*this) = rec; +} + +OPimRecord &OPimRecord::operator=( const OPimRecord& rec) { + if ( this == &rec ) return *this; + + Qtopia::Record::operator=( rec ); + m_xrefman = rec.m_xrefman; + m_lastHit = rec.m_lastHit; + + return *this; +} +/* + * category names + */ +QStringList OPimRecord::categoryNames( const QString& appname ) const { + QStringList list; + QArray<int> cats = categories(); + Categories catDB; + catDB.load( categoryFileName() ); + + for (uint i = 0; i < cats.count(); i++ ) { + list << catDB.label( appname, cats[i] ); + } + + return list; +} +void OPimRecord::setCategoryNames( const QStringList& ) { + +} +void OPimRecord::addCategoryName( const QString& ) { + Categories catDB; + catDB.load( categoryFileName() ); + + +} +bool OPimRecord::isEmpty()const { + return ( uid() == 0 ); +} +/*QString OPimRecord::crossToString()const { + QString str; + QMap<QString, QArray<int> >::ConstIterator it; + for (it = m_relations.begin(); it != m_relations.end(); ++it ) { + QArray<int> id = it.data(); + for ( uint i = 0; i < id.size(); ++i ) { + str += it.key() + "," + QString::number( i ) + ";"; + } + } + str = str.remove( str.length()-1, 1); // strip the ; + //qWarning("IDS " + str ); + + return str; + }*/ +/* if uid = 1 assign a new one */ +void OPimRecord::setUid( int uid ) { + if ( uid == 1) + uid = uidGen().generate(); + + Qtopia::Record::setUid( uid ); +}; +Qtopia::UidGen &OPimRecord::uidGen() { + return m_uidGen; +} +OPimXRefManager &OPimRecord::xrefmanager() { + return m_xrefman; +} +int OPimRecord::rtti(){ + return 0; +} + +/** + * now let's put our data into the stream + */ +/* + * First read UID + * Categories + * XRef + */ +bool OPimRecord::loadFromStream( QDataStream& stream ) { + int Int; + uint UInt; + stream >> Int; + setUid(Int); + + /** Categories */ + stream >> UInt; + QArray<int> array(UInt); + for (uint i = 0; i < UInt; i++ ) { + stream >> array[i]; + } + setCategories( array ); + + /* + * now we do the X-Ref stuff + */ + OPimXRef xref; + stream >> UInt; + for ( uint i = 0; i < UInt; i++ ) { + xref.setPartner( OPimXRef::One, partner( stream ) ); + xref.setPartner( OPimXRef::Two, partner( stream ) ); + m_xrefman.add( xref ); + } + + return true; +} +bool OPimRecord::saveToStream( QDataStream& stream )const { + /** UIDs */ + + stream << uid(); + + /** Categories */ + stream << categories().count(); + for ( uint i = 0; i < categories().count(); i++ ) { + stream << categories()[i]; + } + + /* + * first the XRef count + * then the xrefs + */ + stream << m_xrefman.list().count(); + for ( OPimXRef::ValueList::ConstIterator it = m_xrefman.list().begin(); + it != m_xrefman.list().end(); ++it ) { + flush( (*it).partner( OPimXRef::One), stream ); + flush( (*it).partner( OPimXRef::Two), stream ); + } + return true; +} +void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{ + str << par.service(); + str << par.uid(); + str << par.field(); +} +OPimXRefPartner OPimRecord::partner( QDataStream& stream ) { + OPimXRefPartner par; + QString str; + int i; + + stream >> str; + par.setService( str ); + + stream >> i; + par.setUid( i ); + + stream >> i ; + par.setField( i ); + + return par; +} +void OPimRecord::setLastHitField( int lastHit )const { + m_lastHit = lastHit; +} +int OPimRecord::lastHitField()const{ + return m_lastHit; +} +QMap<QString, QString> OPimRecord::toExtraMap()const { + return customMap; +} +void OPimRecord::setExtraMap( const QMap<QString, QString>& map) { + customMap = map; +} diff --git a/noncore/unsupported/libopie/pim/opimrecord.h b/noncore/unsupported/libopie/pim/opimrecord.h new file mode 100644 index 0000000..3d774e2 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimrecord.h @@ -0,0 +1,158 @@ +#ifndef OPIE_PIM_RECORD_H +#define OPIE_PIM_RECORD_H + +#include <qdatastream.h> +#include <qmap.h> +#include <qstring.h> +#include <qstringlist.h> + +/* + * we need to get customMap which is private... + */ +#define private protected +#include <qpe/palmtoprecord.h> +#undef private + +#include <opie/opimxrefmanager.h> + +/** + * This is the base class for + * all PIM Records + * + */ +class OPimRecord : public Qtopia::Record { +public: + /** + * c'tor + * uid of 0 isEmpty + * uid of 1 will be assigned a new one + */ + OPimRecord(int uid = 0); + ~OPimRecord(); + + /** + * copy c'tor + */ + OPimRecord( const OPimRecord& rec ); + + /** + * copy operator + */ + OPimRecord &operator=( const OPimRecord& ); + + /** + * category names resolved + */ + QStringList categoryNames( const QString& appname )const; + + /** + * set category names they will be resolved + */ + void setCategoryNames( const QStringList& ); + + /** + * addCategoryName adds a name + * to the internal category list + */ + void addCategoryName( const QString& ); + + /** + * if a Record isEmpty + * it's empty if it's 0 + */ + virtual bool isEmpty()const; + + /** + * toRichText summary + */ + virtual QString toRichText()const = 0; + + /** + * a small one line summary + */ + virtual QString toShortText()const = 0; + + /** + * the name of the Record + */ + virtual QString type()const = 0; + + /** + * matches the Records the regular expression? + */ + virtual bool match( const QString ®exp ) const + {setLastHitField( -1 ); + return Qtopia::Record::match(QRegExp(regexp));}; + + /** + * if implemented this function returns which item has been + * last hit by the match() function. + * or -1 if not implemented or no hit has occured + */ + int lastHitField()const; + + /** + * converts the internal structure to a map + */ + virtual QMap<int, QString> toMap()const = 0; + // virtual fromMap( const <int, QString>& map ) = 0; // Should be added in the future (eilers) + + /** + * key value representation of extra items + */ + QMap<QString, QString> toExtraMap()const; + void setExtraMap( const QMap<QString, QString>& ); + + /** + * the name for a recordField + */ + virtual QString recordField(int)const = 0; + + /** + * returns a reference of the + * Cross Reference Manager + * Partner 'One' is THIS PIM RECORD! + * 'Two' is the Partner where we link to + */ + OPimXRefManager& xrefmanager(); + + /** + * set the uid + */ + virtual void setUid( int uid ); + + /* + * used inside the Templates for casting + * REIMPLEMENT in your .... + */ + static int rtti(); + + /** + * some marshalling and de marshalling code + * saves the OPimRecord + * to and from a DataStream + */ + virtual bool loadFromStream(QDataStream& ); + virtual bool saveToStream( QDataStream& stream )const; + +protected: + // need to be const cause it is called from const methods + mutable int m_lastHit; + void setLastHitField( int lastHit )const; + Qtopia::UidGen &uidGen(); +// QString crossToString()const; + +private: + class OPimRecordPrivate; + OPimRecordPrivate *d; + OPimXRefManager m_xrefman; + static Qtopia::UidGen m_uidGen; + +private: + void flush( const OPimXRefPartner&, QDataStream& stream )const; + OPimXRefPartner partner( QDataStream& ); +}; + + + +#endif diff --git a/noncore/unsupported/libopie/pim/opimresolver.cpp b/noncore/unsupported/libopie/pim/opimresolver.cpp new file mode 100644 index 0000000..4ebbd6e --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimresolver.cpp @@ -0,0 +1,198 @@ +#include <qcopchannel_qws.h> + +#include <qpe/qcopenvelope_qws.h> + +#include "otodoaccess.h" +#include "ocontactaccess.h" + +//#include "opimfactory.h" +#include "opimresolver.h" + +OPimResolver* OPimResolver::m_self = 0l; + +OPimResolver::OPimResolver() { + /* the built in channels */ + m_builtIns << "Todolist" << "Addressbook" << "Datebook"; +} +OPimResolver* OPimResolver::self() { + if (!m_self) + m_self = new OPimResolver(); + + return m_self; +} + +/* + * FIXME use a cache here too + */ +OPimRecord* OPimResolver::record( const QString& service, int uid ) { + OPimRecord* rec = 0l; + OPimBase* base = backend( service ); + + if ( base ) + rec = base->record( uid ); + delete base; + + return rec; +} +OPimRecord* OPimResolver::record( const QString& service ) { + return record( serviceId( service ) ); +} +OPimRecord* OPimResolver::record( int rtti ) { + OPimRecord* rec = 0l; + switch( rtti ) { + case 1: /* todolist */ + rec = new OTodo(); + case 2: /* contact */ + rec = new OContact(); + default: + break; + } + /* + * FIXME resolve externally + */ + if (!rec ) { + ; + } + return 0l; +} +bool OPimResolver::isBuiltIn( const QString& str) const{ + return m_builtIns.contains( str ); +} +QCString OPimResolver::qcopChannel( enum BuiltIn& built)const { + QCString str("QPE/"); + switch( built ) { + case TodoList: + str += "Todolist"; + break; + case DateBook: + str += "Datebook"; + break; + case AddressBook: + str += "Addressbook"; + break; + default: + break; + } + + return str; +} +QCString OPimResolver::qcopChannel( const QString& service )const { + QCString str("QPE/"); + str += service.latin1(); + return str; +} +/* + * Implement services!! + * FIXME + */ +QCString OPimResolver::applicationChannel( enum BuiltIn& built)const { + QCString str("QPE/Application/"); + switch( built ) { + case TodoList: + str += "todolist"; + break; + case DateBook: + str += "datebook"; + break; + case AddressBook: + str += "addressbook"; + break; + } + + return str; +} +QCString OPimResolver::applicationChannel( const QString& service )const { + QCString str("QPE/Application/"); + + if ( isBuiltIn( service ) ) { + if ( service == "Todolist" ) + str += "todolist"; + else if ( service == "Datebook" ) + str += "datebook"; + else if ( service == "Addressbook" ) + str += "addressbook"; + }else + ; // FIXME for additional stuff + + return str; +} +QStringList OPimResolver::services()const { + return m_builtIns; +} +QString OPimResolver::serviceName( int rtti ) const{ + QString str; + switch ( rtti ) { + case TodoList: + str = "Todolist"; + break; + case DateBook: + str = "Datebook"; + break; + case AddressBook: + str = "Addressbook"; + break; + default: + break; + } + return str; + // FIXME me for 3rd party +} +int OPimResolver::serviceId( const QString& service ) { + int rtti = 0; + if ( service == "Todolist" ) + rtti = TodoList; + else if ( service == "Datebook" ) + rtti = DateBook; + else if ( service == "Addressbook" ) + rtti = AddressBook; + + return rtti; +} +/** + * check if the 'service' is registered and if so we'll + */ +bool OPimResolver::add( const QString& service, const OPimRecord& rec) { + if ( QCopChannel::isRegistered( applicationChannel( service ) ) ) { + QByteArray data; + QDataStream arg(data, IO_WriteOnly ); + if ( rec.saveToStream( arg ) ) { + QCopEnvelope env( applicationChannel( service ), "add(int,QByteArray)" ); + env << rec.rtti(); + env << data; + }else + return false; + }else{ + OPimBase* base = backend( service ); + if (!base ) return false; + + base->load(); + base->add( rec ); + base->save(); + delete base; + } + + return true; +} +OPimBase* OPimResolver::backend( const QString& service ) { + return backend( serviceId( service ) ); +} +OPimBase* OPimResolver::backend( int rtti ) { + OPimBase* base = 0l; + switch( rtti ) { + case TodoList: + base = new OTodoAccess(); + break; + case DateBook: + break; + case AddressBook: + base = new OContactAccess("Resolver"); + break; + default: + break; + } + // FIXME for 3rd party + if (!base ) + ; + + return base; +} diff --git a/noncore/unsupported/libopie/pim/opimresolver.h b/noncore/unsupported/libopie/pim/opimresolver.h new file mode 100644 index 0000000..1ce1619 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimresolver.h @@ -0,0 +1,90 @@ +#ifndef OPIE_PIM_RESOLVER +#define OPIE_PIM_RESOLVER + +#include <qstring.h> +#include <qvaluelist.h> + +#include <opie/otemplatebase.h> + +/** + * OPimResolver is a MetaClass to access + * available backends read only. + * It will be used to resolve uids + app names + * to full informations + * to traverse through a list of alarms, reminders + * to get access to built in PIM functionality + * and to more stuff + * THE PERFORMANCE will depend on THE BACKEND + * USING XML is a waste of memory!!!!! + */ +class OPimResolver { +public: + enum BuiltIn { TodoList = 0, + DateBook, + AddressBook + }; + static OPimResolver* self(); + + + /** + * return a record for a uid + * and an service + * You've THE OWNERSHIP NOW! + */ + OPimRecord *record( const QString& service, int uid ); + + /** + * return the QCopChannel for service + * When we will use Qtopia Services it will be used here + */ + QCString qcopChannel( enum BuiltIn& )const; + QCString qcopChannel( const QString& service )const; + + /** + * The Application channel (QPE/Application/name) + */ + QCString applicationChannel( enum BuiltIn& )const; + QCString applicationChannel( const QString& service )const; + + /** + * return a list of available services + */ + QStringList services()const; + inline QString serviceName(int rrti )const; + int serviceId( const QString& Service); + /** + * add a record to a service... ;) + */ + bool add( const QString& service, const OPimRecord& ); + + + /** + * record returns an empty record for a given service. + * Be sure to delete it!!! + * + */ + OPimRecord* record( const QString& service ); + OPimRecord* record( int rtti ); + + /** + * you can cast to your + */ + OPimBase* backend( const QString& service ); + OPimBase* backend( int rtti ); +private: + OPimResolver(); + void loadData(); + inline bool isBuiltIn( const QString& )const; + OPimRecord* recordExtern( const QString&, int ); + OPimRecord* recordExtern( const QString& ); + + static OPimResolver* m_self; + struct Data; + class Private; + + Data* data; + Private* d; + QStringList m_builtIns; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimstate.cpp b/noncore/unsupported/libopie/pim/opimstate.cpp new file mode 100644 index 0000000..6fb2feb --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimstate.cpp @@ -0,0 +1,64 @@ +#include <qshared.h> + +#include "opimstate.h" + +/* + * for one int this does not make + * much sense but never the less + * we will do it for the future + */ +struct OPimState::Data : public QShared { + Data() : QShared(),state(Undefined) { + } + int state; +}; + +OPimState::OPimState( int state ) { + data = new Data; + data->state = state; +} +OPimState::OPimState( const OPimState& st) : + data( st.data ) { + /* ref up */ + data->ref(); +} +OPimState::~OPimState() { + if ( data->deref() ) { + delete data ; + data = 0; + } +} +bool OPimState::operator==( const OPimState& st) { + if ( data->state == st.data->state ) return true; + + return false; +} +OPimState &OPimState::operator=( const OPimState& st) { + st.data->ref(); + deref(); + data = st.data; + + return *this; +} +void OPimState::setState( int st) { + copyInternally(); + data->state = st; +} +int OPimState::state()const { + return data->state; +} +void OPimState::deref() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +void OPimState::copyInternally() { + /* we need to change it */ + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->state = data->state; + data = d2; + } +} diff --git a/noncore/unsupported/libopie/pim/opimstate.h b/noncore/unsupported/libopie/pim/opimstate.h new file mode 100644 index 0000000..cf6af46 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimstate.h @@ -0,0 +1,46 @@ +#ifndef OPIE_PIM_STATE_H +#define OPIE_PIM_STATE_H + +#include <qstring.h> + +/** + * The State of a Task + * This class encapsules the state of a todo + * and it's shared too + */ +/* + * in c a simple struct would be enough ;) + * g_new_state(); + * g_do_some_thing( state_t* ); + * ;) + */ +class OPimState { +public: + enum State { + Started = 0, + Postponed, + Finished, + NotStarted, + Undefined + }; + OPimState( int state = Undefined ); + OPimState( const OPimState& ); + ~OPimState(); + + bool operator==( const OPimState& ); + OPimState &operator=( const OPimState& ); + void setState( int state); + int state()const; +private: + void deref(); + inline void copyInternally(); + + struct Data; + Data* data; + + class Private; + Private *d; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/opimxref.cpp b/noncore/unsupported/libopie/pim/opimxref.cpp new file mode 100644 index 0000000..8eefbd8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxref.cpp @@ -0,0 +1,47 @@ +#include "opimxref.h" + +OPimXRef::OPimXRef( const OPimXRefPartner& one, const OPimXRefPartner& two ) + : m_partners(2) +{ + m_partners[0] = one; + m_partners[1] = two; +} +OPimXRef::OPimXRef() + : m_partners(2) +{ + +} +OPimXRef::OPimXRef( const OPimXRef& ref) { + *this = ref; +} +OPimXRef::~OPimXRef() { +} +OPimXRef &OPimXRef::operator=( const OPimXRef& ref) { + m_partners = ref.m_partners; + m_partners.detach(); + + return* this; +} +bool OPimXRef::operator==( const OPimXRef& oper ) { + if ( m_partners == oper.m_partners ) return true; + + return false; +} +OPimXRefPartner OPimXRef::partner( enum Partners par) const{ + return m_partners[par]; +} +void OPimXRef::setPartner( enum Partners par, const OPimXRefPartner& part) { + m_partners[par] = part; +} +bool OPimXRef::containsString( const QString& string ) const{ + if ( m_partners[One].service() == string || + m_partners[Two].service() == string ) return true; + + return false; +} +bool OPimXRef::containsUid( int uid ) const{ + if ( m_partners[One].uid() == uid || + m_partners[Two].uid() == uid ) return true; + + return false; +} diff --git a/noncore/unsupported/libopie/pim/opimxref.h b/noncore/unsupported/libopie/pim/opimxref.h new file mode 100644 index 0000000..6852651 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxref.h @@ -0,0 +1,39 @@ +#ifndef OPIM_XREF_H +#define OPIM_XREF_H + +#include <qarray.h> +#include <qvaluelist.h> + +#include <opie/opimxrefpartner.h> + +/** + * this is a Cross Referecne between + * two Cross Reference Partners + */ +class OPimXRef { +public: + typedef QValueList<OPimXRef> ValueList; + enum Partners { One, Two }; + OPimXRef( const OPimXRefPartner& ONE, const OPimXRefPartner& ); + OPimXRef(); + OPimXRef( const OPimXRef& ); + ~OPimXRef(); + + OPimXRef &operator=( const OPimXRef& ); + bool operator==( const OPimXRef& ); + + OPimXRefPartner partner( enum Partners )const; + + void setPartner( enum Partners, const OPimXRefPartner& ); + + bool containsString( const QString& service)const; + bool containsUid( int uid )const; + +private: + QArray<OPimXRefPartner> m_partners; + + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimxrefmanager.cpp b/noncore/unsupported/libopie/pim/opimxrefmanager.cpp new file mode 100644 index 0000000..58bfd24 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefmanager.cpp @@ -0,0 +1,71 @@ +#include "opimxrefmanager.h" + + +OPimXRefManager::OPimXRefManager() { +} +OPimXRefManager::OPimXRefManager( const OPimXRefManager& ref) { + m_list = ref.m_list; +} +OPimXRefManager::~OPimXRefManager() { +} +OPimXRefManager &OPimXRefManager::operator=( const OPimXRefManager& ref) { + m_list = ref.m_list; + return *this; +} +bool OPimXRefManager::operator==( const OPimXRefManager& /*ref*/) { + // if ( m_list == ref.m_list ) return true; + + return false; +} +void OPimXRefManager::add( const OPimXRef& ref) { + m_list.append( ref ); +} +void OPimXRefManager::remove( const OPimXRef& ref) { + m_list.remove( ref ); +} +void OPimXRefManager::replace( const OPimXRef& ref) { + m_list.remove( ref ); + m_list.append( ref ); +} +void OPimXRefManager::clear() { + m_list.clear(); +} +QStringList OPimXRefManager::apps()const { + OPimXRef::ValueList::ConstIterator it; + QStringList list; + + QString str; + for ( it = m_list.begin(); it != m_list.end(); ++it ) { + str = (*it).partner( OPimXRef::One ).service(); + if ( !list.contains( str ) ) list << str; + + str = (*it).partner( OPimXRef::Two ).service(); + if ( !list.contains( str ) ) list << str; + } + return list; +} +OPimXRef::ValueList OPimXRefManager::list()const { + return m_list; +} +OPimXRef::ValueList OPimXRefManager::list( const QString& appName )const{ + OPimXRef::ValueList list; + OPimXRef::ValueList::ConstIterator it; + + for ( it = m_list.begin(); it != m_list.end(); ++it ) { + if ( (*it).containsString( appName ) ) + list.append( (*it) ); + } + + return list; +} +OPimXRef::ValueList OPimXRefManager::list( int uid )const { + OPimXRef::ValueList list; + OPimXRef::ValueList::ConstIterator it; + + for ( it = m_list.begin(); it != m_list.end(); ++it ) { + if ( (*it).containsUid( uid ) ) + list.append( (*it) ); + } + + return list; +} diff --git a/noncore/unsupported/libopie/pim/opimxrefmanager.h b/noncore/unsupported/libopie/pim/opimxrefmanager.h new file mode 100644 index 0000000..c485e98 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefmanager.h @@ -0,0 +1,43 @@ +#ifndef OPIM_XREF_MANAGER_H +#define OPIM_XREF_MANAGER_H + +#include <qstringlist.h> + +#include <opie/opimxref.h> + +/** + * This is a simple manager for + * OPimXRefs. + * It allows addition, removing, replacing + * clearing and 'querying' the XRef... + */ +class OPimXRefManager { +public: + OPimXRefManager(); + OPimXRefManager( const OPimXRefManager& ); + ~OPimXRefManager(); + + OPimXRefManager& operator=( const OPimXRefManager& ); + bool operator==( const OPimXRefManager& ); + + void add( const OPimXRef& ); + void remove( const OPimXRef& ); + void replace( const OPimXRef& ); + + void clear(); + + /** + * apps participating + */ + QStringList apps()const; + OPimXRef::ValueList list()const; + OPimXRef::ValueList list( const QString& service )const; + OPimXRef::ValueList list( int uid )const; + +private: + OPimXRef::ValueList m_list; + class Private; + Private *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/opimxrefpartner.cpp b/noncore/unsupported/libopie/pim/opimxrefpartner.cpp new file mode 100644 index 0000000..6ef3efb --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefpartner.cpp @@ -0,0 +1,43 @@ +#include "opimxrefpartner.h" + +OPimXRefPartner::OPimXRefPartner( const QString& appName, + int uid, int field ) + : m_app(appName), m_uid(uid), m_field( field ) { +} +OPimXRefPartner::OPimXRefPartner( const OPimXRefPartner& ref ) { + *this = ref; +} +OPimXRefPartner::~OPimXRefPartner() { +} +OPimXRefPartner &OPimXRefPartner::operator=( const OPimXRefPartner& par ) { + m_app = par.m_app; + m_uid = par.m_uid; + m_field = par.m_field; + + return *this; +} +bool OPimXRefPartner::operator==( const OPimXRefPartner& par ) { + if ( m_app != par.m_app ) return false; + if ( m_uid != par.m_uid ) return false; + if ( m_field != par.m_field ) return false; + + return true; +} +QString OPimXRefPartner::service()const { + return m_app; +} +int OPimXRefPartner::uid()const { + return m_uid; +} +int OPimXRefPartner::field()const { + return m_field; +} +void OPimXRefPartner::setService( const QString& appName ) { + m_app = appName; +} +void OPimXRefPartner::setUid( int uid ) { + m_uid = uid; +} +void OPimXRefPartner::setField( int field ) { + m_field = field; +} diff --git a/noncore/unsupported/libopie/pim/opimxrefpartner.h b/noncore/unsupported/libopie/pim/opimxrefpartner.h new file mode 100644 index 0000000..d76e384 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefpartner.h @@ -0,0 +1,40 @@ +#ifndef OPIM_XREF_PARTNER_H +#define OPIM_XREF_PARTNER_H + +#include <qstring.h> + +/** + * This class represents one partner + * of a Cross Reference. + * In Opie one application + * can link one uid + * with one tableId( fieldId ) to another. + */ +class OPimXRefPartner { +public: + OPimXRefPartner( const QString& service = QString::null, + int uid = 0, int field = -1 ); + OPimXRefPartner( const OPimXRefPartner& ); + OPimXRefPartner& operator=( const OPimXRefPartner& ); + ~OPimXRefPartner(); + + bool operator==(const OPimXRefPartner& ); + + QString service()const; + int uid()const; + int field()const; + + void setService( const QString& service ); + void setUid( int uid ); + void setField( int field ); +private: + QString m_app; + int m_uid; + int m_field; + + class Private; + Private* d; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/orecordlist.h b/noncore/unsupported/libopie/pim/orecordlist.h new file mode 100644 index 0000000..5211f57 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecordlist.h @@ -0,0 +1,306 @@ + +#ifndef OPIE_RECORD_LIST_H +#define OPIE_RECORD_LIST_H + +#include <qarray.h> + +#include "otemplatebase.h" +#include "opimrecord.h" + +class ORecordListIteratorPrivate; +/** + * Our List Iterator + * it behaves like STL or Qt + * + * for(it = list.begin(); it != list.end(); ++it ) + * doSomeCoolStuff( (*it) ); + */ +template <class T> class ORecordList; +template <class T = OPimRecord> +class ORecordListIterator { + friend class ORecordList<T>; +public: + typedef OTemplateBase<T> Base; + + /** + * The c'tor used internally from + * ORecordList + */ + ORecordListIterator( const QArray<int>, const Base* ); + + /** + * The standard c'tor + */ + ORecordListIterator(); + ~ORecordListIterator(); + + ORecordListIterator( const ORecordListIterator& ); + ORecordListIterator &operator=(const ORecordListIterator& ); + + /** + * a * operator ;) + * use it like this T = (*it); + */ + T operator*(); + ORecordListIterator &operator++(); + ORecordListIterator &operator--(); + + bool operator==( const ORecordListIterator& it ); + bool operator!=( const ORecordListIterator& it ); + + /** + * the current item + */ + uint current()const; + + /** + * the number of items + */ + uint count()const; + + /** + * sets the current item + */ + void setCurrent( uint cur ); + +private: + QArray<int> m_uids; + uint m_current; + const Base* m_temp; + bool m_end : 1; + T m_record; + bool m_direction :1; + + /* d pointer for future versions */ + ORecordListIteratorPrivate *d; +}; + +class ORecordListPrivate; +/** + * The recordlist used as a return type + * from OPimAccessTemplate + */ +template <class T = OPimRecord > +class ORecordList { +public: + typedef OTemplateBase<T> Base; + typedef ORecordListIterator<T> Iterator; + + /** + * c'tor + */ + ORecordList () { + } +ORecordList( const QArray<int>& ids, + const Base* ); + ~ORecordList(); + + /** + * the first iterator + */ + Iterator begin(); + + /** + * the end + */ + Iterator end(); + + /** + * the number of items in the list + */ + uint count()const; + + T operator[]( uint i ); + int uidAt(uint i ); + + /** + * Remove the contact with given uid + */ + bool remove( int uid ); + + /* + ConstIterator begin()const; + ConstIterator end()const; + */ +private: + QArray<int> m_ids; + const Base* m_acc; + ORecordListPrivate *d; +}; + +/* ok now implement it */ +template <class T> +ORecordListIterator<T>::ORecordListIterator() { + m_current = 0; + m_temp = 0l; + m_end = true; + m_record = T(); + /* forward */ + m_direction = TRUE; +} +template <class T> +ORecordListIterator<T>::~ORecordListIterator() { +/* nothing to delete */ +} + +template <class T> +ORecordListIterator<T>::ORecordListIterator( const ORecordListIterator<T>& it) { +// qWarning("ORecordListIterator copy c'tor"); + m_uids = it.m_uids; + m_current = it.m_current; + m_temp = it.m_temp; + m_end = it.m_end; + m_record = it.m_record; + m_direction = it.m_direction; +} + +template <class T> +ORecordListIterator<T> &ORecordListIterator<T>::operator=( const ORecordListIterator<T>& it) { + m_uids = it.m_uids; + m_current = it.m_current; + m_temp = it.m_temp; + m_end = it.m_end; + m_record = it.m_record; + + return *this; +} + +template <class T> +T ORecordListIterator<T>::operator*() { + //qWarning("operator* %d %d", m_current, m_uids[m_current] ); + if (!m_end ) + m_record = m_temp->find( m_uids[m_current], m_uids, m_current, + m_direction ? Base::Forward : + Base::Reverse ); + else + m_record = T(); + + return m_record; +} + +template <class T> +ORecordListIterator<T> &ORecordListIterator<T>::operator++() { + m_direction = true; + if (m_current < m_uids.count() ) { + m_end = false; + ++m_current; + }else + m_end = true; + + return *this; +} +template <class T> +ORecordListIterator<T> &ORecordListIterator<T>::operator--() { + m_direction = false; + if ( m_current > 0 ) { + --m_current; + m_end = false; + } else + m_end = true; + + return *this; +} + +template <class T> +bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { + + /* if both are at we're the same.... */ + if ( m_end == it.m_end ) return true; + + if ( m_uids != it.m_uids ) return false; + if ( m_current != it.m_current ) return false; + if ( m_temp != it.m_temp ) return false; + + return true; +} +template <class T> +bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) { + return !(*this == it ); +} +template <class T> +ORecordListIterator<T>::ORecordListIterator( const QArray<int> uids, + const Base* t ) + : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ), + m_direction( false ) +{ + /* if the list is empty we're already at the end of the list */ + if (uids.count() == 0 ) + m_end = true; +} +template <class T> +uint ORecordListIterator<T>::current()const { + return m_current; +} +template <class T> +void ORecordListIterator<T>::setCurrent( uint cur ) { + if( cur < m_uids.count() ) { + m_end = false; + m_current= cur; + } +} +template <class T> +uint ORecordListIterator<T>::count()const { + return m_uids.count(); +} +template <class T> +ORecordList<T>::ORecordList( const QArray<int>& ids, + const Base* acc ) + : m_ids( ids ), m_acc( acc ) +{ +} +template <class T> +ORecordList<T>::~ORecordList() { +/* nothing to do here */ +} +template <class T> +typename ORecordList<T>::Iterator ORecordList<T>::begin() { + Iterator it( m_ids, m_acc ); + return it; +} +template <class T> +typename ORecordList<T>::Iterator ORecordList<T>::end() { + Iterator it( m_ids, m_acc ); + it.m_end = true; + it.m_current = m_ids.count(); + + return it; +} +template <class T> +uint ORecordList<T>::count()const { +return m_ids.count(); +} +template <class T> +T ORecordList<T>::operator[]( uint i ) { + if ( i >= m_ids.count() ) + return T(); + /* forward */ + return m_acc->find( m_ids[i], m_ids, i ); +} +template <class T> +int ORecordList<T>::uidAt( uint i ) { + return m_ids[i]; +} + +template <class T> +bool ORecordList<T>::remove( int uid ) { + QArray<int> copy( m_ids.count() ); + int counter = 0; + bool ret_val = false; + + for (uint i = 0; i < m_ids.count(); i++){ + if ( m_ids[i] != uid ){ + copy[counter++] = m_ids[i]; + + }else + ret_val = true; + } + + copy.resize( counter ); + m_ids = copy; + + + return ret_val; +} + + +#endif diff --git a/noncore/unsupported/libopie/pim/orecur.cpp b/noncore/unsupported/libopie/pim/orecur.cpp new file mode 100644 index 0000000..f46f22e --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecur.cpp @@ -0,0 +1,593 @@ +#include <time.h> + +#include <qshared.h> + +#include <qtopia/timeconversion.h> + +#include "otimezone.h" +#include "orecur.h" + +struct ORecur::Data : public QShared { + Data() : QShared() { + type = ORecur::NoRepeat; + freq = -1; + days = 0; + pos = 0; + create = QDateTime::currentDateTime(); + hasEnd = FALSE; + end = QDate::currentDate(); + } + char days; // Q_UINT8 for 8 seven days;) + ORecur::RepeatType type; + int freq; + int pos; + bool hasEnd : 1; + QDate end; + QDateTime create; + int rep; + QString app; + ExceptionList list; + QDate start; +}; + + +ORecur::ORecur() { + data = new Data; +} + +ORecur::ORecur( const QMap<int, QString>& map ) +{ + ORecur(); + fromMap( map ); +} + + +ORecur::ORecur( const ORecur& rec) + : data( rec.data ) +{ + data->ref(); +} +ORecur::~ORecur() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +void ORecur::deref() { + if ( data->deref() ) { + delete data; + data = 0l; + } +} +bool ORecur::operator==( const ORecur& )const { + return false; +} +ORecur &ORecur::operator=( const ORecur& re) { + if ( *this == re ) return *this; + + re.data->ref(); + deref(); + data = re.data; + + return *this; +} +bool ORecur::doesRecur()const { + return !( type() == NoRepeat ); +} +/* + * we try to be smart here + * + */ +bool ORecur::doesRecur( const QDate& date ) { + /* the day before the recurrance */ + QDate da = date.addDays(-1); + + QDate recur; + if (!nextOcurrence( da, recur ) ) + return false; + + return (recur == date); +} +// FIXME unuglify! +// GPL from Datebookdb.cpp +// FIXME exception list! +bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { + bool stillLooking; + stillLooking = p_nextOccurrence( from, next ); + while ( stillLooking && data->list.contains(next) ) + stillLooking = p_nextOccurrence( next.addDays(1), next ); + + return stillLooking; +} +bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) { + + // easy checks, first are we too far in the future or too far in the past? + QDate tmpDate; + int freq = frequency(); + int diff, diff2, a; + int iday, imonth, iyear; + int dayOfWeek = 0; + int firstOfWeek = 0; + int weekOfMonth; + + + if (hasEndDate() && endDate() < from) + return FALSE; + + if (start() >= from ) { + next = start(); + return TRUE; + } + + switch ( type() ) { + case Weekly: + /* weekly is just daily by 7 */ + /* first convert the repeatPattern.Days() mask to the next + day of week valid after from */ + dayOfWeek = from.dayOfWeek(); + dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */ + + /* this is done in case freq > 1 and from in week not + for this round */ + // firstOfWeek = 0; this is already done at decl. + while(!((1 << firstOfWeek) & days() )) + firstOfWeek++; + + /* there is at least one 'day', or there would be no event */ + while(!((1 << (dayOfWeek % 7)) & days() )) + dayOfWeek++; + + dayOfWeek = dayOfWeek % 7; /* the actual day of week */ + dayOfWeek -= start().dayOfWeek() -1; + + firstOfWeek = firstOfWeek % 7; /* the actual first of week */ + firstOfWeek -= start().dayOfWeek() -1; + + // dayOfWeek may be negitive now + // day of week is number of days to add to start day + + freq *= 7; + // FALL-THROUGH !!!!! + case Daily: + // the add is for the possible fall through from weekly */ + if(start().addDays(dayOfWeek) > from) { + /* first week exception */ + next = QDate(start().addDays(dayOfWeek) ); + if ((next > endDate()) + && hasEndDate() ) + return FALSE; + return TRUE; + } + /* if from is middle of a non-week */ + + diff = start().addDays(dayOfWeek).daysTo(from) % freq; + diff2 = start().addDays(firstOfWeek).daysTo(from) % freq; + + if(diff != 0) + diff = freq - diff; + if(diff2 != 0) + diff2 = freq - diff2; + diff = QMIN(diff, diff2); + + next = QDate(from.addDays(diff)); + if ( (next > endDate()) + && hasEndDate() ) + return FALSE; + return TRUE; + case MonthlyDay: + iday = from.day(); + iyear = from.year(); + imonth = from.month(); + /* find equivelent day of month for this month */ + dayOfWeek = start().dayOfWeek(); + weekOfMonth = (start().day() - 1) / 7; + + /* work out when the next valid month is */ + a = from.year() - start().year(); + a *= 12; + a = a + (imonth - start().month()); + /* a is e.start()monthsFrom(from); */ + if(a % freq) { + a = freq - (a % freq); + imonth = from.month() + a; + if (imonth > 12) { + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + } + } + /* imonth is now the first month after or on + from that matches the frequency given */ + + /* find for this month */ + tmpDate = QDate( iyear, imonth, 1 ); + + iday = 1; + iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; + iday += 7 * weekOfMonth; + while (iday > tmpDate.daysInMonth()) { + imonth += freq; + if (imonth > 12) { + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + } + tmpDate = QDate( iyear, imonth, 1 ); + /* these loops could go for a while, check end case now */ + if ((tmpDate > endDate()) && hasEndDate() ) + return FALSE; + iday = 1; + iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; + iday += 7 * weekOfMonth; + } + tmpDate = QDate(iyear, imonth, iday); + + if (tmpDate >= from) { + next = tmpDate; + if ((next > endDate() ) && hasEndDate() ) + return FALSE; + return TRUE; + } + + /* need to find the next iteration */ + do { + imonth += freq; + if (imonth > 12) { + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + } + tmpDate = QDate( iyear, imonth, 1 ); + /* these loops could go for a while, check end case now */ + if ((tmpDate > endDate()) && hasEndDate() ) + return FALSE; + iday = 1; + iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; + iday += 7 * weekOfMonth; + } while (iday > tmpDate.daysInMonth()); + tmpDate = QDate(iyear, imonth, iday); + + next = tmpDate; + if ((next > endDate()) && hasEndDate() ) + return FALSE; + return TRUE; + case MonthlyDate: + iday = start().day(); + iyear = from.year(); + imonth = from.month(); + + a = from.year() - start().year(); + a *= 12; + a = a + (imonth - start().month()); + /* a is e.start()monthsFrom(from); */ + if(a % freq) { + a = freq - (a % freq); + imonth = from.month() + a; + if (imonth > 12) { + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + } + } + /* imonth is now the first month after or on + from that matches the frequencey given */ + + /* this could go for a while, worse case, 4*12 iterations, probably */ + while(!QDate::isValid(iyear, imonth, iday) ) { + imonth += freq; + if (imonth > 12) { + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + } + /* these loops could go for a while, check end case now */ + if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) + return FALSE; + } + + if(QDate(iyear, imonth, iday) >= from) { + /* done */ + next = QDate(iyear, imonth, iday); + if ((next > endDate()) && hasEndDate() ) + return FALSE; + return TRUE; + } + + /* ok, need to cycle */ + imonth += freq; + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + + while(!QDate::isValid(iyear, imonth, iday) ) { + imonth += freq; + imonth--; + iyear += imonth / 12; + imonth = imonth % 12; + imonth++; + if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) + return FALSE; + } + + next = QDate(iyear, imonth, iday); + if ((next > endDate()) && hasEndDate() ) + return FALSE; + return TRUE; + case Yearly: + iday = start().day(); + imonth = start().month(); + iyear = from.year(); // after all, we want to start in this year + + diff = 1; + if(imonth == 2 && iday > 28) { + /* leap year, and it counts, calculate actual frequency */ + if(freq % 4) + if (freq % 2) + freq = freq * 4; + else + freq = freq * 2; + /* else divides by 4 already, leave freq alone */ + diff = 4; + } + + a = from.year() - start().year(); + if(a % freq) { + a = freq - (a % freq); + iyear = iyear + a; + } + + /* under the assumption we won't hit one of the special not-leap years twice */ + if(!QDate::isValid(iyear, imonth, iday)) { + /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ + iyear += freq; + } + + if(QDate(iyear, imonth, iday) >= from) { + next = QDate(iyear, imonth, iday); + + if ((next > endDate()) && hasEndDate() ) + return FALSE; + return TRUE; + } + /* iyear == from.year(), need to advance again */ + iyear += freq; + /* under the assumption we won't hit one of the special not-leap years twice */ + if(!QDate::isValid(iyear, imonth, iday)) { + /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ + iyear += freq; + } + + next = QDate(iyear, imonth, iday); + if ((next > endDate()) && hasEndDate() ) + return FALSE; + return TRUE; + default: + return FALSE; + } +} +ORecur::RepeatType ORecur::type()const{ + return data->type; +} +int ORecur::frequency()const { + return data->freq; +} +int ORecur::position()const { + return data->pos; +} +char ORecur::days() const{ + return data->days; +} +bool ORecur::hasEndDate()const { + return data->hasEnd; +} +QDate ORecur::endDate()const { + return data->end; +} +QDate ORecur::start()const{ + return data->start; +} +QDateTime ORecur::createdDateTime()const { + return data->create; +} +int ORecur::repetition()const { + return data->rep; +} +QString ORecur::service()const { + return data->app; +} +ORecur::ExceptionList& ORecur::exceptions() { + return data->list; +} +void ORecur::setType( const RepeatType& z) { + checkOrModify(); + data->type = z; +} +void ORecur::setFrequency( int freq ) { + checkOrModify(); + data->freq = freq; +} +void ORecur::setPosition( int pos ) { + checkOrModify(); + data->pos = pos; +} +void ORecur::setDays( char c ) { + checkOrModify(); + data->days = c; +} +void ORecur::setEndDate( const QDate& dt) { + checkOrModify(); + data->end = dt; +} +void ORecur::setCreatedDateTime( const QDateTime& t) { + checkOrModify(); + data->create = t; +} +void ORecur::setHasEndDate( bool b) { + checkOrModify(); + data->hasEnd = b; +} +void ORecur::setRepitition( int rep ) { + checkOrModify(); + data->rep = rep; +} +void ORecur::setService( const QString& app ) { + checkOrModify(); + data->app = app; +} +void ORecur::setStart( const QDate& dt ) { + checkOrModify(); + data->start = dt; +} +void ORecur::checkOrModify() { + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->days = data->days; + d2->type = data->type; + d2->freq = data->freq; + d2->pos = data->pos; + d2->hasEnd = data->hasEnd; + d2->end = data->end; + d2->create = data->create; + d2->rep = data->rep; + d2->app = data->app; + d2->list = data->list; + d2->start = data->start; + data = d2; + } +} +QString ORecur::toString()const { + QString buf; + QMap<int, QString> recMap = toMap(); + + buf += " rtype=\""; + buf += recMap[ORecur::RType]; + buf += "\""; + if (data->days > 0 ) + buf += " rweekdays=\"" + recMap[ORecur::RWeekdays] + "\""; + if ( data->pos != 0 ) + buf += " rposition=\"" + recMap[ORecur::RPosition] + "\""; + + buf += " rfreq=\"" + recMap[ORecur::RFreq] + "\""; + buf += " rhasenddate=\"" + recMap[ORecur::RHasEndDate]+ "\""; + if ( data->hasEnd ) + buf += " enddt=\"" + + recMap[ORecur::EndDate] + + "\""; + buf += " created=\"" + recMap[ORecur::Created] + "\""; + + if ( data->list.isEmpty() ) return buf; + buf += " exceptions=\""; + buf += recMap[ORecur::Exceptions]; + buf += "\" "; + + return buf; +} + +QString ORecur::rTypeString() const +{ + QString retString; + switch ( data->type ) { + case ORecur::Daily: + retString = "Daily"; + break; + case ORecur::Weekly: + retString = "Weekly"; + break; + case ORecur::MonthlyDay: + retString = "MonthlyDay"; + break; + case ORecur::MonthlyDate: + retString = "MonthlyDate"; + break; + case ORecur::Yearly: + retString = "Yearly"; + break; + default: + retString = "NoRepeat"; + break; + + } + + return retString; +} + +QMap<QString, ORecur::RepeatType> ORecur::rTypeValueConvertMap() const +{ + QMap<QString, RepeatType> convertMap; + + convertMap.insert( QString( "Daily" ), ORecur::Daily ); + convertMap.insert( QString( "Weekly" ), ORecur::Weekly ); + convertMap.insert( QString( "MonthlyDay" ), ORecur::MonthlyDay ); + convertMap.insert( QString( "MonthlyDate" ), ORecur::MonthlyDate ); + convertMap.insert( QString( "Yearly" ), ORecur::Yearly ); + convertMap.insert( QString( "NoRepeat" ), ORecur::NoRepeat ); + + return convertMap; +} + + +QMap<int, QString> ORecur::toMap() const +{ + QMap<int, QString> retMap; + + retMap.insert( ORecur::RType, rTypeString() ); + retMap.insert( ORecur::RWeekdays, QString::number( static_cast<int>( data->days ) ) ); + retMap.insert( ORecur::RPosition, QString::number(data->pos ) ); + retMap.insert( ORecur::RFreq, QString::number( data->freq ) ); + retMap.insert( ORecur::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) ); + if( data -> hasEnd ) + retMap.insert( ORecur::EndDate, QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) ); + retMap.insert( ORecur::Created, QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) ); + + if ( data->list.isEmpty() ) return retMap; + + // save exceptions list here!! + ExceptionList::ConstIterator it; + ExceptionList list = data->list; + QString exceptBuf; + QDate date; + for ( it = list.begin(); it != list.end(); ++it ) { + date = (*it); + if ( it != list.begin() ) exceptBuf += " "; + + exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() ); + } + + retMap.insert( ORecur::Exceptions, exceptBuf ); + + return retMap; +} + +void ORecur::fromMap( const QMap<int, QString>& map ) +{ + QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap(); + + data -> type = repTypeMap[ map [ORecur::RType] ]; + data -> days = (char) map[ ORecur::RWeekdays ].toInt(); + data -> pos = map[ ORecur::RPosition ].toInt(); + data -> freq = map[ ORecur::RFreq ].toInt(); + data -> hasEnd= map[ ORecur::RHasEndDate ].toInt() ? true : false; + OTimeZone utc = OTimeZone::utc(); + if ( data -> hasEnd ){ + data -> end = utc.fromUTCDateTime( (time_t) map[ ORecur::EndDate ].toLong() ).date(); + } + data -> create = utc.fromUTCDateTime( (time_t) map[ ORecur::Created ].toLong() ).date(); + +#if 0 + // FIXME: Exceptions currently not supported... + // Convert the list of exceptions from QString into ExceptionList + data -> list.clear(); + QString exceptStr = map[ ORecur::Exceptions ]; + QStringList exceptList = QStringList::split( " ", exceptStr ); + ... +#endif + + +} diff --git a/noncore/unsupported/libopie/pim/orecur.h b/noncore/unsupported/libopie/pim/orecur.h new file mode 100644 index 0000000..d7ecd90 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecur.h @@ -0,0 +1,107 @@ +/* + * GPL from TT + */ + +#ifndef OPIE_RECUR_H +#define OPIE_RECUR_H + +#include <sys/types.h> + +#include <qdatetime.h> +#include <qvaluelist.h> +#include <qmap.h> + + +/** + * Class to handle Recurrencies.. + */ + +class ORecur { +public: + typedef QValueList<QDate> ExceptionList; + enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay, + MonthlyDate, Yearly }; + enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, + FRI = 0x10, SAT = 0x20, SUN = 0x40 }; + enum Fields{ RType = 0, RWeekdays, RPosition, RFreq, RHasEndDate, + EndDate, Created, Exceptions }; + + ORecur(); + ORecur( const QMap<int, QString>& map ); + ORecur( const ORecur& ); + ~ORecur(); + + ORecur &operator=( const ORecur& ); + bool operator==(const ORecur& )const; + + bool doesRecur()const; + /* if it recurrs on that day */ + bool doesRecur( const QDate& ); + RepeatType type()const; + int frequency()const; + int position()const; + char days()const; + bool hasEndDate()const; + QDate start()const; + QDate endDate()const; + QDateTime createdDateTime()const; + /** + * starting on monday=0, sunday=6 + * for convience + */ + bool repeatOnWeekDay( int day )const; + + /** + * FromWhereToStart is not included!!! + */ + bool nextOcurrence( const QDate& FromWhereToStart, QDate &recurDate ); + + /** + * The module this ORecur belongs to + */ + QString service()const; + + /* + * reference to the exception list + */ + ExceptionList &exceptions(); + + /** + * the current repetition + */ + int repetition()const; + + void setType( const RepeatType& ); + void setFrequency( int freq ); + void setPosition( int pos ); + void setDays( char c); + void setEndDate( const QDate& dt ); + void setStart( const QDate& dt ); + void setCreatedDateTime( const QDateTime& ); + void setHasEndDate( bool b ); + void setRepitition(int ); + + void setService( const QString& ser ); + + QMap<int, QString> toMap() const; + void fromMap( const QMap<int, QString>& map ); + + /* almost internal */ + QString toString()const; +private: + bool p_nextOccurrence( const QDate& from, QDate& next ); + void deref(); + inline void checkOrModify(); + + /* Converts rType to String */ + QString rTypeString() const; + /* Returns a map to convert Stringname for RType to RepeatType */ + QMap<QString, RepeatType> rTypeValueConvertMap() const; + + class Data; + Data* data; + class ORecurPrivate; + ORecurPrivate *d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/otemplatebase.h b/noncore/unsupported/libopie/pim/otemplatebase.h new file mode 100644 index 0000000..cadac74 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otemplatebase.h @@ -0,0 +1,98 @@ +#ifndef OPIE_TEMPLATE_BASE_H +#define OPIE_TEMPLATE_BASE_H + +#include <qarray.h> + +#include <opie/opimrecord.h> + + +/** + * Templates do not have a base class, This is why + * we've this class + * this is here to give us the possibility + * to have a common base class + * You may not want to use that interface internaly + * POOR mans interface + */ +class OPimBasePrivate; +struct OPimBase { + /** + * return the rtti + */ + virtual int rtti()= 0; + virtual OPimRecord* record()const = 0; + virtual OPimRecord* record(int uid)const = 0; + virtual bool add( const OPimRecord& ) = 0; + virtual bool remove( int uid ) = 0; + virtual bool remove( const OPimRecord& ) = 0; + virtual void clear() = 0; + virtual bool load() = 0; + virtual bool save() = 0; + virtual QArray<int> records()const = 0; + /* + * ADD editing here? + * -zecke + */ +private: + OPimBasePrivate* d; + +}; +/** + * internal template base + * T needs to implement the copy c'tor!!! + */ +class OTemplateBasePrivate; +template <class T = OPimRecord> +class OTemplateBase : public OPimBase { +public: + enum CacheDirection { Forward=0, Reverse }; + OTemplateBase() { + }; + virtual ~OTemplateBase() { + } + virtual T find( int uid )const = 0; + + /** + * read ahead find + */ + virtual T find( int uid, const QArray<int>& items, + uint current, CacheDirection dir = Forward )const = 0; + virtual void cache( const T& )const = 0; + virtual void setSaneCacheSize( int ) = 0; + + /* reimplement of OPimBase */ + int rtti(); + OPimRecord* record()const; + OPimRecord* record(int uid )const; + static T* rec(); + +private: + OTemplateBasePrivate *d; +}; + +/* + * implementation + */ +template <class T> +int +OTemplateBase<T>::rtti() { + return T::rtti(); +} +template <class T> +OPimRecord* OTemplateBase<T>::record()const { + T* t = new T; + return t; +} +template <class T> +OPimRecord* OTemplateBase<T>::record(int uid )const { + T t2 = find(uid ); + T* t1 = new T(t2); + + return t1; +}; +template <class T> +T* OTemplateBase<T>::rec() { + return new T; +} + +#endif diff --git a/noncore/unsupported/libopie/pim/otimezone.cpp b/noncore/unsupported/libopie/pim/otimezone.cpp new file mode 100644 index 0000000..34659c3 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otimezone.cpp @@ -0,0 +1,113 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <sys/types.h> + +#include "otimezone.h" + +namespace { + + QDateTime utcTime( time_t t) { + tm* broken = ::gmtime( &t ); + QDateTime ret; + ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); + ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); + return ret; + } + QDateTime utcTime( time_t t, const QString& zone) { + QCString org = ::getenv( "TZ" ); +#ifndef Q_OS_MACX // Following line causes bus errors on Mac + ::setenv( "TZ", zone.latin1(), true ); + ::tzset(); + + tm* broken = ::localtime( &t ); + ::setenv( "TZ", org, true ); +#else +#warning "Need a replacement for MacOSX!!" + tm* broken = ::localtime( &t ); +#endif + + QDateTime ret; + ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); + ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); + + return ret; + } + time_t to_Time_t( const QDateTime& utc, const QString& str ) { + QDate d = utc.date(); + QTime t = utc.time(); + + tm broken; + broken.tm_year = d.year() - 1900; + broken.tm_mon = d.month() - 1; + broken.tm_mday = d.day(); + broken.tm_hour = t.hour(); + broken.tm_min = t.minute(); + broken.tm_sec = t.second(); + + QCString org = ::getenv( "TZ" ); +#ifndef Q_OS_MACX // Following line causes bus errors on Mac + ::setenv( "TZ", str.latin1(), true ); + ::tzset(); + + time_t ti = ::mktime( &broken ); + ::setenv( "TZ", org, true ); +#else +#warning "Need a replacement for MacOSX!!" + time_t ti = ::mktime( &broken ); +#endif + return ti; + } +} +OTimeZone::OTimeZone( const ZoneName& zone ) + : m_name(zone) { +} +OTimeZone::~OTimeZone() { +} + +bool OTimeZone::isValid()const { + return !m_name.isEmpty(); +} + +/* + * we will get the current timezone + * and ask it to convert to the timezone date + */ +QDateTime OTimeZone::toLocalDateTime( const QDateTime& dt) { + return OTimeZone::current().toDateTime( dt, *this ); +} +QDateTime OTimeZone::toUTCDateTime( const QDateTime& dt ) { + return OTimeZone::utc().toDateTime( dt, *this ); +} +QDateTime OTimeZone::fromUTCDateTime( time_t t) { + return utcTime( t ); +} +QDateTime OTimeZone::toDateTime( time_t t) { + return utcTime( t, m_name ); +} +/* + * convert dt to utc using zone.m_name + * convert utc -> timeZoneDT using this->m_name + */ +QDateTime OTimeZone::toDateTime( const QDateTime& dt, const OTimeZone& zone ) { + time_t utc = to_Time_t( dt, zone.m_name ); + qWarning("%d %s", utc, zone.m_name.latin1() ); + return utcTime( utc, m_name ); +} +time_t OTimeZone::fromDateTime( const QDateTime& time ) { + return to_Time_t( time, m_name ); +} +time_t OTimeZone::fromUTCDateTime( const QDateTime& time ) { + return to_Time_t( time, "UTC" ); +} +OTimeZone OTimeZone::current() { + QCString str = ::getenv("TZ"); + OTimeZone zone( str ); + return zone; +} +OTimeZone OTimeZone::utc() { + return OTimeZone("UTC"); +} +QString OTimeZone::timeZone()const { + return m_name; +} diff --git a/noncore/unsupported/libopie/pim/otimezone.h b/noncore/unsupported/libopie/pim/otimezone.h new file mode 100644 index 0000000..bb08349 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otimezone.h @@ -0,0 +1,71 @@ +#ifndef OPIE_TIME_ZONE_H +#define OPIE_TIME_ZONE_H + +#include <time.h> +#include <qdatetime.h> + +/** + * A very primitive class to convert time + * from one timezone to another + * and to localtime + * and time_t + */ +class OTimeZone { + public: + typedef QString ZoneName; + OTimeZone( const ZoneName& = ZoneName::null ); + virtual ~OTimeZone(); // just in case. + + bool isValid()const; + + /** + * converts the QDateTime to a DateTime + * in the local timezone + * if QDateTime is 25th Jan and takes place in Europe/Berlin at 12h + * and the current timezone is Europe/London the returned + * time will be 11h. + */ + QDateTime toLocalDateTime( const QDateTime& dt ); + + /** + * converts the QDateTime to UTC time + */ + QDateTime toUTCDateTime( const QDateTime& dt ); + + /** + * reads the time_t into a QDateTime using UTC as timezone! + */ + QDateTime fromUTCDateTime( time_t ); + + /** + * converts the time_t to the time in the timezone + */ + QDateTime toDateTime( time_t ); + + /** + * converts the QDateTime from one timezone to this timeZone + */ + QDateTime toDateTime( const QDateTime&, const OTimeZone& timeZone ); + + /** + * converts the date time into a time_t. It takes the timezone into account + */ + time_t fromDateTime( const QDateTime& ); + + /** + * converts the datetime with timezone UTC + */ + time_t fromUTCDateTime( const QDateTime& ); + + static OTimeZone current(); + static OTimeZone utc(); + + QString timeZone()const; + private: + ZoneName m_name; + class Private; + Private* d; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/otodo.cpp b/noncore/unsupported/libopie/pim/otodo.cpp new file mode 100644 index 0000000..b2c76f8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodo.cpp @@ -0,0 +1,519 @@ + +#include <qobject.h> +#include <qshared.h> + + + +#include <qpe/palmtopuidgen.h> +#include <qpe/palmtoprecord.h> +#include <qpe/categories.h> +#include <qpe/categoryselect.h> +#include <qpe/stringutil.h> + + +#include "opimstate.h" +#include "orecur.h" +#include "opimmaintainer.h" +#include "opimnotifymanager.h" +#include "opimresolver.h" + +#include "otodo.h" + + +struct OTodo::OTodoData : public QShared { + OTodoData() : QShared() { + recur = 0; + state = 0; + maintainer = 0; + notifiers = 0; + }; + ~OTodoData() { + delete recur; + delete maintainer; + delete notifiers; + } + + QDate date; + bool isCompleted:1; + bool hasDate:1; + int priority; + QString desc; + QString sum; + QMap<QString, QString> extra; + ushort prog; + OPimState *state; + ORecur *recur; + OPimMaintainer *maintainer; + QDate start; + QDate completed; + OPimNotifyManager *notifiers; +}; + +OTodo::OTodo(const OTodo &event ) + : OPimRecord( event ), data( event.data ) +{ + data->ref(); +// qWarning("ref up"); +} +OTodo::~OTodo() { + +// qWarning("~OTodo " ); + if ( data->deref() ) { +// qWarning("OTodo::dereffing"); + delete data; + data = 0l; + } +} +OTodo::OTodo(bool completed, int priority, + const QArray<int> &category, + const QString& summary, + const QString &description, + ushort progress, + bool hasDate, QDate date, int uid ) + : OPimRecord( uid ) +{ +// qWarning("OTodoData " + summary); + setCategories( category ); + + data = new OTodoData; + + data->date = date; + data->isCompleted = completed; + data->hasDate = hasDate; + data->priority = priority; + data->sum = summary; + data->prog = progress; + data->desc = Qtopia::simplifyMultiLineSpace(description ); +} +OTodo::OTodo(bool completed, int priority, + const QStringList &category, + const QString& summary, + const QString &description, + ushort progress, + bool hasDate, QDate date, int uid ) + : OPimRecord( uid ) +{ +// qWarning("OTodoData" + summary); + setCategories( idsFromString( category.join(";") ) ); + + data = new OTodoData; + + data->date = date; + data->isCompleted = completed; + data->hasDate = hasDate; + data->priority = priority; + data->sum = summary; + data->prog = progress; + data->desc = Qtopia::simplifyMultiLineSpace(description ); +} +bool OTodo::match( const QRegExp ®Exp )const +{ + if( QString::number( data->priority ).find( regExp ) != -1 ){ + setLastHitField( Priority ); + return true; + }else if( data->hasDate && data->date.toString().find( regExp) != -1 ){ + setLastHitField( HasDate ); + return true; + }else if(data->desc.find( regExp ) != -1 ){ + setLastHitField( Description ); + return true; + }else if(data->sum.find( regExp ) != -1 ) { + setLastHitField( Summary ); + return true; + } + return false; +} +bool OTodo::isCompleted() const +{ + return data->isCompleted; +} +bool OTodo::hasDueDate() const +{ + return data->hasDate; +} +bool OTodo::hasStartDate()const { + return data->start.isValid(); +} +bool OTodo::hasCompletedDate()const { + return data->completed.isValid(); +} +int OTodo::priority()const +{ + return data->priority; +} +QString OTodo::summary() const +{ + return data->sum; +} +ushort OTodo::progress() const +{ + return data->prog; +} +QDate OTodo::dueDate()const +{ + return data->date; +} +QDate OTodo::startDate()const { + return data->start; +} +QDate OTodo::completedDate()const { + return data->completed; +} +QString OTodo::description()const +{ + return data->desc; +} +bool OTodo::hasState() const{ + if (!data->state ) return false; + return ( data->state->state() != OPimState::Undefined ); +} +OPimState OTodo::state()const { + if (!data->state ) { + OPimState state; + return state; + } + + return (*data->state); +} +bool OTodo::hasRecurrence()const { + if (!data->recur) return false; + return data->recur->doesRecur(); +} +ORecur OTodo::recurrence()const { + if (!data->recur) return ORecur(); + + return (*data->recur); +} +bool OTodo::hasMaintainer()const { + if (!data->maintainer) return false; + + return (data->maintainer->mode() != OPimMaintainer::Undefined ); +} +OPimMaintainer OTodo::maintainer()const { + if (!data->maintainer) return OPimMaintainer(); + + return (*data->maintainer); +} +void OTodo::setCompleted( bool completed ) +{ + changeOrModify(); + data->isCompleted = completed; +} +void OTodo::setHasDueDate( bool hasDate ) +{ + changeOrModify(); + data->hasDate = hasDate; +} +void OTodo::setDescription(const QString &desc ) +{ +// qWarning( "desc " + desc ); + changeOrModify(); + data->desc = Qtopia::simplifyMultiLineSpace(desc ); +} +void OTodo::setSummary( const QString& sum ) +{ + changeOrModify(); + data->sum = sum; +} +void OTodo::setPriority(int prio ) +{ + changeOrModify(); + data->priority = prio; +} +void OTodo::setDueDate( const QDate& date ) +{ + changeOrModify(); + data->date = date; +} +void OTodo::setStartDate( const QDate& date ) { + changeOrModify(); + data->start = date; +} +void OTodo::setCompletedDate( const QDate& date ) { + changeOrModify(); + data->completed = date; +} +void OTodo::setState( const OPimState& state ) { + changeOrModify(); + if (data->state ) + (*data->state) = state; + else + data->state = new OPimState( state ); +} +void OTodo::setRecurrence( const ORecur& rec) { + changeOrModify(); + if (data->recur ) + (*data->recur) = rec; + else + data->recur = new ORecur( rec ); +} +void OTodo::setMaintainer( const OPimMaintainer& pim ) { + changeOrModify(); + + if (data->maintainer ) + (*data->maintainer) = pim; + else + data->maintainer = new OPimMaintainer( pim ); +} +bool OTodo::isOverdue( ) +{ + if( data->hasDate && !data->isCompleted) + return QDate::currentDate() > data->date; + return false; +} +void OTodo::setProgress(ushort progress ) +{ + changeOrModify(); + data->prog = progress; +} +QString OTodo::toShortText() const { + return summary(); +} +/*! + Returns a richt text string +*/ +QString OTodo::toRichText() const +{ + QString text; + QStringList catlist; + + // summary + text += "<b><h3><img src=\"todo/TodoList\"> "; + if ( !summary().isEmpty() ) { + text += Qtopia::escapeString(summary() ).replace(QRegExp( "[\n]"), "" ); + } + text += "</h3></b><br><hr><br>"; + + // description + if( !description().isEmpty() ){ + text += "<b>" + QObject::tr( "Description:" ) + "</b><br>"; + text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; + } + + // priority + int priorityval = priority(); + text += "<b>" + QObject::tr( "Priority:") +" </b><img src=\"todo/priority" + + QString::number( priorityval ) + "\"> "; + + switch ( priorityval ) + { + case 1 : text += QObject::tr( "Very high" ); + break; + case 2 : text += QObject::tr( "High" ); + break; + case 3 : text += QObject::tr( "Normal" ); + break; + case 4 : text += QObject::tr( "Low" ); + break; + case 5 : text += QObject::tr( "Very low" ); + break; + }; + text += "<br>"; + + // progress + text += "<b>" + QObject::tr( "Progress:") + " </b>" + + QString::number( progress() ) + " %<br>"; + + // due date + if (hasDueDate() ){ + QDate dd = dueDate(); + int off = QDate::currentDate().daysTo( dd ); + + text += "<b>" + QObject::tr( "Deadline:" ) + " </b><font color=\""; + if ( off < 0 ) + text += "#FF0000"; + else if ( off == 0 ) + text += "#FFFF00"; + else if ( off > 0 ) + text += "#00FF00"; + + text += "\">" + dd.toString() + "</font><br>"; + } + + // categories + text += "<b>" + QObject::tr( "Category:") + "</b> "; + text += categoryNames( "Todo List" ).join(", "); + text += "<br>"; + + return text; +} +bool OTodo::hasNotifiers()const { + if (!data->notifiers) return false; + return !data->notifiers->isEmpty(); +} +OPimNotifyManager& OTodo::notifiers() { + if (!data->notifiers ) + data->notifiers = new OPimNotifyManager; + return (*data->notifiers); +} +const OPimNotifyManager& OTodo::notifiers()const{ + if (!data->notifiers ) + data->notifiers = new OPimNotifyManager; + + return (*data->notifiers); +} + +bool OTodo::operator<( const OTodo &toDoEvent )const{ + if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; + if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; + if( hasDueDate() && toDoEvent.hasDueDate() ){ + if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide + return priority() < toDoEvent.priority(); + }else{ + return dueDate() < toDoEvent.dueDate(); + } + } + return false; +} +bool OTodo::operator<=(const OTodo &toDoEvent )const +{ + if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; + if( !hasDueDate() && toDoEvent.hasDueDate() ) return true; + if( hasDueDate() && toDoEvent.hasDueDate() ){ + if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide + return priority() <= toDoEvent.priority(); + }else{ + return dueDate() <= toDoEvent.dueDate(); + } + } + return true; +} +bool OTodo::operator>(const OTodo &toDoEvent )const +{ + if( !hasDueDate() && !toDoEvent.hasDueDate() ) return false; + if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; + if( hasDueDate() && toDoEvent.hasDueDate() ){ + if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide + return priority() > toDoEvent.priority(); + }else{ + return dueDate() > toDoEvent.dueDate(); + } + } + return false; +} +bool OTodo::operator>=(const OTodo &toDoEvent )const +{ + if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; + if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; + if( hasDueDate() && toDoEvent.hasDueDate() ){ + if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide + return priority() > toDoEvent.priority(); + }else{ + return dueDate() > toDoEvent.dueDate(); + } + } + return true; +} +bool OTodo::operator==(const OTodo &toDoEvent )const +{ + if ( data->priority != toDoEvent.data->priority ) return false; + if ( data->priority != toDoEvent.data->prog ) return false; + if ( data->isCompleted != toDoEvent.data->isCompleted ) return false; + if ( data->hasDate != toDoEvent.data->hasDate ) return false; + if ( data->date != toDoEvent.data->date ) return false; + if ( data->sum != toDoEvent.data->sum ) return false; + if ( data->desc != toDoEvent.data->desc ) return false; + if ( data->maintainer != toDoEvent.data->maintainer ) + return false; + + return OPimRecord::operator==( toDoEvent ); +} +void OTodo::deref() { + +// qWarning("deref in ToDoEvent"); + if ( data->deref() ) { +// qWarning("deleting"); + delete data; + data= 0; + } +} +OTodo &OTodo::operator=(const OTodo &item ) +{ + if ( this == &item ) return *this; + + OPimRecord::operator=( item ); + //qWarning("operator= ref "); + item.data->ref(); + deref(); + data = item.data; + + return *this; +} + +QMap<int, QString> OTodo::toMap() const { + QMap<int, QString> map; + + map.insert( Uid, QString::number( uid() ) ); + map.insert( Category, idsToString( categories() ) ); + map.insert( HasDate, QString::number( data->hasDate ) ); + map.insert( Completed, QString::number( data->isCompleted ) ); + map.insert( Description, data->desc ); + map.insert( Summary, data->sum ); + map.insert( Priority, QString::number( data->priority ) ); + map.insert( DateDay, QString::number( data->date.day() ) ); + map.insert( DateMonth, QString::number( data->date.month() ) ); + map.insert( DateYear, QString::number( data->date.year() ) ); + map.insert( Progress, QString::number( data->prog ) ); +// map.insert( CrossReference, crossToString() ); + /* FIXME!!! map.insert( State, ); + map.insert( Recurrence, ); + map.insert( Reminders, ); + map. + */ + return map; +} + +/** + * change or modify looks at the ref count and either + * creates a new QShared Object or it can modify it + * right in place + */ +void OTodo::changeOrModify() { + if ( data->count != 1 ) { + qWarning("changeOrModify"); + data->deref(); + OTodoData* d2 = new OTodoData(); + copy(data, d2 ); + data = d2; + } +} +// WATCHOUT +/* + * if you add something to the Data struct + * be sure to copy it here + */ +void OTodo::copy( OTodoData* src, OTodoData* dest ) { + dest->date = src->date; + dest->isCompleted = src->isCompleted; + dest->hasDate = src->hasDate; + dest->priority = src->priority; + dest->desc = src->desc; + dest->sum = src->sum; + dest->extra = src->extra; + dest->prog = src->prog; + + if (src->state ) + dest->state = new OPimState( *src->state ); + + if (src->recur ) + dest->recur = new ORecur( *src->recur ); + + if (src->maintainer ) + dest->maintainer = new OPimMaintainer( *src->maintainer ) + ; + dest->start = src->start; + dest->completed = src->completed; + + if (src->notifiers ) + dest->notifiers = new OPimNotifyManager( *src->notifiers ); +} +QString OTodo::type() const { + return QString::fromLatin1("OTodo"); +} +QString OTodo::recordField(int /*id*/ )const { + return QString::null; +} + +int OTodo::rtti(){ + return OPimResolver::TodoList; +} diff --git a/noncore/unsupported/libopie/pim/otodo.h b/noncore/unsupported/libopie/pim/otodo.h new file mode 100644 index 0000000..6df98b9 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodo.h @@ -0,0 +1,285 @@ + +#ifndef OPIE_TODO_EVENT_H +#define OPIE_TODO_EVENT_H + + +#include <qarray.h> +#include <qmap.h> +#include <qregexp.h> +#include <qstringlist.h> +#include <qdatetime.h> +#include <qvaluelist.h> + +#include <qpe/recordfields.h> +#include <qpe/palmtopuidgen.h> + +#include <opie/opimrecord.h> + + +class OPimState; +class ORecur; +class OPimMaintainer; +class OPimNotifyManager; +class OTodo : public OPimRecord { +public: + typedef QValueList<OTodo> ValueList; + enum RecordFields { + Uid = Qtopia::UID_ID, + Category = Qtopia::CATEGORY_ID, + HasDate, + Completed, + Description, + Summary, + Priority, + DateDay, + DateMonth, + DateYear, + Progress, + CrossReference, + State, + Recurrence, + Alarms, + Reminders, + Notifiers, + Maintainer, + StartDate, + CompletedDate + }; + public: + // priorities from Very low to very high + enum TaskPriority { VeryHigh=1, High, Normal, Low, VeryLow }; + + /* Constructs a new ToDoEvent + @param completed Is the TodoEvent completed + @param priority What is the priority of this ToDoEvent + @param category Which category does it belong( uid ) + @param summary A small summary of the todo + @param description What is this ToDoEvent about + @param hasDate Does this Event got a deadline + @param date what is the deadline? + @param uid what is the UUID of this Event + **/ + OTodo( bool completed = false, int priority = Normal, + const QStringList &category = QStringList(), + const QString &summary = QString::null , + const QString &description = QString::null, + ushort progress = 0, + bool hasDate = false, QDate date = QDate::currentDate(), + int uid = 0 /*empty*/ ); + + OTodo( bool completed, int priority, + const QArray<int>& category, + const QString& summary = QString::null, + const QString& description = QString::null, + ushort progress = 0, + bool hasDate = false, QDate date = QDate::currentDate(), + int uid = 0 /* empty */ ); + + /** Copy c'tor + * + */ + OTodo(const OTodo & ); + + /** + *destructor + */ + ~OTodo(); + + /** + * Is this event completed? + */ + bool isCompleted() const; + + /** + * Does this Event have a deadline + */ + bool hasDueDate() const; + bool hasStartDate()const; + bool hasCompletedDate()const; + + /** + * What is the priority? + */ + int priority()const ; + + /** + * progress as ushort 0, 20, 40, 60, 80 or 100% + */ + ushort progress() const; + + /** + * The due Date + */ + QDate dueDate()const; + + /** + * When did it start? + */ + QDate startDate()const; + + /** + * When was it completed? + */ + QDate completedDate()const; + + /** + * does it have a state? + */ + bool hasState()const; + + /** + * What is the state of this OTodo? + */ + OPimState state()const; + + /** + * has recurrence? + */ + bool hasRecurrence()const; + + /** + * the recurrance of this + */ + ORecur recurrence()const; + + /** + * does this OTodo have a maintainer? + */ + bool hasMaintainer()const; + + /** + * the Maintainer of this OTodo + */ + OPimMaintainer maintainer()const; + + /** + * The description of the todo + */ + QString description()const; + + /** + * A small summary of the todo + */ + QString summary() const; + + /** + * @reimplemented + * Return this todoevent in a RichText formatted QString + */ + QString toRichText() const; + + bool hasNotifiers()const; + /* + * FIXME check if the sharing is still fine!! -zecke + * ### CHECK If API is fine + */ + /** + * return a reference to our notifiers... + */ + OPimNotifyManager ¬ifiers(); + + /** + * + */ + const OPimNotifyManager ¬ifiers()const; + + /** + * reimplementations + */ + QString type()const; + QString toShortText()const; + QString recordField(int id )const; + + /** + * toMap puts all data into the map. int relates + * to ToDoEvent RecordFields enum + */ + QMap<int, QString> toMap()const; + + /** + * Set if this Todo is completed + */ + void setCompleted(bool completed ); + + /** + * set if this todo got an end data + */ + void setHasDueDate( bool hasDate ); + // FIXME we do not have these for start, completed + // cause we'll use the isNull() of QDate for figuring + // out if it's has a date... + // decide what to do here? -zecke + + /** + * Set the priority of the Todo + */ + void setPriority(int priority ); + + /** + * Set the progress. + */ + void setProgress( ushort progress ); + + /** + * set the end date + */ + void setDueDate( const QDate& date ); + + /** + * set the start date + */ + void setStartDate( const QDate& date ); + + /** + * set the completed date + */ + void setCompletedDate( const QDate& date ); + + void setRecurrence( const ORecur& ); + + void setDescription(const QString& ); + void setSummary(const QString& ); + + /** + * set the state of a Todo + * @param state State what the todo should take + */ + void setState( const OPimState& state); + + /** + * set the Maintainer Mode + */ + void setMaintainer( const OPimMaintainer& ); + + bool isOverdue(); + + + virtual bool match( const QRegExp &r )const; + + bool operator<(const OTodo &toDoEvent )const; + bool operator<=(const OTodo &toDoEvent )const; + bool operator!=(const OTodo &toDoEvent )const; + bool operator>(const OTodo &toDoEvent )const; + bool operator>=(const OTodo &toDoEvent)const; + bool operator==(const OTodo &toDoEvent )const; + OTodo &operator=(const OTodo &toDoEvent ); + + static int rtti(); + + private: + class OTodoPrivate; + struct OTodoData; + + void deref(); + inline void changeOrModify(); + void copy( OTodoData* src, OTodoData* dest ); + OTodoPrivate *d; + OTodoData *data; + +}; +inline bool OTodo::operator!=(const OTodo &toDoEvent )const { + return !(*this == toDoEvent); +} + + +#endif diff --git a/noncore/unsupported/libopie/pim/otodoaccess.cpp b/noncore/unsupported/libopie/pim/otodoaccess.cpp new file mode 100644 index 0000000..37f6fbc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccess.cpp @@ -0,0 +1,62 @@ +#include <qdatetime.h> + +#include <qpe/alarmserver.h> + +// #include "otodoaccesssql.h" +#include "otodoaccess.h" +#include "obackendfactory.h" + +OTodoAccess::OTodoAccess( OTodoAccessBackend* end, enum Access ) + : QObject(), OPimAccessTemplate<OTodo>( end ), m_todoBackEnd( end ) +{ +// if (end == 0l ) +// m_todoBackEnd = new OTodoAccessBackendSQL( QString::null); + + // Zecke: Du musst hier noch für das XML-Backend einen Appnamen übergeben ! + if (end == 0l ) + m_todoBackEnd = OBackendFactory<OTodoAccessBackend>::Default ("todo", QString::null); + + setBackEnd( m_todoBackEnd ); +} +OTodoAccess::~OTodoAccess() { +// qWarning("~OTodoAccess"); +} +void OTodoAccess::mergeWith( const QValueList<OTodo>& list ) { + QValueList<OTodo>::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + replace( (*it) ); + } +} +OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates ) { + QArray<int> ints = m_todoBackEnd->effectiveToDos( start, end, includeNoDates ); + + List lis( ints, this ); + return lis; +} +OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, + bool includeNoDates ) { + return effectiveToDos( start, QDate::currentDate(), + includeNoDates ); +} +OTodoAccess::List OTodoAccess::overDue() { + List lis( m_todoBackEnd->overDue(), this ); + return lis; +} +/* sort order */ +OTodoAccess::List OTodoAccess::sorted( bool ascending, int sort,int filter, int cat ) { + QArray<int> ints = m_todoBackEnd->sorted( ascending, sort, + filter, cat ); + OTodoAccess::List list( ints, this ); + return list; +} +void OTodoAccess::removeAllCompleted() { + m_todoBackEnd->removeAllCompleted(); +} +QBitArray OTodoAccess::backendSupport( const QString& ) const{ + return m_todoBackEnd->supports(); +} +bool OTodoAccess::backendSupports( int attr, const QString& ar) const{ + return backendSupport(ar).testBit( attr ); +} diff --git a/noncore/unsupported/libopie/pim/otodoaccess.h b/noncore/unsupported/libopie/pim/otodoaccess.h new file mode 100644 index 0000000..916923f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccess.h @@ -0,0 +1,105 @@ +#ifndef OPIE_TODO_ACCESS_H +#define OPIE_TODO_ACCESS_H + +#include <qobject.h> +#include <qvaluelist.h> + +#include "otodo.h" +#include "otodoaccessbackend.h" +#include "opimaccesstemplate.h" + + +/** + * OTodoAccess + * the class to get access to + * the todolist + */ +class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> { + Q_OBJECT +public: + enum SortOrder { Completed = 0, + Priority, + Description, + Deadline }; + enum SortFilter{ Category =1, + OnlyOverDue= 2, + DoNotShowCompleted =4 }; + /** + * if you use 0l + * the default resource will be + * picked up + */ + OTodoAccess( OTodoAccessBackend* = 0l, enum Access acc = Random ); + ~OTodoAccess(); + + + /* our functions here */ + /** + * include todos from start to end + * includeNoDates whether or not to include + * events with no dates + */ + List effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates = true ); + + /** + * start + * end date taken from the currentDate() + */ + List effectiveToDos( const QDate& start, + bool includeNoDates = true ); + + + /** + * return overdue OTodos + */ + List overDue(); + + /** + * + */ + List sorted( bool ascending, int sortOrder, int sortFilter, int cat ); + + /** + * merge a list of OTodos into + * the resource + */ + void mergeWith( const QValueList<OTodo>& ); + + /** + * delete all already completed items + */ + void removeAllCompleted(); + + /** + * request information about what a backend supports. + * Supports in the sense of beeing able to store. + * This is related to the enum in OTodo + * + * @param backend Will be used in the future when we support multiple backend + */ + QBitArray backendSupport( const QString& backend = QString::null )const; + + /** + * see above but for a specefic attribute. This method was added for convience + * @param attr The attribute to be queried for + * @param backend Will be used in the future when we support multiple backends + */ + bool backendSupports( int attr, const QString& backend = QString::null )const; +signals: + /** + * if the OTodoAccess was changed + */ + void changed( const OTodoAccess* ); + void changed( const OTodoAccess*, int uid ); + void added( const OTodoAccess*, int uid ); + void removed( const OTodoAccess*, int uid ); +private: + int m_cat; + OTodoAccessBackend* m_todoBackEnd; + class OTodoAccessPrivate; + OTodoAccessPrivate* d; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp b/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp new file mode 100644 index 0000000..baaeecc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp @@ -0,0 +1,10 @@ + +#include "otodoaccessbackend.h" + +OTodoAccessBackend::OTodoAccessBackend() + : OPimAccessBackend<OTodo>() +{ +} +OTodoAccessBackend::~OTodoAccessBackend() { + +} diff --git a/noncore/unsupported/libopie/pim/otodoaccessbackend.h b/noncore/unsupported/libopie/pim/otodoaccessbackend.h new file mode 100644 index 0000000..6be95bc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessbackend.h @@ -0,0 +1,28 @@ +#ifndef OPIE_TODO_ACCESS_BACKEND_H +#define OPIE_TODO_ACCESS_BACKEND_H + +#include <qbitarray.h> + +#include "otodo.h" +#include "opimaccessbackend.h" + +class OTodoAccessBackend : public OPimAccessBackend<OTodo> { +public: + OTodoAccessBackend(); + ~OTodoAccessBackend(); + virtual QArray<int> effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates ) = 0; + virtual QArray<int> overDue() = 0; + virtual QArray<int> sorted( bool asc, int sortOrder, int sortFilter, + int cat ) = 0; + virtual void removeAllCompleted() = 0; + virtual QBitArray supports()const = 0; + +private: + class Private; + Private *d; + +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/otodoaccesssql.cpp b/noncore/unsupported/libopie/pim/otodoaccesssql.cpp new file mode 100644 index 0000000..fd01a42 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccesssql.cpp @@ -0,0 +1,694 @@ + +#include <qdatetime.h> + +#include <qpe/global.h> + +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +#include "otodoaccesssql.h" +#include "opimstate.h" +#include "opimnotifymanager.h" +#include "orecur.h" + +using namespace Opie::DB; +/* + * first some query + * CREATE query + * LOAD query + * INSERT + * REMOVE + * CLEAR + */ +namespace { + /** + * CreateQuery for the Todolist Table + */ + class CreateQuery : public OSQLQuery { + public: + CreateQuery(); + ~CreateQuery(); + QString query()const; + }; + + /** + * LoadQuery + * this one queries for all uids + */ + class LoadQuery : public OSQLQuery { + public: + LoadQuery(); + ~LoadQuery(); + QString query()const; + }; + + /** + * inserts/adds a OTodo to the table + */ + class InsertQuery : public OSQLQuery { + public: + InsertQuery(const OTodo& ); + ~InsertQuery(); + QString query()const; + private: + OTodo m_todo; + }; + + /** + * removes one from the table + */ + class RemoveQuery : public OSQLQuery { + public: + RemoveQuery(int uid ); + ~RemoveQuery(); + QString query()const; + private: + int m_uid; + }; + + /** + * Clears (delete) a Table + */ + class ClearQuery : public OSQLQuery { + public: + ClearQuery(); + ~ClearQuery(); + QString query()const; + + }; + + /** + * a find query + */ + class FindQuery : public OSQLQuery { + public: + FindQuery(int uid); + FindQuery(const QArray<int>& ); + ~FindQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray<int> m_uids; + int m_uid; + }; + + /** + * overdue query + */ + class OverDueQuery : public OSQLQuery { + public: + OverDueQuery(); + ~OverDueQuery(); + QString query()const; + }; + class EffQuery : public OSQLQuery { + public: + EffQuery( const QDate&, const QDate&, bool inc ); + ~EffQuery(); + QString query()const; + private: + QString with()const; + QString out()const; + QDate m_start; + QDate m_end; + bool m_inc :1; + }; + + + CreateQuery::CreateQuery() : OSQLQuery() {} + CreateQuery::~CreateQuery() {} + QString CreateQuery::query()const { + QString qu; + qu += "create table todolist( uid PRIMARY KEY, categories, completed, "; + qu += "description, summary, priority, DueDate, progress , state, "; + // This is the recurrance-stuff .. Exceptions are currently not supported (see ORecur.cpp) ! (eilers) + qu += "RType, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions, "; + qu += "reminders, alarms, maintainer, startdate, completeddate);"; + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; + return qu; + } + + LoadQuery::LoadQuery() : OSQLQuery() {} + LoadQuery::~LoadQuery() {} + QString LoadQuery::query()const { + QString qu; + // We do not need "distinct" here. The primary key is always unique.. + //qu += "select distinct uid from todolist"; + qu += "select uid from todolist"; + + return qu; + } + + InsertQuery::InsertQuery( const OTodo& todo ) + : OSQLQuery(), m_todo( todo ) { + } + InsertQuery::~InsertQuery() { + } + /* + * converts from a OTodo to a query + * we leave out X-Ref + Alarms + */ + QString InsertQuery::query()const{ + + int year, month, day; + year = month = day = 0; + if (m_todo.hasDueDate() ) { + QDate date = m_todo.dueDate(); + year = date.year(); + month = date.month(); + day = date.day(); + } + int sYear = 0, sMonth = 0, sDay = 0; + if( m_todo.hasStartDate() ){ + QDate sDate = m_todo.startDate(); + sYear = sDate.year(); + sMonth= sDate.month(); + sDay = sDate.day(); + } + + int eYear = 0, eMonth = 0, eDay = 0; + if( m_todo.hasCompletedDate() ){ + QDate eDate = m_todo.completedDate(); + eYear = eDate.year(); + eMonth= eDate.month(); + eDay = eDate.day(); + } + QString qu; + QMap<int, QString> recMap = m_todo.recurrence().toMap(); + qu = "insert into todolist VALUES(" + + QString::number( m_todo.uid() ) + "," + + "'" + m_todo.idsToString( m_todo.categories() ) + "'" + "," + + QString::number( m_todo.isCompleted() ) + "," + + "'" + m_todo.description() + "'" + "," + + "'" + m_todo.summary() + "'" + "," + + QString::number(m_todo.priority() ) + "," + + "'" + QString::number(year) + "-" + + QString::number(month) + + "-" + QString::number( day ) + "'" + "," + + QString::number( m_todo.progress() ) + "," + + QString::number( m_todo.state().state() ) + "," + + "'" + recMap[ ORecur::RType ] + "'" + "," + + "'" + recMap[ ORecur::RWeekdays ] + "'" + "," + + "'" + recMap[ ORecur::RPosition ] + "'" + "," + + "'" + recMap[ ORecur::RFreq ] + "'" + "," + + "'" + recMap[ ORecur::RHasEndDate ] + "'" + "," + + "'" + recMap[ ORecur::EndDate ] + "'" + "," + + "'" + recMap[ ORecur::Created ] + "'" + "," + + "'" + recMap[ ORecur::Exceptions ] + "'" + ","; + + if ( m_todo.hasNotifiers() ) { + OPimNotifyManager manager = m_todo.notifiers(); + qu += "'" + manager.remindersToString() + "'" + "," + + "'" + manager.alarmsToString() + "'" + ","; + } + else{ + qu += QString( "''" ) + "," + + "''" + ","; + } + + qu += QString( "''" ) + QString( "," ) // Maintainers (cur. not supported !) + + "'" + QString::number(sYear) + "-" + + QString::number(sMonth) + + "-" + QString::number(sDay) + "'" + "," + + "'" + QString::number(eYear) + "-" + + QString::number(eMonth) + + "-"+QString::number(eDay) + "'" + + ")"; + + qWarning("add %s", qu.latin1() ); + return qu; + } + + RemoveQuery::RemoveQuery(int uid ) + : OSQLQuery(), m_uid( uid ) {} + RemoveQuery::~RemoveQuery() {} + QString RemoveQuery::query()const { + QString qu = "DELETE from todolist where uid = " + QString::number(m_uid); + return qu; + } + + + ClearQuery::ClearQuery() + : OSQLQuery() {} + ClearQuery::~ClearQuery() {} + QString ClearQuery::query()const { + QString qu = "drop table todolist"; + return qu; + } + FindQuery::FindQuery(int uid) + : OSQLQuery(), m_uid(uid ) { + } + FindQuery::FindQuery(const QArray<int>& ints) + : OSQLQuery(), m_uids(ints){ + } + FindQuery::~FindQuery() { + } + QString FindQuery::query()const{ + if (m_uids.count() == 0 ) + return single(); + else + return multi(); + } + QString FindQuery::single()const{ + QString qu = "select * from todolist where uid = " + QString::number(m_uid); + return qu; + } + QString FindQuery::multi()const { + QString qu = "select * from todolist where "; + for (uint i = 0; i < m_uids.count(); i++ ) { + qu += " UID = " + QString::number( m_uids[i] ) + " OR"; + } + qu.remove( qu.length()-2, 2 ); + return qu; + } + + OverDueQuery::OverDueQuery(): OSQLQuery() {} + OverDueQuery::~OverDueQuery() {} + QString OverDueQuery::query()const { + QDate date = QDate::currentDate(); + QString str; + str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); + + return str; + } + + + EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) + : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} + EffQuery::~EffQuery() {} + QString EffQuery::query()const { + return m_inc ? with() : out(); + } + QString EffQuery::with()const { + QString str; + str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") + .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) + .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); + return str; + } + QString EffQuery::out()const { + QString str; + str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") + .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) + .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); + + return str; + } +}; + +OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) + : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true) +{ + QString fi = file; + if ( fi.isEmpty() ) + fi = Global::applicationFileName( "todolist", "todolist.db" ); + OSQLManager man; + m_driver = man.standard(); + m_driver->setUrl(fi); + // fillDict(); +} + +OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ + if( m_driver ) + delete m_driver; +} + +bool OTodoAccessBackendSQL::load(){ + if (!m_driver->open() ) + return false; + + CreateQuery creat; + OSQLResult res = m_driver->query(&creat ); + + m_dirty = true; + return true; +} +bool OTodoAccessBackendSQL::reload(){ + return load(); +} + +bool OTodoAccessBackendSQL::save(){ + return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) +} +QArray<int> OTodoAccessBackendSQL::allRecords()const { + if (m_dirty ) + update(); + + return m_uids; +} +QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){ + QArray<int> ints(0); + return ints; +} +OTodo OTodoAccessBackendSQL::find(int uid ) const{ + FindQuery query( uid ); + return todo( m_driver->query(&query) ); + +} +OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, + uint cur, Frontend::CacheDirection dir ) const{ + uint CACHE = readAhead(); + qWarning("searching for %d", uid ); + QArray<int> search( CACHE ); + uint size =0; + OTodo to; + + // we try to cache CACHE items + switch( dir ) { + /* forward */ + case 0: // FIXME: Not a good style to use magic numbers here (eilers) + for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { + qWarning("size %d %d", size, ints[i] ); + search[size] = ints[i]; + size++; + } + break; + /* reverse */ + case 1: // FIXME: Not a good style to use magic numbers here (eilers) + for (uint i = cur; i != 0 && size < CACHE; i-- ) { + search[size] = ints[i]; + size++; + } + break; + } + search.resize( size ); + FindQuery query( search ); + OSQLResult res = m_driver->query( &query ); + if ( res.state() != OSQLResult::Success ) + return to; + + return todo( res ); +} +void OTodoAccessBackendSQL::clear() { + ClearQuery cle; + OSQLResult res = m_driver->query( &cle ); + CreateQuery qu; + res = m_driver->query(&qu); +} +bool OTodoAccessBackendSQL::add( const OTodo& t) { + InsertQuery ins( t ); + OSQLResult res = m_driver->query( &ins ); + + if ( res.state() == OSQLResult::Failure ) + return false; + int c = m_uids.count(); + m_uids.resize( c+1 ); + m_uids[c] = t.uid(); + + return true; +} +bool OTodoAccessBackendSQL::remove( int uid ) { + RemoveQuery rem( uid ); + OSQLResult res = m_driver->query(&rem ); + + if ( res.state() == OSQLResult::Failure ) + return false; + + m_dirty = true; + return true; +} +/* + * FIXME better set query + * but we need the cache for that + * now we remove + */ +bool OTodoAccessBackendSQL::replace( const OTodo& t) { + remove( t.uid() ); + bool b= add(t); + m_dirty = false; // we changed some stuff but the UID stayed the same + return b; +} +QArray<int> OTodoAccessBackendSQL::overDue() { + OverDueQuery qu; + return uids( m_driver->query(&qu ) ); +} +QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s, + const QDate& t, + bool u) { + EffQuery ef(s, t, u ); + return uids (m_driver->query(&ef) ); +} +/* + * + */ +QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder, + int sortFilter, int cat ) { + qWarning("sorted %d, %d", asc, sortOrder ); + QString query; + query = "select uid from todolist WHERE "; + + /* + * Sort Filter stuff + * not that straight forward + * FIXME: Replace magic numbers + * + */ + /* Category */ + if ( sortFilter & 1 ) { + QString str; + if (cat != 0 ) str = QString::number( cat ); + query += " categories like '%" +str+"%' AND"; + } + /* Show only overdue */ + if ( sortFilter & 2 ) { + QDate date = QDate::currentDate(); + QString due; + QString base; + base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() ); + query += " " + base + " AND"; + } + /* not show completed */ + if ( sortFilter & 4 ) { + query += " completed = 0 AND"; + }else{ + query += " ( completed = 1 OR completed = 0) AND"; + } + /* srtip the end */ + query = query.remove( query.length()-3, 3 ); + + + /* + * sort order stuff + * quite straight forward + */ + query += "ORDER BY "; + switch( sortOrder ) { + /* completed */ + case 0: + query += "completed"; + break; + case 1: + query += "priority"; + break; + case 2: + query += "summary"; + break; + case 3: + query += "DueDate"; + break; + } + + if ( !asc ) { + qWarning("not ascending!"); + query += " DESC"; + } + + qWarning( query ); + OSQLRawQuery raw(query ); + return uids( m_driver->query(&raw) ); +} +bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ + if ( str == "0-0-0" ) + return false; + else{ + int day, year, month; + QStringList list = QStringList::split("-", str ); + year = list[0].toInt(); + month = list[1].toInt(); + day = list[2].toInt(); + da.setYMD( year, month, day ); + return true; + } +} +OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{ + if ( res.state() == OSQLResult::Failure ) { + OTodo to; + return to; + } + + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it = list.begin(); + qWarning("todo1"); + OTodo to = todo( (*it) ); + cache( to ); + ++it; + + for ( ; it != list.end(); ++it ) { + qWarning("caching"); + cache( todo( (*it) ) ); + } + return to; +} +OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const { + qWarning("todo"); + bool hasDueDate = false; QDate dueDate = QDate::currentDate(); + hasDueDate = date( dueDate, item.data("DueDate") ); + QStringList cats = QStringList::split(";", item.data("categories") ); + + qWarning("Item is completed: %d", item.data("completed").toInt() ); + + OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), + cats, item.data("summary"), item.data("description"), + item.data("progress").toUShort(), hasDueDate, dueDate, + item.data("uid").toInt() ); + + bool isOk; + int prioInt = QString( item.data("priority") ).toInt( &isOk ); + if ( isOk ) + to.setPriority( prioInt ); + + bool hasStartDate = false; QDate startDate = QDate::currentDate(); + hasStartDate = date( startDate, item.data("startdate") ); + bool hasCompletedDate = false; QDate completedDate = QDate::currentDate(); + hasCompletedDate = date( completedDate, item.data("completeddate") ); + + if ( hasStartDate ) + to.setStartDate( startDate ); + if ( hasCompletedDate ) + to.setCompletedDate( completedDate ); + + OPimNotifyManager& manager = to.notifiers(); + manager.alarmsFromString( item.data("alarms") ); + manager.remindersFromString( item.data("reminders") ); + + OPimState pimState; + pimState.setState( QString( item.data("state") ).toInt() ); + to.setState( pimState ); + + QMap<int, QString> recMap; + recMap.insert( ORecur::RType , item.data("RType") ); + recMap.insert( ORecur::RWeekdays , item.data("RWeekdays") ); + recMap.insert( ORecur::RPosition , item.data("RPosition") ); + recMap.insert( ORecur::RFreq , item.data("RFreq") ); + recMap.insert( ORecur::RHasEndDate, item.data("RHasEndDate") ); + recMap.insert( ORecur::EndDate , item.data("EndDate") ); + recMap.insert( ORecur::Created , item.data("Created") ); + recMap.insert( ORecur::Exceptions , item.data("Exceptions") ); + + ORecur recur; + recur.fromMap( recMap ); + to.setRecurrence( recur ); + + return to; +} +OTodo OTodoAccessBackendSQL::todo( int uid )const { + FindQuery find( uid ); + return todo( m_driver->query(&find) ); +} +/* + * update the dict + */ +void OTodoAccessBackendSQL::fillDict() { + /* initialize dict */ + /* + * UPDATE dict if you change anything!!! + * FIXME: Isn't this dict obsolete ? (eilers) + */ + m_dict.setAutoDelete( TRUE ); + m_dict.insert("Categories" , new int(OTodo::Category) ); + m_dict.insert("Uid" , new int(OTodo::Uid) ); + m_dict.insert("HasDate" , new int(OTodo::HasDate) ); + m_dict.insert("Completed" , new int(OTodo::Completed) ); + m_dict.insert("Description" , new int(OTodo::Description) ); + m_dict.insert("Summary" , new int(OTodo::Summary) ); + m_dict.insert("Priority" , new int(OTodo::Priority) ); + m_dict.insert("DateDay" , new int(OTodo::DateDay) ); + m_dict.insert("DateMonth" , new int(OTodo::DateMonth) ); + m_dict.insert("DateYear" , new int(OTodo::DateYear) ); + m_dict.insert("Progress" , new int(OTodo::Progress) ); + m_dict.insert("Completed", new int(OTodo::Completed) ); // Why twice ? (eilers) + m_dict.insert("CrossReference", new int(OTodo::CrossReference) ); +// m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); // old stuff (eilers) +// m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); // old stuff (eilers) +} +/* + * need to be const so let's fool the + * compiler :( + */ +void OTodoAccessBackendSQL::update()const { + ((OTodoAccessBackendSQL*)this)->m_dirty = false; + LoadQuery lo; + OSQLResult res = m_driver->query(&lo); + if ( res.state() != OSQLResult::Success ) + return; + + ((OTodoAccessBackendSQL*)this)->m_uids = uids( res ); +} +QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{ + + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray<int> ints(list.count() ); + qWarning(" count = %d", list.count() ); + + int i = 0; + for (it = list.begin(); it != list.end(); ++it ) { + ints[i] = (*it).data("uid").toInt(); + i++; + } + return ints; +} + +QArray<int> OTodoAccessBackendSQL::matchRegexp( const QRegExp &r ) const +{ + +#warning OTodoAccessBackendSQL::matchRegexp() not implemented !! + +#if 0 + + Copied from xml-backend by not adapted to sql (eilers) + + QArray<int> m_currentQuery( m_events.count() ); + uint arraycounter = 0; + + + + QMap<int, OTodo>::ConstIterator it; + for (it = m_events.begin(); it != m_events.end(); ++it ) { + if ( it.data().match( r ) ) + m_currentQuery[arraycounter++] = it.data().uid(); + + } + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; +#endif + QArray<int> empty; + return empty; +} +QBitArray OTodoAccessBackendSQL::supports()const { + + return sup(); +} + +QBitArray OTodoAccessBackendSQL::sup() const{ + + QBitArray ar( OTodo::CompletedDate + 1 ); + ar.fill( true ); + ar[OTodo::CrossReference] = false; + ar[OTodo::State ] = false; + ar[OTodo::Reminders] = false; + ar[OTodo::Notifiers] = false; + ar[OTodo::Maintainer] = false; + + return ar; +} + +void OTodoAccessBackendSQL::removeAllCompleted(){ +#warning OTodoAccessBackendSQL::removeAllCompleted() not implemented !! + +} diff --git a/noncore/unsupported/libopie/pim/otodoaccesssql.h b/noncore/unsupported/libopie/pim/otodoaccesssql.h new file mode 100644 index 0000000..72214de --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccesssql.h @@ -0,0 +1,61 @@ +#ifndef OPIE_PIM_ACCESS_SQL_H +#define OPIE_PIM_ACCESS_SQL_H + +#include <qasciidict.h> + +#include "otodoaccessbackend.h" + +namespace Opie{ +namespace DB { +class OSQLDriver; +class OSQLResult; +class OSQLResultItem; +} +} + +class OTodoAccessBackendSQL : public OTodoAccessBackend { +public: + OTodoAccessBackendSQL( const QString& file ); + ~OTodoAccessBackendSQL(); + + bool load(); + bool reload(); + bool save(); + QArray<int> allRecords()const; + + QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); + OTodo find(int uid)const; + OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; + void clear(); + bool add( const OTodo& t ); + bool remove( int uid ); + bool replace( const OTodo& t ); + + QArray<int> overDue(); + QArray<int> effectiveToDos( const QDate& start, + const QDate& end, bool includeNoDates ); + QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); + + QBitArray supports()const; + QArray<int> matchRegexp( const QRegExp &r ) const; + void removeAllCompleted(); + + +private: + void update()const; + void fillDict(); + inline bool date( QDate& date, const QString& )const; + inline OTodo todo( const Opie::DB::OSQLResult& )const; + inline OTodo todo( Opie::DB::OSQLResultItem& )const; + inline QArray<int> uids( const Opie::DB::OSQLResult& )const; + OTodo todo( int uid )const; + QBitArray sup() const; + + QAsciiDict<int> m_dict; + Opie::DB::OSQLDriver* m_driver; + QArray<int> m_uids; + bool m_dirty : 1; +}; + + +#endif diff --git a/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp b/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp new file mode 100644 index 0000000..6415952 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp @@ -0,0 +1,249 @@ +#include <qfile.h> + +#include <qtopia/private/vobject_p.h> +#include <qtopia/timeconversion.h> +#include <qtopia/private/qfiledirect_p.h> + +#include "otodoaccessvcal.h" + +namespace { + static OTodo eventByVObj( VObject *obj ){ + OTodo event; + VObject *ob; + QCString name; + // no uid, attendees, ... and no fun + // description + if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ + name = vObjectStringZValue( ob ); +#if 0 + event.setDescription( name ); +#else + event.setSummary( name ); +#endif + } + // summary + if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { + name = vObjectStringZValue( ob ); +#if 0 + event.setSummary( name ); +#else + event.setDescription( name ); +#endif + } + // completed + if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ + name = vObjectStringZValue( ob ); + if( name == "COMPLETED" ){ + event.setCompleted( true ); + }else{ + event.setCompleted( false ); + } + }else + event.setCompleted( false ); + // priority + if ((ob = isAPropertyOf(obj, VCPriorityProp))) { + name = vObjectStringZValue( ob ); + bool ok; + event.setPriority(name.toInt(&ok) ); + } + //due date + if((ob = isAPropertyOf(obj, VCDueProp)) ){ + event.setHasDueDate( true ); + name = vObjectStringZValue( ob ); + event.setDueDate( TimeConversion::fromISO8601( name).date() ); + } + // categories + if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ + name = vObjectStringZValue( ob ); + qWarning("Categories:%s", name.data() ); + } + + event.setUid( 1 ); + return event; + }; + static VObject *vobjByEvent( const OTodo &event ) { + VObject *task = newVObject( VCTodoProp ); + if( task == 0 ) + return 0l; + + if( event.hasDueDate() ) { + QTime time(0, 0, 0); + QDateTime date(event.dueDate(), time ); + addPropValue( task, VCDueProp, + TimeConversion::toISO8601( date ) ); + } + + if( event.isCompleted() ) + addPropValue( task, VCStatusProp, "COMPLETED"); + + QString string = QString::number(event.priority() ); + addPropValue( task, VCPriorityProp, string.local8Bit() ); + + addPropValue( task, VCCategoriesProp, + event.idsToString( event.categories() ).local8Bit() ); + +#if 0 + + // There seems a misrepresentation between summary in otodoevent + // and summary in vcard. + // The same with description.. + // Description is summary and vice versa.. Argh.. (eilers) + + + addPropValue( task, VCDescriptionProp, + event.description().local8Bit() ); + + addPropValue( task, VCSummaryProp, + event.summary().local8Bit() ); + +#else + addPropValue( task, VCDescriptionProp, + event.summary().local8Bit() ); + + addPropValue( task, VCSummaryProp, + event.description().local8Bit() ); +#endif + return task; +}; +} + +OTodoAccessVCal::OTodoAccessVCal( const QString& path ) + : m_dirty(false), m_file( path ) +{ +} +OTodoAccessVCal::~OTodoAccessVCal() { +} +bool OTodoAccessVCal::load() { + m_map.clear(); + m_dirty = false; + + VObject* vcal = 0l; + vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); + if (!vcal ) + return false; + + // Iterate over the list + VObjectIterator it; + VObject* vobj; + + initPropIterator(&it, vcal); + + while( moreIteration( &it ) ) { + vobj = ::nextVObject( &it ); + QCString name = ::vObjectName( vobj ); + if( name == VCTodoProp ){ + OTodo to = eventByVObj( vobj ); + m_map.insert( to.uid(), to ); + } + } + + // Should I do a delete vcal? + + return true; +} +bool OTodoAccessVCal::reload() { + return load(); +} +bool OTodoAccessVCal::save() { + if (!m_dirty ) + return true; + + QFileDirect file( m_file ); + if (!file.open(IO_WriteOnly ) ) + return false; + + VObject *obj; + obj = newVObject( VCCalProp ); + addPropValue( obj, VCVersionProp, "1.0" ); + VObject *vo; + for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ + vo = vobjByEvent( it.data() ); + addVObjectProp(obj, vo ); + } + writeVObject( file.directHandle(), obj ); + cleanVObject( obj ); + cleanStrTbl(); + + m_dirty = false; + return true; +} +void OTodoAccessVCal::clear() { + m_map.clear(); + m_dirty = true; +} +bool OTodoAccessVCal::add( const OTodo& to ) { + m_map.insert( to.uid(), to ); + m_dirty = true; + return true; +} +bool OTodoAccessVCal::remove( int uid ) { + m_map.remove( uid ); + m_dirty = true; + return true; +} +void OTodoAccessVCal::removeAllCompleted() { + for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { + if ( (*it).isCompleted() ) + m_map.remove( it ); + } +} +bool OTodoAccessVCal::replace( const OTodo& to ) { + m_map.replace( to.uid(), to ); + m_dirty = true; + return true; +} +OTodo OTodoAccessVCal::find(int uid )const { + return m_map[uid]; +} +QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { + QArray<int> ar(0); + return ar; +} +QArray<int> OTodoAccessVCal::allRecords()const { + QArray<int> ar( m_map.count() ); + QMap<int, OTodo>::ConstIterator it; + int i = 0; + for ( it = m_map.begin(); it != m_map.end(); ++it ) { + ar[i] = it.key(); + i++; + } + return ar; +} +QArray<int> OTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const { + QArray<int> ar(0); + return ar; +} +QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) { + QArray<int> ar(0); + return ar; +} +QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , + const QDate& , + bool ) { + QArray<int> ar(0); + return ar; +} +QArray<int> OTodoAccessVCal::overDue() { + QArray<int> ar(0); + return ar; +} +QBitArray OTodoAccessVCal::supports()const { + static QBitArray ar = sup(); + + return ar; +} +QBitArray OTodoAccessVCal::sup() { + QBitArray ar ( OTodo::CompletedDate +1 ); + ar.fill( true ); + + ar[OTodo::CrossReference] = false; + ar[OTodo::State ] = false; + ar[OTodo::Reminders] = false; + ar[OTodo::Notifiers] = false; + ar[OTodo::Maintainer] = false; + ar[OTodo::Progress] = false; + ar[OTodo::Alarms ] = false; + ar[OTodo::Recurrence] = false; + + return ar; +} diff --git a/noncore/unsupported/libopie/pim/otodoaccessvcal.h b/noncore/unsupported/libopie/pim/otodoaccessvcal.h new file mode 100644 index 0000000..2b17147 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessvcal.h @@ -0,0 +1,40 @@ +#ifndef OPIE_OTODO_ACCESS_VCAL_H +#define OPIE_OTODO_ACCESS_VCAL_H + +#include "otodoaccessbackend.h" + +class OTodoAccessVCal : public OTodoAccessBackend { +public: + OTodoAccessVCal(const QString& ); + ~OTodoAccessVCal(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() ); + QArray<int> effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates ); + QArray<int> overDue(); + QArray<int> sorted( bool asc, int sortOrder, int sortFilter, + int cat ); + OTodo find(int uid)const; + void clear(); + bool add( const OTodo& ); + bool remove( int uid ); + bool replace( const OTodo& ); + + void removeAllCompleted(); + virtual QBitArray supports()const; + +private: + static QBitArray sup(); + bool m_dirty : 1; + QString m_file; + QMap<int, OTodo> m_map; +}; + +#endif diff --git a/noncore/unsupported/libopie/pim/otodoaccessxml.cpp b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp new file mode 100644 index 0000000..4a5cb33 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp @@ -0,0 +1,876 @@ +#include <errno.h> +#include <fcntl.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + + +#include <qfile.h> +#include <qvector.h> + +#include <qpe/global.h> +#include <qpe/stringutil.h> +#include <qpe/timeconversion.h> + +#include "oconversion.h" +#include "opimstate.h" +#include "otimezone.h" +#include "opimnotifymanager.h" +#include "orecur.h" +#include "otodoaccessxml.h" + +namespace { + time_t rp_end; + ORecur* rec; + ORecur *recur() { + if (!rec ) rec = new ORecur; + return rec; + } + int snd; + enum MoreAttributes { + FRType = OTodo::CompletedDate + 2, + FRWeekdays, + FRPosition, + FRFreq, + FRHasEndDate, + FREndDate, + FRStart, + FREnd + }; + // FROM TT again +char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) +{ + char needleChar; + char haystackChar; + if (!needle || !haystack || !hLen || !nLen) + return 0; + + const char* hsearch = haystack; + + if ((needleChar = *needle++) != 0) { + nLen--; //(to make up for needle++) + do { + do { + if ((haystackChar = *hsearch++) == 0) + return (0); + if (hsearch >= haystack + hLen) + return (0); + } while (haystackChar != needleChar); + } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); + hsearch--; + } + return ((char *)hsearch); +} +} + + +OTodoAccessXML::OTodoAccessXML( const QString& appName, + const QString& fileName ) + : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) +{ + if (!fileName.isEmpty() ) + m_file = fileName; + else + m_file = Global::applicationFileName( "todolist", "todolist.xml" ); +} +OTodoAccessXML::~OTodoAccessXML() { + +} +bool OTodoAccessXML::load() { + rec = 0; + m_opened = true; + m_changed = false; + /* initialize dict */ + /* + * UPDATE dict if you change anything!!! + */ + QAsciiDict<int> dict(26); + dict.setAutoDelete( TRUE ); + dict.insert("Categories" , new int(OTodo::Category) ); + dict.insert("Uid" , new int(OTodo::Uid) ); + dict.insert("HasDate" , new int(OTodo::HasDate) ); + dict.insert("Completed" , new int(OTodo::Completed) ); + dict.insert("Description" , new int(OTodo::Description) ); + dict.insert("Summary" , new int(OTodo::Summary) ); + dict.insert("Priority" , new int(OTodo::Priority) ); + dict.insert("DateDay" , new int(OTodo::DateDay) ); + dict.insert("DateMonth" , new int(OTodo::DateMonth) ); + dict.insert("DateYear" , new int(OTodo::DateYear) ); + dict.insert("Progress" , new int(OTodo::Progress) ); + dict.insert("CompletedDate", new int(OTodo::CompletedDate) ); + dict.insert("StartDate", new int(OTodo::StartDate) ); + dict.insert("CrossReference", new int(OTodo::CrossReference) ); + dict.insert("State", new int(OTodo::State) ); + dict.insert("Alarms", new int(OTodo::Alarms) ); + dict.insert("Reminders", new int(OTodo::Reminders) ); + dict.insert("Notifiers", new int(OTodo::Notifiers) ); + dict.insert("Maintainer", new int(OTodo::Maintainer) ); + dict.insert("rtype", new int(FRType) ); + dict.insert("rweekdays", new int(FRWeekdays) ); + dict.insert("rposition", new int(FRPosition) ); + dict.insert("rfreq", new int(FRFreq) ); + dict.insert("start", new int(FRStart) ); + dict.insert("rhasenddate", new int(FRHasEndDate) ); + dict.insert("enddt", new int(FREndDate) ); + + // here the custom XML parser from TT it's GPL + // but we want to push OpiePIM... to TT..... + // mmap part from zecke :) + int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); + struct stat attribut; + if ( fd < 0 ) return false; + + if ( fstat(fd, &attribut ) == -1 ) { + ::close( fd ); + return false; + } + void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if ( map_addr == ( (caddr_t)-1) ) { + ::close(fd ); + return false; + } + /* advise the kernel who we want to read it */ + ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); + /* we do not the file any more */ + ::close( fd ); + + char* dt = (char*)map_addr; + int len = attribut.st_size; + int i = 0; + char *point; + const char* collectionString = "<Task "; + int strLen = strlen(collectionString); + while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { + i = point -dt; + i+= strLen; + qWarning("Found a start at %d %d", i, (point-dt) ); + + OTodo ev; + m_year = m_month = m_day = 0; + + while ( TRUE ) { + while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) + ++i; + if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) + break; + + // we have another attribute, read it. + int j = i; + while ( j < len && dt[j] != '=' ) + ++j; + QCString attr( dt+i, j-i+1); + + i = ++j; // skip = + + // find the start of quotes + while ( i < len && dt[i] != '"' ) + ++i; + j = ++i; + + bool haveUtf = FALSE; + bool haveEnt = FALSE; + while ( j < len && dt[j] != '"' ) { + if ( ((unsigned char)dt[j]) > 0x7f ) + haveUtf = TRUE; + if ( dt[j] == '&' ) + haveEnt = TRUE; + ++j; + } + if ( i == j ) { + // empty value + i = j + 1; + continue; + } + + QCString value( dt+i, j-i+1 ); + i = j + 1; + + QString str = (haveUtf ? QString::fromUtf8( value ) + : QString::fromLatin1( value ) ); + if ( haveEnt ) + str = Qtopia::plainString( str ); + + /* + * add key + value + */ + todo( &dict, ev, attr, str ); + + } + /* + * now add it + */ + qWarning("End at %d", i ); + if (m_events.contains( ev.uid() ) || ev.uid() == 0) { + ev.setUid( 1 ); + m_changed = true; + } + if ( ev.hasDueDate() ) { + ev.setDueDate( QDate(m_year, m_month, m_day) ); + } + if ( rec && rec->doesRecur() ) { + OTimeZone utc = OTimeZone::utc(); + ORecur recu( *rec ); // call copy c'tor + recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() ); + recu.setStart( ev.dueDate() ); + ev.setRecurrence( recu ); + } + m_events.insert(ev.uid(), ev ); + m_year = m_month = m_day = -1; + delete rec; + rec = 0; + } + + munmap(map_addr, attribut.st_size ); + + qWarning("counts %d records loaded!", m_events.count() ); + return true; +} +bool OTodoAccessXML::reload() { + m_events.clear(); + return load(); +} +bool OTodoAccessXML::save() { +// qWarning("saving"); + if (!m_opened || !m_changed ) { +// qWarning("not saving"); + return true; + } + QString strNewFile = m_file + ".new"; + QFile f( strNewFile ); + if (!f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + int written; + QString out; + out = "<!DOCTYPE Tasks>\n<Tasks>\n"; + + // for all todos + QMap<int, OTodo>::Iterator it; + for (it = m_events.begin(); it != m_events.end(); ++it ) { + out+= "<Task " + toString( (*it) ) + " />\n"; + QCString cstr = out.utf8(); + written = f.writeBlock( cstr.data(), cstr.length() ); + + /* less written then we wanted */ + if ( written != (int)cstr.length() ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + out = QString::null; + } + + out += "</Tasks>"; + QCString cstr = out.utf8(); + written = f.writeBlock( cstr.data(), cstr.length() ); + + if ( written != (int)cstr.length() ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + /* flush before renaming */ + f.close(); + + if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { +// qWarning("error renaming"); + QFile::remove( strNewFile ); + } + + m_changed = false; + return true; +} +QArray<int> OTodoAccessXML::allRecords()const { + QArray<int> ids( m_events.count() ); + QMap<int, OTodo>::ConstIterator it; + int i = 0; + + for ( it = m_events.begin(); it != m_events.end(); ++it ) { + ids[i] = it.key(); + i++; + } + return ids; +} +QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { + QArray<int> ids(0); + return ids; +} +OTodo OTodoAccessXML::find( int uid )const { + OTodo todo; + todo.setUid( 0 ); // isEmpty() + QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); + if ( it != m_events.end() ) + todo = it.data(); + + return todo; +} +void OTodoAccessXML::clear() { + if (m_opened ) + m_changed = true; + + m_events.clear(); +} +bool OTodoAccessXML::add( const OTodo& todo ) { +// qWarning("add"); + m_changed = true; + m_events.insert( todo.uid(), todo ); + + return true; +} +bool OTodoAccessXML::remove( int uid ) { + m_changed = true; + m_events.remove( uid ); + + return true; +} +bool OTodoAccessXML::replace( const OTodo& todo) { + m_changed = true; + m_events.replace( todo.uid(), todo ); + + return true; +} +QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates ) { + QArray<int> ids( m_events.count() ); + QMap<int, OTodo>::Iterator it; + + int i = 0; + for ( it = m_events.begin(); it != m_events.end(); ++it ) { + if ( !it.data().hasDueDate() ) { + if ( includeNoDates ) { + ids[i] = it.key(); + i++; + } + }else if ( it.data().dueDate() >= start && + it.data().dueDate() <= end ) { + ids[i] = it.key(); + i++; + } + } + ids.resize( i ); + return ids; +} +QArray<int> OTodoAccessXML::overDue() { + QArray<int> ids( m_events.count() ); + int i = 0; + + QMap<int, OTodo>::Iterator it; + for ( it = m_events.begin(); it != m_events.end(); ++it ) { + if ( it.data().isOverdue() ) { + ids[i] = it.key(); + i++; + } + } + ids.resize( i ); + return ids; +} + + +/* private */ +void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, + const QCString& attr, const QString& val) { +// qWarning("parse to do from XMLElement" ); + + int *find=0; + + find = (*dict)[ attr.data() ]; + if (!find ) { +// qWarning("Unknown option" + it.key() ); + ev.setCustomField( attr, val ); + return; + } + + switch( *find ) { + case OTodo::Uid: + ev.setUid( val.toInt() ); + break; + case OTodo::Category: + ev.setCategories( ev.idsFromString( val ) ); + break; + case OTodo::HasDate: + ev.setHasDueDate( val.toInt() ); + break; + case OTodo::Completed: + ev.setCompleted( val.toInt() ); + break; + case OTodo::Description: + ev.setDescription( val ); + break; + case OTodo::Summary: + ev.setSummary( val ); + break; + case OTodo::Priority: + ev.setPriority( val.toInt() ); + break; + case OTodo::DateDay: + m_day = val.toInt(); + break; + case OTodo::DateMonth: + m_month = val.toInt(); + break; + case OTodo::DateYear: + m_year = val.toInt(); + break; + case OTodo::Progress: + ev.setProgress( val.toInt() ); + break; + case OTodo::CompletedDate: + ev.setCompletedDate( OConversion::dateFromString( val ) ); + break; + case OTodo::StartDate: + ev.setStartDate( OConversion::dateFromString( val ) ); + break; + case OTodo::State: + ev.setState( val.toInt() ); + break; + case OTodo::Alarms:{ + OPimNotifyManager &manager = ev.notifiers(); + QStringList als = QStringList::split(";", val ); + for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { + QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty + qWarning("alarm: %s", alarm.join("___").latin1() ); + qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); + OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() ); + manager.add( al ); + } + } + break; + case OTodo::Reminders:{ + OPimNotifyManager &manager = ev.notifiers(); + QStringList rems = QStringList::split(";", val ); + for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { + OPimReminder rem( (*it).toInt() ); + manager.add( rem ); + } + } + break; + case OTodo::CrossReference: + { + /* + * A cross refernce looks like + * appname,id;appname,id + * we need to split it up + */ + QStringList refs = QStringList::split(';', val ); + QStringList::Iterator strIt; + for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { + int pos = (*strIt).find(','); + if ( pos > -1 ) + ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); + + } + break; + } + /* Recurrence stuff below + post processing later */ + case FRType: + if ( val == "Daily" ) + recur()->setType( ORecur::Daily ); + else if ( val == "Weekly" ) + recur()->setType( ORecur::Weekly); + else if ( val == "MonthlyDay" ) + recur()->setType( ORecur::MonthlyDay ); + else if ( val == "MonthlyDate" ) + recur()->setType( ORecur::MonthlyDate ); + else if ( val == "Yearly" ) + recur()->setType( ORecur::Yearly ); + else + recur()->setType( ORecur::NoRepeat ); + break; + case FRWeekdays: + recur()->setDays( val.toInt() ); + break; + case FRPosition: + recur()->setPosition( val.toInt() ); + break; + case FRFreq: + recur()->setFrequency( val.toInt() ); + break; + case FRHasEndDate: + recur()->setHasEndDate( val.toInt() ); + break; + case FREndDate: { + rp_end = (time_t) val.toLong(); + break; + } + default: + ev.setCustomField( attr, val ); + break; + } +} + +// from PalmtopRecord... GPL ### FIXME +namespace { +QString customToXml(const QMap<QString, QString>& customMap ) +{ + //qWarning(QString("writing custom %1").arg(customMap.count())); + QString buf(" "); + for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); + cit != customMap.end(); ++cit) { +// qWarning(".ITEM."); + buf += cit.key(); + buf += "=\""; + buf += Qtopia::escapeString(cit.data()); + buf += "\" "; + } + return buf; +} + + +} + +QString OTodoAccessXML::toString( const OTodo& ev )const { + QString str; + + str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; + str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; + str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; + str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; + + str += "Categories=\"" + toString( ev.categories() ) + "\" "; + str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; + str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; + + if ( ev.hasDueDate() ) { + str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; + str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; + str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; + } +// qWarning( "Uid %d", ev.uid() ); + str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; + +// append the extra options + /* FIXME Qtopia::Record this is currently not + * possible you can set custom fields + * but don' iterate over the list + * I may do #define private protected + * for this case - cough --zecke + */ + /* + QMap<QString, QString> extras = ev.extras(); + QMap<QString, QString>::Iterator extIt; + for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) + str += extIt.key() + "=\"" + extIt.data() + "\" "; + */ + // cross refernce + if ( ev.hasRecurrence() ) { + str += ev.recurrence().toString(); + } + if ( ev.hasStartDate() ) + str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" "; + if ( ev.hasCompletedDate() ) + str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" "; + if ( ev.hasState() ) + str += "State=\""+QString::number( ev.state().state() )+"\" "; + + /* + * save reminders and notifiers! + * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:.... + */ + if ( ev.hasNotifiers() ) { + OPimNotifyManager manager = ev.notifiers(); + OPimNotifyManager::Alarms alarms = manager.alarms(); + if (!alarms.isEmpty() ) { + QStringList als; + OPimNotifyManager::Alarms::Iterator it = alarms.begin(); + for ( ; it != alarms.end(); ++it ) { + /* only if time is valid */ + if ( (*it).dateTime().isValid() ) { + als << OConversion::dateTimeToString( (*it).dateTime() ) + + ":" + QString::number( (*it).duration() ) + + ":" + QString::number( (*it).sound() ) + + ":"; + } + } + // now write the list + qWarning("als: %s", als.join("____________").latin1() ); + str += "Alarms=\""+als.join(";") +"\" "; + } + + /* + * now the same for reminders but more easy. We just save the uid of the OEvent. + */ + OPimNotifyManager::Reminders reminders = manager.reminders(); + if (!reminders.isEmpty() ) { + OPimNotifyManager::Reminders::Iterator it = reminders.begin(); + QStringList records; + for ( ; it != reminders.end(); ++it ) { + records << QString::number( (*it).recordUid() ); + } + str += "Reminders=\""+ records.join(";") +"\" "; + } + } + str += customToXml( ev.toExtraMap() ); + + + return str; +} +QString OTodoAccessXML::toString( const QArray<int>& ints ) const { + return Qtopia::Record::idsToString( ints ); +} + +/* internal class for sorting + * + * Inspired by todoxmlio.cpp from TT + */ + +struct OTodoXMLContainer { + OTodo todo; +}; + +namespace { + inline QString string( const OTodo& todo) { + return todo.summary().isEmpty() ? + todo.description().left(20 ) : + todo.summary(); + } + inline int completed( const OTodo& todo1, const OTodo& todo2) { + int ret = 0; + if ( todo1.isCompleted() ) ret++; + if ( todo2.isCompleted() ) ret--; + return ret; + } + inline int priority( const OTodo& t1, const OTodo& t2) { + return ( t1.priority() - t2.priority() ); + } + inline int description( const OTodo& t1, const OTodo& t2) { + return QString::compare( string(t1), string(t2) ); + } + inline int deadline( const OTodo& t1, const OTodo& t2) { + int ret = 0; + if ( t1.hasDueDate() && + t2.hasDueDate() ) + ret = t2.dueDate().daysTo( t1.dueDate() ); + else if ( t1.hasDueDate() ) + ret = -1; + else if ( t2.hasDueDate() ) + ret = 1; + else + ret = 0; + + return ret; + } + +}; + +/* + * Returns: + * 0 if item1 == item2 + * + * non-zero if item1 != item2 + * + * This function returns int rather than bool so that reimplementations + * can return one of three values and use it to sort by: + * + * 0 if item1 == item2 + * + * > 0 (positive integer) if item1 > item2 + * + * < 0 (negative integer) if item1 < item2 + * + */ +class OTodoXMLVector : public QVector<OTodoXMLContainer> { +public: + OTodoXMLVector(int size, bool asc, int sort) + : QVector<OTodoXMLContainer>( size ) + { + setAutoDelete( true ); + m_asc = asc; + m_sort = sort; + } + /* return the summary/description */ + QString string( const OTodo& todo) { + return todo.summary().isEmpty() ? + todo.description().left(20 ) : + todo.summary(); + } + /** + * we take the sortorder( switch on it ) + * + */ + int compareItems( Item d1, Item d2 ) { + bool seComp, sePrio, seDesc, seDeadline; + seComp = sePrio = seDeadline = seDesc = false; + int ret =0; + OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; + OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; + + /* same item */ + if ( con1->todo.uid() == con2->todo.uid() ) + return 0; + + switch ( m_sort ) { + /* completed */ + case 0: { + ret = completed( con1->todo, con2->todo ); + seComp = TRUE; + break; + } + /* priority */ + case 1: { + ret = priority( con1->todo, con2->todo ); + sePrio = TRUE; + break; + } + /* description */ + case 2: { + ret = description( con1->todo, con2->todo ); + seDesc = TRUE; + break; + } + /* deadline */ + case 3: { + ret = deadline( con1->todo, con2->todo ); + seDeadline = TRUE; + break; + } + default: + ret = 0; + break; + }; + /* + * FIXME do better sorting if the first sort criteria + * ret equals 0 start with complete and so on... + */ + + /* twist it we're not ascending*/ + if (!m_asc) + ret = ret * -1; + + if ( ret ) + return ret; + + // default did not gave difference let's try it other way around + /* + * General try if already checked if not test + * and return + * 1.Completed + * 2.Priority + * 3.Description + * 4.DueDate + */ + if (!seComp ) { + if ( (ret = completed( con1->todo, con2->todo ) ) ) { + if (!m_asc ) ret *= -1; + return ret; + } + } + if (!sePrio ) { + if ( (ret = priority( con1->todo, con2->todo ) ) ) { + if (!m_asc ) ret *= -1; + return ret; + } + } + if (!seDesc ) { + if ( (ret = description(con1->todo, con2->todo ) ) ) { + if (!m_asc) ret *= -1; + return ret; + } + } + if (!seDeadline) { + if ( (ret = deadline( con1->todo, con2->todo ) ) ) { + if (!m_asc) ret *= -1; + return ret; + } + } + + return 0; + } + private: + bool m_asc; + int m_sort; + +}; + +QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, + int sortFilter, int cat ) { + OTodoXMLVector vector(m_events.count(), asc,sortOrder ); + QMap<int, OTodo>::Iterator it; + int item = 0; + + bool bCat = sortFilter & 1 ? true : false; + bool bOnly = sortFilter & 2 ? true : false; + bool comp = sortFilter & 4 ? true : false; + for ( it = m_events.begin(); it != m_events.end(); ++it ) { + + /* show category */ + /* -1 == unfiled */ + if ( bCat && cat == -1 ) { + if(!(*it).categories().isEmpty() ) + continue; + }else if ( bCat && cat != 0) + if (!(*it).categories().contains( cat ) ) { + continue; + } + /* isOverdue but we should not show overdue - why?*/ +/* if ( (*it).isOverdue() && !bOnly ) { + qWarning("item is overdue but !bOnly"); + continue; + } +*/ + if ( !(*it).isOverdue() && bOnly ) { + continue; + } + + if ((*it).isCompleted() && comp ) { + continue; + } + + + OTodoXMLContainer* con = new OTodoXMLContainer(); + con->todo = (*it); + vector.insert(item, con ); + item++; + } + vector.resize( item ); + /* sort it now */ + vector.sort(); + /* now get the uids */ + QArray<int> array( vector.count() ); + for (uint i= 0; i < vector.count(); i++ ) { + array[i] = ( vector.at(i) )->todo.uid(); + } + return array; +}; +void OTodoAccessXML::removeAllCompleted() { + QMap<int, OTodo> events = m_events; + for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { + if ( (*it).isCompleted() ) + events.remove( it.key() ); + } + m_events = events; +} +QBitArray OTodoAccessXML::supports()const { + static QBitArray ar = sup(); + return ar; +} +QBitArray OTodoAccessXML::sup() { + QBitArray ar( OTodo::CompletedDate +1 ); + ar.fill( true ); + ar[OTodo::CrossReference] = false; + ar[OTodo::State ] = false; + ar[OTodo::Reminders] = false; + ar[OTodo::Notifiers] = false; + ar[OTodo::Maintainer] = false; + + return ar; +} +QArray<int> OTodoAccessXML::matchRegexp( const QRegExp &r ) const +{ + QArray<int> m_currentQuery( m_events.count() ); + uint arraycounter = 0; + + QMap<int, OTodo>::ConstIterator it; + for (it = m_events.begin(); it != m_events.end(); ++it ) { + if ( it.data().match( r ) ) + m_currentQuery[arraycounter++] = it.data().uid(); + + } + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; +} diff --git a/noncore/unsupported/libopie/pim/otodoaccessxml.h b/noncore/unsupported/libopie/pim/otodoaccessxml.h new file mode 100644 index 0000000..e4850a1 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessxml.h @@ -0,0 +1,60 @@ +#ifndef OPIE_TODO_ACCESS_XML_H +#define OPIE_TODO_ACCESS_XML_H + +#include <qasciidict.h> +#include <qmap.h> + +#include "otodoaccessbackend.h" + +namespace Opie { + class XMLElement; +}; + +class OTodoAccessXML : public OTodoAccessBackend { +public: + /** + * fileName if Empty we will use the default path + */ + OTodoAccessXML( const QString& appName, + const QString& fileName = QString::null ); + ~OTodoAccessXML(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() ); + OTodo find( int uid )const; + void clear(); + bool add( const OTodo& ); + bool remove( int uid ); + void removeAllCompleted(); + bool replace( const OTodo& ); + + /* our functions */ + QArray<int> effectiveToDos( const QDate& start, + const QDate& end, + bool includeNoDates ); + QArray<int> overDue(); + QArray<int> sorted( bool asc, int sortOrder, + int sortFilter, int cat ); + QBitArray supports()const; +private: + static QBitArray sup(); + void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); + QString toString( const OTodo& )const; + QString toString( const QArray<int>& ints ) const; + QMap<int, OTodo> m_events; + QString m_file; + QString m_app; + bool m_opened : 1; + bool m_changed : 1; + class OTodoAccessXMLPrivate; + OTodoAccessXMLPrivate* d; + int m_year, m_month, m_day; + +}; + +#endif diff --git a/noncore/unsupported/libopie/sharp_compat.cpp b/noncore/unsupported/libopie/sharp_compat.cpp new file mode 100644 index 0000000..1d16a09 --- a/dev/null +++ b/noncore/unsupported/libopie/sharp_compat.cpp @@ -0,0 +1,18 @@ +/* + * This file contains hacks or workarounds, that make it possible to use a normal + * libopie arm build (iPAQ or OZ) directly on the Sharp retail ROM. + * This way, we only need one 'official' libopie binary for all platforms. + */ + + +// 1) Opie's libqpe.so has an additional function in Sound, which is utilized +// in ODevice: + +// ok this is really evil ;), but Sound::isFinished is only needed in the +// iPAQ part of ODevice, which is never called on Z's +// we add a "weak" symbol here. This will be used, if ld.so does not find +// a normal ("hard") symbol of the same name - hence only on the retail Z + +struct Sound { bool Sound::isFinished ( ) const __attribute__(( weak )); }; +bool Sound::isFinished ( ) const { return true; } + diff --git a/noncore/unsupported/libopie/todayconfigwidget.h b/noncore/unsupported/libopie/todayconfigwidget.h new file mode 100644 index 0000000..f3501a1 --- a/dev/null +++ b/noncore/unsupported/libopie/todayconfigwidget.h @@ -0,0 +1,39 @@ + +#ifndef CONFIG_WIDGET_H +#define CONFIG_WIDGET_H + + +/** + * A base class for all Today Config Widgets. + * This will let a Today plugin to add the possibility of configuration. + * Plugins need to inherit from this class and need to implement + * the pure virtual method to control configuration. + * The Plugin should read its configuration during creation of the Widget + * + * + * @author Maximilian Reiß + * @short base class of all today config widgets + */ +class TodayConfigWidget : public QWidget { + + +public: + + /** + * This will construct the widget. The widget gets deleted once the parent + * gets deleted as in any Qt application + * + * @param parent The parent of the widget + * @param name The name of the object + */ + TodayConfigWidget( QWidget *parent, const char *name ) : QWidget( parent, name ) {} ; + virtual ~TodayConfigWidget() {}; + + /** + * Plugins need to reimplement this in the config widget + * Used when the config dialog is closed to write config stuff + */ + virtual void writeConfig() = 0; +}; + +#endif diff --git a/noncore/unsupported/libopie/todayplugininterface.h b/noncore/unsupported/libopie/todayplugininterface.h new file mode 100644 index 0000000..5dfeaa8 --- a/dev/null +++ b/noncore/unsupported/libopie/todayplugininterface.h @@ -0,0 +1,133 @@ +/* + This file is part of the Opie Project + Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#ifndef TODAY_PLUGIN_INTERFACE +#define TODAY_PLUGIN_INTERFACE + +#include <qpe/qcom.h> +#include "todayconfigwidget.h" + +class QString; +class QWidget; + +#ifndef IID_TodayPluginInterface +#define IID_TodayPluginInterface QUuid( 0x70481804, 0x2b50, 0x4fba, 0x80, 0xbb, 0x0b, 0xf8, 0xdc, 0x72, 0x04, 0x14) +#endif + +/** + * + * A TodayPluginObject is the base for all Today Plugins. + * A plugin author needs to inherit this class and implement + * the pure virtual methods + * + * @short base class for today plugins + * @author Maximilian Reiss + * + */ +class TodayPluginObject { + +public: + + virtual ~TodayPluginObject() {}; + + /** + * The name if the plugin + * @return The plugin should return its name here + */ + virtual QString pluginName() const = 0; + + /** + * Version numbering + * @return The plugin should return the version number + */ + virtual double versionNumber() const = 0; + + + /** + * @return the pixmap name widget?! -- FIXME + */ + virtual QString pixmapNameWidget() const = 0; + + /** + * widget for the today view + * It _needs_ a parent here. + * Plugin authors need to take parent as parent! + */ + virtual QWidget* widget( QWidget *parent ) = 0; + + /** + * Pixmap used in the config widget + */ + virtual QString pixmapNameConfig() const = 0; + + /** + * Config plugin widget - optional + * If the plugin has a config widget, it _needs_ a parent here. + * may return 0 if no config widget is needed + */ + virtual TodayConfigWidget* configWidget( QWidget * ) = 0; + + /** + * The application that should be assigned to the button (pixmap) + * Today will show the plugin icon. On click it tries to execute the + * plugin related application. + */ + virtual QString appName() const = 0; + + + /** + * If the plugin should take part in the periodic refresh + */ + virtual bool excludeFromRefresh() const = 0; + + /** + * Refresh that plugins view. For updating the plugins + */ + virtual void refresh() {}; + + /** + * reread the plugins config and act apropiate + * This is for example used when returning from the config dialog + */ + virtual void reinitialize() {}; +}; + +/** + * This is part of the QCOM works. See example plugins how to do it right + */ +struct TodayPluginInterface : public QUnknownInterface { + /** + * return the TodayPluginObject implementation + */ + virtual TodayPluginObject *guiPart() = 0; +}; + +#endif diff --git a/noncore/unsupported/libopie/xmltree.cc b/noncore/unsupported/libopie/xmltree.cc new file mode 100644 index 0000000..27db5b3 --- a/dev/null +++ b/noncore/unsupported/libopie/xmltree.cc @@ -0,0 +1,322 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Simon Hausmann <hausmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <qpe/stringutil.h> +#include <opie/xmltree.h> + +#include <qxml.h> + +#include <assert.h> + +using namespace Opie; + +XMLElement::XMLElement() + : m_parent( 0 ), m_next( 0 ), m_prev( 0 ), m_first( 0 ), m_last( 0 ) +{ +} + +XMLElement::~XMLElement() +{ + XMLElement *n = m_first; + + while ( n ) + { + XMLElement *tmp = n; + n = n->m_next; + delete tmp; + } +} + +void XMLElement::appendChild( XMLElement *child ) +{ + if ( child->m_parent ) + child->m_parent->removeChild( child ); + + child->m_parent = this; + + if ( m_last ) + m_last->m_next = child; + + child->m_prev = m_last; + + if ( !m_first ) + m_first = child; + + m_last = child; +} + +void XMLElement::insertAfter( XMLElement *newChild, XMLElement *refChild ) +{ + assert( newChild != refChild ); + + if ( refChild == m_last ) + { + appendChild( newChild ); + return; + } + + assert( refChild ); + assert( refChild->m_parent ); + assert( refChild->m_parent == this ); + + if ( newChild->m_parent && newChild != refChild ) + newChild->m_parent->removeChild( newChild ); + + newChild->m_parent = this; + + XMLElement *next = refChild->m_next; + + refChild->m_next = newChild; + + newChild->m_prev = refChild; + newChild->m_next = next; + + if ( next ) + next->m_prev = newChild; +} + +QString XMLElement::attribute( const QString &attr ) const +{ + AttributeMap::ConstIterator it = m_attributes.find( attr ); + if ( it == m_attributes.end() ) + return QString::null; + return it.data(); +} + +void XMLElement::setAttribute( const QString &attr, const QString &value ) +{ + m_attributes.replace( attr, value ); +} + +void XMLElement::insertBefore( XMLElement *newChild, XMLElement *refChild ) +{ + assert( refChild ); + assert( refChild->m_parent ); + assert( refChild->m_parent == this ); + assert( newChild != refChild ); + + if ( newChild->m_parent && newChild != refChild ) + newChild->m_parent->removeChild( newChild ); + + newChild->m_parent = this; + + XMLElement *prev = refChild->m_prev; + + refChild->m_prev = newChild; + + newChild->m_prev = prev; + newChild->m_next = refChild; + + if ( prev ) + prev->m_next = newChild; + + if ( refChild == m_first ) + m_first = newChild; +} + +void XMLElement::removeChild( XMLElement *child ) +{ + if ( child->m_parent != this ) + return; + + if ( m_first == child ) + m_first = child->m_next; + + if ( m_last == child ) + m_last = child->m_prev; + + if ( child->m_prev ) + child->m_prev->m_next = child->m_next; + + if ( child->m_next ) + child->m_next->m_prev = child->m_prev; + + child->m_parent = 0; + child->m_prev = 0; + child->m_next = 0; +} + +void XMLElement::save( QTextStream &s, uint indent ) +{ + if ( !m_value.isEmpty() ) + { + s << Qtopia::escapeString( m_value ); + return; + } + + for ( uint i = 0; i < indent; ++i ) + s << " "; + + s << "<" << m_tag; + + if ( !m_attributes.isEmpty() ) + { + s << " "; + AttributeMap::ConstIterator it = m_attributes.begin(); + AttributeMap::ConstIterator end = m_attributes.end(); + for (; it != end; ++it ) + { + s << it.key() << "=\"" << Qtopia::escapeString( it.data() ) << "\""; + s << " "; + } + } + + if ( m_last ) + { + if ( ( m_first && !m_first->value().isEmpty() ) || !m_parent ) + s << ">"; + else + s << ">" << endl; + + int newIndent = indent; + if ( m_parent ) + newIndent++; + + XMLElement *n = m_first; + while ( n ) + { + n->save( s, newIndent ); + n = n->nextChild(); + } + + if ( m_last && m_last->value().isEmpty() && m_parent ) + for ( uint i = 0; i < indent; ++i ) + s << " "; + + if ( m_parent ) + s << "</" << m_tag << ">" << endl; + } + else + s << "/>" << endl; +} + +class Handler : public QXmlDefaultHandler +{ +public: + Handler() : m_node( 0 ), m_root( 0 ) {} + + XMLElement *root() const { return m_root; } + + virtual bool startDocument(); + virtual bool endDocument(); + virtual bool startElement( const QString &ns, const QString &ln, const QString &qName, + const QXmlAttributes &attr ); + virtual bool endElement( const QString &ns, const QString &ln, const QString &qName ); + virtual bool characters( const QString &ch ); + +private: + XMLElement *m_node; + XMLElement *m_root; +}; + +bool Handler::startDocument() +{ + m_root = m_node = new XMLElement; + + return true; +} + +bool Handler::endDocument() +{ + return m_root == m_node; +} + +bool Handler::startElement( const QString &, const QString &, const QString &qName, + const QXmlAttributes &attr ) +{ + XMLElement *bm = new XMLElement; + + XMLElement::AttributeMap attributes; + for ( int i = 0; i < attr.length(); ++i ) + attributes[ attr.qName( i ) ] = attr.value( i ); + + bm->setAttributes( attributes ); + + bm->setTagName( qName ); + + m_node->appendChild( bm ); + m_node = bm; + + return true; +} + +bool Handler::endElement( const QString &, const QString &, const QString & ) +{ + if ( m_node == m_root ) + return false; + + m_node = m_node->parent(); + return true; +} + +bool Handler::characters( const QString &ch ) +{ + XMLElement *textNode = new XMLElement; + textNode->setValue( ch ); + m_node->appendChild( textNode ); + return true; +} + +XMLElement *XMLElement::namedItem( const QString &name ) +{ + XMLElement *e = m_first; + + for (; e; e = e->nextChild() ) + if ( e->tagName() == name ) + return e; + + return 0; +} + +XMLElement *XMLElement::clone() const +{ + XMLElement *res = new XMLElement; + + res->setTagName( m_tag ); + res->setValue( m_value ); + res->setAttributes( m_attributes ); + + XMLElement *e = m_first; + for (; e; e = e->m_next ) + res->appendChild( e->clone() ); + + return res; +} + +XMLElement *XMLElement::load( const QString &fileName ) +{ + QFile f( fileName ); + if ( !f.open( IO_ReadOnly ) ) + return 0; + + QTextStream stream( &f ); + stream.setEncoding( QTextStream::UnicodeUTF8 ); + QXmlInputSource src( stream ); + QXmlSimpleReader reader; + Handler handler; + + reader.setFeature( "http://trolltech.com/xml/features/report-whitespace-only-CharData", false ); + reader.setContentHandler( &handler ); + reader.parse( src ); + + return handler.root();; +} + +/* vim: et sw=4 + */ diff --git a/noncore/unsupported/libopie/xmltree.h b/noncore/unsupported/libopie/xmltree.h new file mode 100644 index 0000000..4b6bdfa --- a/dev/null +++ b/noncore/unsupported/libopie/xmltree.h @@ -0,0 +1,119 @@ +/* This file is part of the KDE project + Copyright (C) 2000,2001 Simon Hausmann <hausmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + + +#ifndef __bookmarks_h__ +#define __bookmarks_h__ + +#include <qstring.h> +#include <qmap.h> +#include <qtextstream.h> + +namespace Opie +{ + +/** + * A small xml lib written by Simon Hausmann. + */ +class XMLElement +{ +public: + typedef QMap<QString, QString> AttributeMap; + + /** + * The constructor of XMLElement + */ + XMLElement(); + ~XMLElement(); + + /** appendChild appends a child to the XMLElement behind the last element. + * The ownership of the child get's transfered to the + * this XMLElement. + * If child is already the child of another parent + * it's get removed from the other parent first. + */ + void appendChild( XMLElement *child ); + + /** inserts newChild after refChild. If newChild is the child + * of another parent the child will get removed. + * The ownership of child gets transfered. + * + */ + void insertAfter( XMLElement *newChild, XMLElement *refChild ); + + /** same as insertAfter but the element get's inserted before refChild. + * + */ + void insertBefore( XMLElement *newChild, XMLElement *refChild ); + + /** removeChild removes the child from the XMLElement. + * The ownership gets dropped. You need to delete the + * child yourself. + */ + void removeChild( XMLElement *child ); + + /** parent() returns the parent of this XMLElement + * If there is no parent 0l gets returned + */ + XMLElement *parent() const { return m_parent; } + XMLElement *firstChild() const { return m_first; } + XMLElement *nextChild() const { return m_next; } + XMLElement *prevChild() const { return m_prev; } + XMLElement *lastChild() const { return m_last; } + + void setTagName( const QString &tag ) { m_tag = tag; } + QString tagName() const { return m_tag; } + + void setValue( const QString &val ) { m_value = val; } + QString value() const { return m_value; } + + void setAttributes( const AttributeMap &attrs ) { m_attributes = attrs; } + AttributeMap attributes() const { return m_attributes; } + AttributeMap &attributes() { return m_attributes; } + + QString attribute( const QString & ) const; + void setAttribute( const QString &attr, const QString &value ); + void save( QTextStream &stream, uint indent = 0 ); + + XMLElement *namedItem( const QString &name ); + + XMLElement *clone() const; + + static XMLElement *load( const QString &fileName ); + +private: + QString m_tag; + QString m_value; + AttributeMap m_attributes; + + XMLElement *m_parent; + XMLElement *m_next; + XMLElement *m_prev; + XMLElement *m_first; + XMLElement *m_last; + + XMLElement( const XMLElement &rhs ); + XMLElement &operator=( const XMLElement &rhs ); + class Private; + Private* d; +}; + +} // namespace Opie + +#endif |